前言:
本文使用Entitas插件,开发一个逻辑表现分离的小Demo
好多教程都是写个HelloWorld的,毫无营养
后续会根据这个一点一点开发,补充功能:预测or回滚
这次要做什么?
很简单,逐帧update,然后显示在UI上
逻辑系统:一直在update增加帧数
渲染系统:当帧数变化时,同时UI更新显示(可有可无,不影响逻辑运行)
1.导入插件
本次用到的插件目录:传送门
点击右边的Release,下载 1.13.0 这个版本(最新)
然后解压,把Assets目录下的文件都导入到Unity工程中,如图所示:
主要就两个目录:
1.DesperateDevs
2.Entitas
2.游戏开发
点击菜单栏下的Tools->Jenny->Preference
如果是第一次打开,点击AutoImport
找到Contexts,修改原来的Game为 Logic 和 Render
Contexts 是什么意思呢?
我们不懂的话可以理解为一个环境(上下文),两者互不影响但是可以相互访问
这里我们把Logic作为一个单独的环境,Render作为另一个单独的环境
也就是说Logic环境也可以单独运行,Render环境是需要Logic环境发事件运行的
最后点击,Generate 生成代码。
创建一下工程整体的目录结构:
主要分为两个部分:
1.Component:所有数据组件的地方
2.System:所有操作组件的逻辑的地方
每个文件夹下都有两个字文件夹,分别是Logic和Render,区分到底是逻辑层还是渲染层的
创建第一个数据组件:TickComponent
[Logic, Unique]
public struct TickComponent : IComponent
{
public int currentTick;
}
注意:
1.struct和class语法都允许,具体用啥暂时也不知道,后续看看
2.Logic特性代表属于这个环境,可以对逻辑的Entity添加这个数据组件
3.Unqiue特性代表这个是全局唯一的,类似单例
然后回到刚才的Jenny界面,再次点击生成,大概会生成如下文件:
1.有一个全局的tickEntity对象
2.提供全局方便的 Set/Replace/Remove 方法
public partial class LogicContext {
public LogicEntity tickEntity { get { return GetGroup(LogicMatcher.Tick).GetSingleEntity(); } }
public TickComponent tick { get { return tickEntity.tick; } }
public bool hasTick { get { return tickEntity != null; } }
public LogicEntity SetTick(int newCurrentTick) {
if (hasTick) {
throw new Entitas.EntitasException("Could not set Tick!\n" + this + " already has an entity with TickComponent!",
"You should check if the context already has a tickEntity before setting it or use context.ReplaceTick().");
}
var entity = CreateEntity();
entity.AddTick(newCurrentTick);
return entity;
}
public void ReplaceTick(int newCurrentTick) {
var entity = tickEntity;
if (entity == null) {
entity = SetTick(newCurrentTick);
} else {
entity.ReplaceTick(newCurrentTick);
}
}
public void RemoveTick() {
tickEntity.Destroy();
}
}
然后创建对应的操作System:TickUpdateSystem
这个的逻辑,就是每次Excute的时候,把全局的这个tickCount++
public class TickUpdateSystem : IInitializeSystem, IExecuteSystem
{
LogicContext _logicContext;
public TickUpdateSystem(Contexts contexts)
{
_logicContext = contexts.logic;
}
public void Initialize()
{
_logicContext.ReplaceTick(0);
}
public void Execute()
{
_logicContext.ReplaceTick(_logicContext.tick.currentTick + 1);
}
}
注意:
1.IInitializeSystem,是第一次初始化的接口
2.IExecuteSystem,是每帧Excute的接口
这样的话逻辑系统就创建完成了,我们可以构建Systems先跑起来游戏了!
创建一个Monobehaviour脚本,挂在场景物体上,接收Unity的回调
public class ECSTestController : MonoBehaviour
{
Systems _system;
void Start()
{
Contexts contexts = Contexts.sharedInstance;
_system = new Feature("LogicSystem")
.Add(new TickUpdateSystem(contexts));
_system.Initialize();
}
void Update()
{
_system.Execute();
_system.Cleanup();
}
void OnDestroy()
{
_system.TearDown();
}
}
然后运行游戏,可以看到场景中多了几个物体:
1.自己创建的 LogicSystem
2.全局自动创建创建的 Entity_0,上面有一个TickComonent组件
选中这个Entity_0,查看Inspector面板:
可以看到里面的currentTick正在一直增加
OK,逻辑系统已经正常跑起来了,下一篇开始写渲染系统。