游戏编程模式
MVVM模式
https://github.com/MEyes/uMVVM
https://github.com/nie341/Unity-Weld
https://github.com/nie341/hugula
ECS框架:
ECS 的设计就是为了管理复杂度,它提供的指导方案就是 Component 是纯数据组合,没有任何操作这个数据的方法;
而 System 是纯方法组合,它自己没有内部状态。它要么做成无副作用的纯函数,根据它所能见到的对象 Component 组合计算出某种结果;要么用来更新特定 Component 的状态。System 之间也不需要相互调用(减少耦合),是由游戏世界(外部框架)来驱动若干 System 的。如果满足了这些前提条件,每个 System 都可以独立开发,它只需要遍历给框架提供给它的组件集合,做出正确的处理,更新组件状态就够了。
编写 Gameplay 的人更像是在用胶水粘合这些 System ,他只要清楚每个 System 到底做了什么,操作本身对哪些 Component 造成了影响,正确的书写 System 的更新次序就可以了。一个 System 对大多数 Component 是只读的,只对少量 Component 是会改写的,这个可以预先定义清楚,有了这个知识,一是容易管理复杂度,二是给并行处理留下了优化空间。
演讲后面还提到了一些 ECS 模式下处理一些复杂问题的常见手法。
Component 没有方法,而 System 则没有状态,只是对定义好的 Component 状态的加工过程。而许多 System 中很可能会处理同一类问题,涉及的 Component 类型是相同的。如果这个有共性的问题只涉及一个 Entity ,那么直观的方法是设计一个 System ,迭代,逐个把结果计算出来,存为 Component 的状态,别的 System 可以在后续把这个结果作为一个状态读出来就可以了。
但如果这个行为涉及多个 Entity ,比如在不同的 System 中,都需要查询两个 Entity 的敌对关系。我们不可能用一个 System 计算出所有 Entity 间的敌对关系,这样必然产生了大量不必要的计算;又或者这个行为并不想额外修改 Component 的状态,希望对它保持无副作用,比如我想持续模拟一个对象随时间流逝的位置变化,就不能用一个 System 计算好,再从另一个 System 读出来。
这样,就引入了 Utility 函数的概念,来做上面这种类型的操作,再把 Utility 函数共享给不同的 System 调用。为了降低系统复杂度,就要求要么这种函数是无副作用的,随便怎么调用都没问题,比如上面查询敌对关系的例子;要么就限制调用这种函数的地方,仅在很少的地方调用,由调用者小心的保证副作用的影响,比如上面那个持续位置变化的过程。
如果产生状态改变这种副作用的行为必须存在时,又在很多 System 中都会触发,那么为了减少调用的地方,就需要把真正产生副作用的点集中在一处了。这个技巧就是推迟行为的发生时机。就是把行为发生时需要的状态保存起来,放在队列里,由一个单独的 System 在独立的环节集中处理它们。
例如不同的射击行为都可能创建出新的对象、破坏场景、影响已有对象的状态。在同一面墙上留下不同的弹孔,不需要堆叠在一起,而只需要保留最后一个,删除前面的。我们可以把让不同的 System 触发这些对象创建、删除的行为,但并不真正去做。集中在一起推迟到当前帧的末尾或下一帧的开头来做。这样就尽量保证了多数 System 工作的时候,对大多数组件来说是无副作用的,而把严重副作用的行为集中在单点小心处理
ET
ET:https://github.com/egametang/ET
1 所有的热更层async void方法一定要try catch异常,并且log.error(exception),否则里面抛异常会看不到正确的出错堆栈。
2 aot问题,集合dictionary是mono层的类,所以mono层没用到的泛型,ilrt层是有问题的,最好用Dictionary<object, object>或者用非泛型集合。
注意这两点,基本上跟用mono的C#没什么区别了
学习文档
https://1090268920.docs.qq.com/JgzDmLgZnGK?opendocxfrom=tim&ADUIN=910281638&ADSESSION=1516758475&ADTAG=CLIENT.QQ.5543_.0&ADPUBNO=26767
knight:https://github.com/winddyhe/knight
Xlua
toLua集成