Entity的创建
GameContext gameContext = Contexts.sharedInstance.game;
var entity = gameContext.CreateEntity();
entity只可以通过Contexts创建,任何Contexts都可创建其对应的entity,例如GameContext创建GameEntity,InputContext创建InputEntity。为什么至于必须要用Contexts创建entity,可以查看其创建代码,如下:
//Context.cs
public TEntity CreateEntity()
{
TEntity entity;
if (this._reusableEntities.Count > 0)
{
entity = this._reusableEntities.Pop();
entity.Reactivate(this._creationIndex++);
}
else
{
entity = this._entityFactory();
entity.Initialize(this._creationIndex++, this._totalComponents, this._componentPools, this._contextInfo, this._aercFactory((IEntity) entity));
}
this._entities.Add(entity);
entity.Retain((object) this);
this._entitiesCache = (TEntity[]) null;
entity.OnComponentAdded += this._cachedEntityChanged;
entity.OnComponentRemoved += this._cachedEntityChanged;
entity.OnComponentReplaced += this._cachedComponentReplaced;
entity.OnEntityReleased += this._cachedEntityReleased;
entity.OnDestroyEntity += this._cachedDestroyEntity;
// ISSUE: reference to a compiler-generated field
if (this.OnEntityCreated != null)
{
// ISSUE: reference to a compiler-generated field
this.OnEntityCreated((IContext) this, (IEntity) entity);
}
return entity;
}
- 可以很明显的看出,entity的创建使用的对象池技术,销毁的对象
可重复利用
的entity保存在名为_reusableEntities的栈中。利用对象池的好处相信每个人都明白。 - 另一个原因利用Contexts创建的对象都可以通过该Context获取到,保存在名为_entities的HashSet中(不可以有重复对象,保证了对象的唯一想),可以通过如下代码获取该Contexts中所有的entity。
var entities = gameContext.GetEntities();
Entity 的销毁
有entity的创建,自然就有entity的销毁,可通过entity自身调用Destroy方法销毁,如下:
entity.Destroy();
看一下调用过程中发生了什么:
//Entity.cs
public void Destroy()
{
if (!this._isEnabled)
throw new EntityIsNotEnabledException("Cannot destroy " + (object) this + "!");
// ISSUE: reference to a compiler-generated field
if (this.OnDestroyEntity == null)
return;
// ISSUE: reference to a compiler-generated field
this.OnDestroyEntity((IEntity) this);
}
是不是对OnDestroyEntity这个事件名称很熟悉,因为在创建entity时,对其进行了赋值,如下:
//Context.cs
public TEntity CreateEntity()
{
......//省略前面代码
entity.OnDestroyEntity += this._cachedDestroyEntity;
......//省略后面代码
return entity;
}
_cachedDestroyEntity这个事件在Contexts初始化时进行了赋值,最终OnDestroyEntity监听的方法为Contexts中的onDestroyEntity(IEntity entity)方法,如下:
//Context.cs
private void onDestroyEntity(IEntity entity)
{
......//省略前面代码
if (entity1.retainCount == 1) //判断包含该entity的对象的数量是否为1.(也就是否只用该Contexts包含了该entity)
{
entity1.OnEntityReleased -= this._cachedEntityReleased;
this._reusableEntities.Push(entity1); //放入对象池中
entity1.Release((object) this); //将引用删除
entity1.RemoveAllOnEntityReleasedHandlers();
}
else
{
this._retainedEntities.Add(entity1);
entity1.Release((object) this);
}
}
可以看到,有且只有创建该entity的Contexts包含这个entity时,删除时才会证明这个entity可以重复利用
,那这个Contexts是什么时候包含的这个entity呢,也是在创建的时候:
public TEntity CreateEntity()
{
......//省略前面代码
entity.Retain((object) this);
......//省略后面代码
}
接下来看一下entity1.retainCount中的属性retainCount:
public int retainCount
{
get
{
return this._aerc.retainCount;
}
}
_aerc是一个SafeAERC对象,其具体实现细节如下所示:
public sealed class SafeAERC : IAERC
{
private readonly HashSet<object> _owners = new HashSet<object>();
private readonly IEntity _entity;
public int retainCount
{
get
{
return this._owners.Count;
}
}
public HashSet<object> owners
{
get
{
return this._owners;
}
}
public SafeAERC(IEntity entity)
{
this._entity = entity;
}
public void Retain(object owner)
{
if (!this.owners.Add(owner))
throw new EntityIsAlreadyRetainedByOwnerException(this._entity, owner);
}
public void Release(object owner)
{
if (!this.owners.Remove(owner))
throw new EntityIsNotRetainedByOwnerException(this._entity, owner);
}
}
综上所述,如果entity1.retainCount大于1时,也就是我们自行调用了entity.Retain(a)方法,在Destroy entity 之前,要先调用entity.Release(a),将这个entity从那个对象a中删除,否则entity不会进入对象池,也不会被重复利用,而永久存在内存中,造成内存泄漏。
Entity与Component的关系
Entity相当于一个Component的集合,一个Entity可以有多个Component,我们可以通过Generate Code很方便的添加,删除和替换Component。例如:
public void Initialize()
{
var entity = game.CreateEntity();
entity.AddAssetName("Player");
entity.AddPosition(Vector3.zero);
entity.AddSpeed(0,0.03f);
entity.isSpecial = true;
entity.RemoveSpeed();
}