(RU) Processors - PixeyeHQ/actors.unity Wiki

( Актуально на 19.07.2020 )

Обработчики

Обработчики - это название для всех систем, менеджеров, контроллеров и "глобальных" скриптов.

Как создавать

Обработчики наследуются от Processor.

 public class ProcessorDamageble : Processor
 {

 }

Где объявлять

Обработчики добавляются в Toolbox через Layer класс.

    	public class LayerDefault : Layer<LayerDefault>
	{
        // Use to add processors and set up a layer.
		protected override void Setup()
		{
			Add<MobBehaviourProcessor>();
			Add<ProcessorMovePlayer>();
		}

		// Use to clean up custom stuff before the layer gets destroyed.
		protected override void OnLayerDestroy()
		{
		}
	}

Дополнительные интерфейсы

Если обработчику нужны апдейты то используются интерфейсы ITick, ITickFixed, ITickLate.

public class ProcessorPlayer : Processor, ITick

Для работы с сигналами используется интерфейс IRecieve<Тип передаваемого объекта>

public class ProcessorDamageble : Processor, IReceive<SignalDamage>, ITick
{
	public void HandleSignal(ref SignalDamage arg){}
}

Для того чтобы обработчик не был уничтожен тулбоксом при смене сцены используйте интерфейс IKernel Например:

public class ProcessorTimer : Processor, IKernel

На моей практике ни разу не возникало необходимости в использовании IKernel внутри кода игры. IKernel используется внутри фреймворка для базовых обработчиков так что используя его вы должны понимать зачем вам это нужно.

Работа с группами

В 90% случаев обработчики имеют дело с группами сущностей. Пример из игры Cryoshock:

public class ProcessorMotion : Processor, ITick, ITickFixed
{
public Group<ComponentMotion, ComponentRigidbody, ComponentObject> groupMotion;

public override void HandleEcsEvents()
{
	       // do something with added entities. 
	       foreach (ent entity in groupMotion.added)
		{
		   var cRigid  = entity.ComponentRigidBody();
	           var cObject = entity.ComponentObject();
	           cRigid.body = cObject.transform.GetComponent<Rigidbody2D>();
		}
	 
}

public void TickFixed(float delta)
{
      foreach (var entity in groupMotion)
      {
	 var cMotion = entity.ComponentMotion();
	 var cRigid  = entity.ComponentRigidBody();
	 cRigid.body.MovePosition(cMotion.positionTo);
      }
}

public void Tick(float delta)
	{
        var bounds = Game.roomBounds;
			
	foreach (var entity in groupMotion)
	{
		var cMotion = entity.ComponentMotion();
                var cRigid = entity.ComponentRigidBody();

		var position = cRigid.body.transform.position;
		var velocity = cMotion.velocity;


		velocity.x += (0 - velocity.x) * delta / cMotion.drag;
		velocity.y += (0 - velocity.y) * delta / cMotion.drag;

		cMotion.velocity = velocity;

		position.x += (cMotion.velocity.x + cMotion.direction.x * cMotion.speed) * delta;
		position.y += (cMotion.velocity.y + cMotion.direction.y * cMotion.speed) * delta;

		position.x = Mathf.Clamp(position.x, bounds.min.x, bounds.max.x);

		cMotion.positionTo = position;
	}


   }
}

Код выше работают для всех сущностей у которых есть ComponentMotion отвечающий за движение и физику , ComponentObject отвечающий за объект ( transform и go ), ComponentRigidbody отвечающий за Rigidbody.

Наличие этих компонентов может быть у таких сущностей как игрок или монстр.

Альтернативная форма описания группы в процессоре.

// группа будет инициализированв в недрах процессора. К ней можно обратиться через поле source.
public class ProcessorMotion : Processor<ComponentMotion, ComponentRigidbody, ComponentObject>, ITick, ITickFixed
{
 
}

Конструкторы

Обработчики создаются по типу во время игры и не наследуются от классов monobehavior. Чтобы провести инициализацию обработчика используем его конструктор. Например :

public ProcessorMotion()
{ 
}

События групп

У каждой группы есть два события:

Ближайшие аналоги это методы OnEnable/OnDisable у monobehavior класса. Обрабатываются Все сущности добавленные или удаленные из группы за последний процессор. Для этого в процессоре вызывается метод HandleEcsEvents.

public override void HandleEcsEvents()
{
	       // do something with added entities. 
	       foreach (ent entity in groupMotion.added)
		{
		   var cRigid  = entity.ComponentRigidBody();
	           var cObject = entity.ComponentObject();
	           cRigid.body = cObject.transform.GetComponent<Rigidbody2D>();
		}
	 
}

Событие в качестве аргумента использует значение типа int символизирующий сущность.

В примере всегда когда сущность добавляется к группе groupMotion работает код выше. Он назначает реальный ригидбоди объекта своему компоненту.

Обработка групп

Все группы являются IEnumerable. Для того чтобы прогнать группу нам достаточно использовать такую конструкцию:

foreach (var entity in groupMotion) 
 {
              
 }

где entity - сущность участвующая в группе. Далее, чтобы работать с компонентами достаточно вытащить их из сушности.

foreach (var entity in groupInAir)
{
var cInAir    = entity.ComponentInAir();
var cObject   = entity.ComponentObject();
var cMotion   = entity.ComponentMotion();
}

Дополнительные проверки на наличие компонента не нужны так как группы фильтруются раньше обработки. При уходе нужного компонента группа уберет сущность. Можно догадаться, что обращаясь к entity мы можем попытаться вытащить любой компонент, даже если его нет в группе, однако это небезопасно и так лучше не делать.

Файловые шаблоны

Код шаблона:

using Pixeye.Actors;

namespace $NAMESPACE$
{
	sealed class $CLASS$ : Processor, ITick
	{
		// Group Example Group<ComponentAlpaca> groupAlpacas = default;
		$END$

		public void Tick(float delta)
		{
		}
	}
}

Настройки macro для переменных:
CLASS - Current file name without extension with all non-alphanumeric replaced with underscores
NAMESPACE - Default namespace for current file
Это Вариант 1 файловых шаблонов из руководства по компонентам. Обязательно обратите внимание на опцию Availability при настройке, иначе шаблон может не отображаться в меню Add.

На заметку

	foreach (var entity in groupInAir)
	{
	var cInAir    = entity.ComponentInAir();
	var cRigid    = entity.ComponentRigidBody();
	var cMotion   = entity.ComponentMotion();