Entitas 初级

Entitas 实现 点击创建物体在屏幕上面

1.创建四个 Component
每个 Componet 都是只包含自身的数据。

[Game]
public class TransformComponent : IComponent //使用Gameobject 也行
{
    public Transform transform;
}
[Game]
public class PositionComponent : IComponent
{
    public Vector2 position;
}
[Game]
public class SpriteComponent : IComponent
{
    public string spriteName;
}

以及记录输入数据的 InputComponent。

[Input, Unique]//Unique 全局唯一
public class MouseComponent : IComponent
{
    public EMouseEventType mouseEventType;
}

2.创建 MouseSystem
负责检测鼠标点击。

public enum EMouseEventType
{
    Down,
    Press,
    Up
}
public class MouseSystem : IExecuteSystem //每一帧都会执行的System
{
    private InputContext _context;
    public MouseSystem(Contexts contexts)
    {
        this._context = contexts.input;
    }
    public void Execute()
    {
        if (Input.GetMouseButtonDown(0))
        {
            this._context.ReplaceInputExampleMouse(EMouseEventType.Down);
        }
        if (Input.GetMouseButtonDown(1))
        {
            this._context.ReplaceInputExampleMouse(EMouseEventType.Down);
        }
    }
}

3.创建 CreateSystem
负责监听鼠标点击事件。

public class CreateSystem : ReactiveSystem<InputEntity>
{
    private Transform _parent;
    private GameContext _gameContext;
    public CreateSystem(Contexts contexts) : base(contexts.input)
    {
        this._gameContext = contexts.game;
        this._parent = new GameObject("CreateParent").transform;
    }
    protected override ICollector<InputEntity> GetTrigger(IContext<InputEntity> context)
    {
        return context.CreateCollector(InputMatcher.InputExampleMouse);
    }
    protected override bool Filter(InputEntity entity)
    {
        return entity.hasInputExampleMouse && entity.inputExampleMouse.mouseEventType == EMouseEventType.Down;
    }
    protected override void Execute(List<InputEntity> entities)
    {
        foreach (InputEntity entity in entities)
        {
            GameEntity gameEntity = this._gameContext.CreateEntity();

            Transform transform = this.GetEntityTransform(gameEntity);//添加Transform组件
            gameEntity.AddInputExampleTransform(transform);

            Vector2 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);//添加Position组件
            gameEntity.AddInputExamplePosition(worldPos);

            string spriteName = "Test Sprite Name";//添加Sprite组件
            gameEntity.AddInputExampleSprite(spriteName);

        }
    }
    private Transform GetEntityTransform(GameEntity gameEntity)
    {
        GameObject go = new GameObject("Clone");
        go.transform.SetParent(this._parent);
        go.Link(gameEntity, this._gameContext);//物体与Entity进行 链接
        return go.transform;
    }
}

4.创建 ChangePositonSystem
负责物体修改坐标。

public class ChangePositionSystem : ReactiveSystem<GameEntity>
{
    public ChangePositionSystem(Contexts contexts) : base(contexts.game)
    {
    }
    protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context)
    {
        return context.CreateCollector(GameMatcher.InputExamplePosition);
    }
    protected override bool Filter(GameEntity entity)
    {
        return entity.hasInputExamplePosition && entity.hasInputExampleTransform;
    }
    protected override void Execute(List<GameEntity> entities)
    {
        foreach (GameEntity entity in entities)
        {
            Vector2 postion = entity.inputExamplePosition.position;
            Transform transform = entity.inputExampleTransform.transform;
            transform.position = postion;
        }
    }
}

5.创建 ChangeSpriteSystem
负责修改图片显示。

public class RenderSpriteSystem : ReactiveSystem<GameEntity>
{
    public RenderSpriteSystem(Contexts contexts) : base(contexts.game)
    {
    }
    protected override ICollector<GameEntity> GetTrigger(IContext<GameEntity> context)
    {
        return context.CreateCollector(GameMatcher.InputExampleSprite);
    }
    protected override bool Filter(GameEntity entity)
    {
        return entity.hasInputExampleSprite && entity.hasInputExampleTransform;
    }
    protected override void Execute(List<GameEntity> entities)
    {
        foreach (GameEntity entity in entities)
        {
            Transform transform = entity.inputExampleTransform.transform;
            SpriteRenderer spriteRenderer = transform.GetComponent<SpriteRenderer>();
            if (spriteRenderer == null)
            {
                spriteRenderer = transform.gameObject.AddComponent<SpriteRenderer>();
            }
            spriteRenderer.sprite = Resources.Load<Sprite>(entity.inputExampleSprite.spriteName);
        }
    }
}

6.创建 两个Feature
GameFeature与InputFeature

public class GameFeature : Feature
{
    public GameFeature(Contexts contexts)
    {
        Add(new RenderSpriteSystem(contexts));
        Add(new ChangePositionSystem(contexts));
    }
}

public class InputFeature : Feature
{
    public InputFeature(Contexts contexts)
    {
        Add(new MouseSystem(contexts));
        Add(new CreateSystem(contexts));
    }
}

7.与Unity进行关联

public class GameController : MonoBehaviour
{
    private Contexts _contexts;
    private Systems _systems;
    // Start is called before the first frame update
    void Start()
    {
        this._contexts = Contexts.sharedInstance;
        this._systems = new Feature("System")
            .Add(new GameFeature(this._contexts))
            .Add(new InputFeature(this._contexts));
        this._systems.Initialize();
    }
    // Update is called once per frame
    void Update()
    {
        this._systems.Execute();
        this._systems.Cleanup();
    }
}

这样就实现了点击屏幕,实例化一个物体,并且修改位置与坐标显示。

问题:
1.使用普通代码的方式不是更简单吗?
这里追求的不是写的快,一是学习ECS的方式,二是把数据和逻辑进行分离。
2.Game和Input有什么区别?
本质上没区别,但是是两个不同上下文,也可以理解为不同的环境。

上一篇:STL 概览


下一篇:STL