浅谈《守望先锋》中的 ECS 构架(4)
时间:2019-01-08 07:03 来源:百度新闻 作者:巧天工 点击:次
演讲后面还提到了一些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工作的时候,对大多数组件来说是无副作用的,而把严重副作用的行为集中在单点小心处理。 (责任编辑:波少) |