一、ECS框架简介
ECS(Entity-Component-System)是一种游戏引擎开发中常见的架构,其主要思想是将游戏对象拆分为实体(Entity)、组件(Component)和系统(System)三个部分,分别处理不同的逻辑。在ECS架构中,实体仅仅是一个ID,而组件则是具体的属性,系统则用于处理这些属性。
以Unity为例,使用ECS框架可以提高游戏的性能,降低开发难度,提高游戏可玩性。其中,实体是一个GameObject,组件就是该GameObject上挂载的MonoBehaviour脚本,而系统则是用Job System编写的管理逻辑。下面我们将从组件、实体、系统三个方面详细讲解ECS框架。
二、ECS框架中的组件
组件是ECS框架中的核心,是游戏逻辑的具体表现。组件的表现形式是一个结构体,其中包含该组件的所有属性。一个实体可以拥有多个组件,通过组件的组合来表现实体的不同状态。
在Unity中,使用IComponentData接口或者Component基类来表示组件。其中,IComponentData接口只包含数据,而Component基类则可以继承MonoBehaviour,同时也包含一些函数接口(比如可以使用Start和Update函数)。
public struct Velocity : IComponentData {
public float3 Value;
}
public class MoveSystem : JobComponentSystem {
void OnUpdate () {
Entities.
ForEach ((ref Translation translation, in Velocity velocity) => {
translation.Value += velocity.Value * Time.deltaTime;
});
}
}
上述代码展示了一个Velocity组件,其包含一个float3类型的速度值。同时,MoveSystem使用Job System实现了这个组件的计算逻辑。在这里,Entities.ForEach函数表示对于每个实体,都要执行后面的语句。其中,ref表示该参数即是输入又是输出参数,而in则表示该参数是只读参数,避免了多线程之间的数据冲突。
三、ECS框架中的实体
实体是ECS框架中最重要的概念,因为实体是游戏对象的具体表现形式。在ECS架构中,实体只是一个ID,所有实体的状态都由它所拥有的组件来决定。实体不包括任何行为,行为由组件和系统来完成。
在Unity中,Entity是通过EntityManager来管理的。EntityManager以实体的ID为索引,保存所有的实体信息。EntityManager还提供了一些函数接口,可以对实体进行增加、删除、查询等操作。
public class GameManager : MonoBehaviour {
public static GameManager Instance;
EntityManager entityManager;
void Awake() {
Instance = this;
entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
}
public void CreateCube() {
Entity entity = entityManager.CreateEntity(CubeArchetype);
entityManager.SetComponentData(entity, new Translation { Value = new float3(Random.Range(-10,10),Random.Range(-10,10),0)});
entityManager.SetComponentData(entity, new Velocity { Value = new float3(Random.Range(-10,10),Random.Range(-10,10),0)});
}
private void OnDestroy() {
entityManager.DestroyEntity(Entities);
}
}
上述代码展示了如何创建和销毁实体。其中,CreateCube函数创建了一个Cube实体,并将它的位置和速度设置为随机值。而OnDestroy函数则销毁了所有的实体。
四、ECS框架中的系统
系统是ECS框架中实际处理组件逻辑的部分,它们是本质上是依赖数据的代码片段,负责更新实体状态。每个系统专注于管理不同类型的组件,通过过滤器来获取匹配的实体并进行逻辑计算。
在Unity中,使用Job Component System编写系统,可以达到最佳的性能。Job Component System是一种基于Job System的高性能框架,利用了多线程的优势,实现了分离和并行计算。在系统中,可以使用Entities.ForEach函数来遍历匹配的实体和组件,或者通过JobHandle来处理大量的计算任务。
public struct RotationSpeed : IComponentData {
public float Value;
}
public class RotationSystem : JobComponentSystem {
[BurstCompile]
struct RotationSpeedJob : IJobForEach {
public float deltaTime;
public void Execute(ref Rotation rotation, [ReadOnly] ref RotationSpeed speed) {
rotation.Value = math.mul(math.normalize(rotation.Value), quaternion.AxisAngle(math.up(), speed.Value * deltaTime));
}
}
protected override JobHandle OnUpdate(JobHandle inputDeps) {
var job = new RotationSpeedJob {
deltaTime = Time.deltaTime
};
return job.Schedule(this, inputDeps);
}
}
上述代码展示了一个旋转系统,其包含一个RotationSpeed组件和一个Rotation组件。在Execute函数中,通过quaternion.AxisAngle函数计算旋转后的欧拉角,然后将结果赋给Rotation组件。
五、ECS框架的优缺点
优点:
1、性能优越。ECS框架可以充分利用 Job System 的多线程计算,提高游戏的性能。
2、代码可维护性高。在ECS框架中,同种类型的组件都是按照分类存放的,代码中的逻辑可以根据不同的系统来实现,更方便代码的维护和开发。
3、适合高并发场景。ECS的运行方式适合处理大量相似的结构,尤其适合高并发场景。
缺点:
1、学习曲线较陡峭。ECS框架和普通的游戏开发方法有较大的差异,需要一定的学习时间来适应。
2、不适合小型游戏。ECS框架适合大型游戏,因为它包含大量的组件和系统,对于小型游戏则有些繁琐。
3、不支持常规的Unity组件。在ECS框架中,仅支持IComponentData接口或者Component基类,无法很好地支持常规的Unity组件。