//增加、获取、移除组件
entity.AddComponent(index, component);
entity.GetComponent(index);
entity.RemoveComponent(index);
//1、给实体赋值
//Position为一个组件,其结构为保存一个Vector2 pos;
//方法一(效率慢):使用使用Generate生成的Add代码
entity.AddPosition(3, 7);
//方法二:直接赋值(速度据说比方法一快三倍)
entity.Position.pos = new vector2(3,7);
//组件标签,当组件为空的时候,那么该组件相当于一个Tag或者Flag
entity.isMovable = false;
//2、获取实体的其中组件值
var hasPos = entity.hasPosition;
// Contexts.game由代码自动生成
var gameContext = Contexts.game;
var entity = gameContext.CreateEntity();
entity.isMovable = true;
// Returns all entities having MovableComponent and PositionComponent.
// Matchers也会自动生成
var entities = gameContext.GetEntities(Matcher.AllOf(GameMatcher.Movable, GameMatcher.Position));
foreach (var e in entities) {
// do something
}
gameContext.GetGroup(GameMatcher.Position).GetEntities();
gameContext.GetEntities(GameMatcher.Movable)
也是使用组的结构。OnEntityAdded
, OnEntityRemoved
and OnEntityUpdated
可以直接对组的更改做出反应。gameContext.GetGroup(GameMatcher.Position).OnEntityAdded += (group, entity, index, component) => {
// Do something
};
//group事件
OnEntityAdded
OnEntityRemoved
OnEntityUpdated
//获取一个group,所有使用了GameBoardElement.Removed()事件(即删除了该组件)的Entity
context.CreateCollector(GameMatcher.GameBoardElement.Removed());
//总共三个Added,Removed,AddedOrRemoved
//这里有个问题有待验证一下,如果不使用他生成的Add而是我手动直接更改的方式更改数据是否也会被检测到。我猜测应该是不可以
var group = gameContext.GetGroup(GameMatcher.Position);
var collector = group.CreateCollector(GroupEvent.Added);
foreach (var e in collector.collectedEntities) {
// do something with all the entities
// that have been collected to this point of time
}
collector.ClearCollectedEntities();
//查询所有拥有某些组件的GameEntity。AllOf代表全满足,AnyOf至少满足一个,NoneOf没有该组件则满足条件。NoneOf不能单独使用,必须搭配前两者一起使用,因为NoneOf可能会使得产生的查询过长
//慎用AnyOf,他可能会返回预期之外的结果。如果发生这种情况,建议使用多个GameMatcher来进行合并查找,而非AnyOf
context.GetGroup(GameMatcher.AllOf(GameMatcher.Position,GameMatcher.Velocity).NoneOf(GameMatcher.NotMovable));
[Context]: 你可以使用这个属性让它仅在特定的上下文中可以被获取; ,[MyContextName], [Enemies], [UI], etc. 提高内存占用率。不仅如此,他还可以创建组件。
[Unique]: 代码生成器将会提供一个额外的方法,来确保最大仅有一个实体在这个组件上存在。
[FlagPrefix]: 这个属性可以给你的组件标记一个自定义的前缀。
[PrimaryEntityIndex]: 可以将实体固定为一个唯一的组件值。
[EntityIndex]: 可用于通过组件值寻找相对应的组件。
[CustomComponentName]: 生成多个名字不同的组件继承自同一个类或者同一个接口。
[DontGenerate]: 代码生成器将会跳过这个属性的组件。
[Event]: 代码生成器将会为反应式的UI 生成相应的组件,系统。接口。
[Cleanup]: 代码生成器将会生成一处组件或者删除组件。
public class MatchOneSystems : Feature {
public MatchOneSystems(Contexts contexts) {
// Input
Add(new InputSystems(contexts));
// Update
Add(new GameBoardSystems(contexts));
Add(new GameStateSystems(contexts));
// Render
Add(new ViewSystems(contexts));
// Destroy
Add(new DestroySystem(contexts));
}
}
using Entitas;
using UnityEngine;
public class GameController : MonoBehaviour {
Systems _systems;
void Start() {
Random.InitState(42);
var contexts = Contexts.sharedInstance;
_systems = new MatchOneSystems(contexts);
_systems.Initialize();
}
void Update() {
_systems.Execute();//检查所有可执行System
_systems.Cleanup();//执行完成之后进行清除
}
void OnDestroy() {
_systems.TearDown();//释放
}
}
using System.Collections.Generic;
using Entitas;
public sealed class DestroySystem : ReactiveSystem {
public DestroySystem(Contexts contexts) : base(contexts.game) {
}
//CreateCollector的默认检测事件为Add所以在示例中没有添加
protected override ICollector GetTrigger(IContext context) {
return context.CreateCollector(GameMatcher.Destroyed);
}
//过滤返回所有拥有该组件的Entity
protected override bool Filter(GameEntity entity) {
return entity.isDestroyed;
}
//DestroySystem在每个周期都会运行,但Execute只有在Collector收集到内容后才执行
protected override void Execute(List entities) {
foreach (var e in entities) {
e.Destroy();
}
}
}
using UnityEngine;
public class GameManager : MonoBehaviour
{
private GameSystem m_gameSystem;
///
/// 唤醒时创建游戏系统
///
private void Awake()
{
m_gameSystem = new GameSystem(Contexts.sharedInstance);
}
///
/// 游戏系统实例化生成
///
private void Start()
{
m_gameSystem.Initialize();
}
///
/// 用Unity原生Update检查那些System需要执行以及清理
///
private void Update()
{
m_gameSystem.Execute();
m_gameSystem.Cleanup();
}
///
/// ECS清理回收
///
private void OnDestroy()
{
m_gameSystem.TearDown();
}
}
public class GameSystem : Feature
{
public GameSystem(Contexts contexts)
{
//玩家初始化
Add(new PlayerSpawnSystem(contexts));
//玩家输入
Add(new InputSystem(contexts));
Add(new PlayerInputProcessSystem(contexts));
//移动
Add(new MoveSystem(contexts));
//加载实体到场景
Add(new AddViewSystem(contexts));
//清理
Add(new InputCleanupSystem(contexts));
}
}
public static class EntityUtil
{
///
/// 创建PlayerEntity
///
///
/// 生成位置
/// 速度
///
public static GameEntity creatPlayerEntity(Contexts contexts, Vector2 pos,Vector2 vel)
{
var playerEntity = contexts.game.CreateEntity();
playerEntity.isPlayerTag = true;
playerEntity.AddPosComp(pos);
playerEntity.AddVelComp(vel);
playerEntity.AddCreatObjectCmdComp("Prefab/Player");
return playerEntity;
}
}
public class PlayerSpawnSystem :IInitializeSystem
{
private readonly Contexts m_context;
public PlayerSpawnSystem(Contexts contexts)
{
m_context = contexts;
}
public void Initialize()
{
EntityUtil.creatPlayerEntity(m_context, Vector2.zero, Vector2.zero);
}
}
public class AddViewSystem : ReactiveSystem
{
private readonly Contexts m_contexts;
public AddViewSystem(Contexts contexts) : base(contexts.game)
{
m_contexts = contexts;
}
///
/// 调用Entity生成和绘制模块
///
/// 所有符合条件的Entity
protected override void Execute(List entities)
{
foreach(var entity in entities)
{
var obj = SpawnObj(entity);
entity.AddViewComp(obj);
//生成之后就无须再次生成,所以直接移除生成Comp
entity.RemoveCreatObjectCmdComp();
}
}
protected override bool Filter(GameEntity entity)
{
return true;
}
protected override ICollector GetTrigger(IContext context)
{
return context.CreateCollector(GameMatcher.CreatObjectCmdComp);
}
///
/// 生成Enity所链接的Gameobject的方法
///
///
///
private GameObject SpawnObj(GameEntity gameEntity)
{
var path = gameEntity.creatObjectCmdComp.path;
var prefab = Resources.Load(path);
var obj = GameObject.Instantiate(prefab,Vector3.zero,Quaternion.identity);
var view = obj.GetComponent();
view.Link(m_contexts, gameEntity);
return obj;
}
}
public class InputSystem : IExecuteSystem
{
private readonly Contexts m_contexts;
public InputSystem(Contexts contexts)
{
m_contexts = contexts;
}
public void Execute()
{
var playerInputEntity = m_contexts.input.CreateEntity();
playerInputEntity.AddInputComp(new Vector2(
Input.GetAxis("Horizontal"),
Input.GetAxis("Vertical")
));
}
}
public class PlayerInputProcessSystem : ReactiveSystem
{
private readonly Contexts m_contexts;
private readonly IGroup m_playerGroup;
public PlayerInputProcessSystem(Contexts contexts) : base(contexts.input)
{
m_contexts = contexts;
m_playerGroup = m_contexts.game.GetGroup(GameMatcher.PlayerTag);
}
///
/// 获取速度读入并给Player赋值
///
/// PlayerEntity单例
protected override void Execute(List entities)
{
var playerEntity = m_playerGroup.GetSingleEntity();
foreach (var inputEntity in entities)
{
playerEntity.velComp.value = new Vector2(
inputEntity.inputComp.Dir.x * PlayerSettings.PlayerSpeed,
inputEntity.inputComp.Dir.y * PlayerSettings.PlayerSpeed);
}
}
protected override bool Filter(InputEntity entity)
{
return true;
}
protected override ICollector GetTrigger(IContext context)
{
return context.CreateCollector(InputMatcher.InputComp);
}
}
public class MoveSystem : IExecuteSystem
{
private readonly IGroup m_group;
public MoveSystem(Contexts contexts)
{
m_group = contexts.game.GetGroup(GameMatcher.AllOf(
GameMatcher.PosComp,
GameMatcher.VelComp,
GameMatcher.ViewComp
));
}
///
/// 获取移动速度,根据速度更改人物位置
///
public void Execute()
{
//移动
var dt = Time.deltaTime;
foreach(var entity in m_group.GetEntities())
{
var posComp = entity.posComp;
var velComp = entity.velComp;
float sidewaysRate = 1f;
if (velComp.value.x != 0 && velComp.value.y != 0)
sidewaysRate = 0.7f;
entity.ReplacePosComp(new Vector2(
posComp.value.x + dt * velComp.value.x * sidewaysRate,
posComp.value.y + dt * velComp.value.y * sidewaysRate
));
entity.viewComp.view.transform.position = entity.posComp.value;
}
}
}
public class InputCleanupSystem : ICleanupSystem
{
private readonly Contexts m_context;
public InputCleanupSystem(Contexts contexts)
{
m_context = contexts;
}
public void Cleanup()
{
m_context.input.DestroyAllEntities();
}
}