DebugSystem在Editor查看时崩溃
没有实现特殊TypeDrawer会导致崩溃。
查看下Entitas的TypeDrawer,看看自己的Component是否使用了某些类型,但TypeDrawer并没有实现。参考其他实现自己的TypeDrawer,例如我的PositionComp使用了float3类型,需要自己实现Float3TypeDrawer:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using Unity.Mathematics;
using UnityEditor;
using UnityEngine;
namespace Entitas.VisualDebugging.Unity.Editor {
public class Float3TypeDrawer : ITypeDrawer {
public bool HandlesType(Type type) {
return type == typeof(float3);
}
public object DrawAndGetNewValue(Type memberType, string memberName, object value, object target) {
float3 vector = (float3)value;
vector.x = EditorGUILayout.FloatField("x", vector.x);
vector.y = EditorGUILayout.FloatField("y", vector.y);
vector.z = EditorGUILayout.FloatField("z", vector.z);
return vector;
}
}
}
ReactiveSystem的OnAdded/OnRemoved
查看源码Collector.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// Activates the Collector and will start collecting
/// changed entities. Collectors are activated by default.
public void Activate() {
for (int i = 0; i < _groups.Length; i++) {
var group = _groups[i];
var groupEvent = _groupEvents[i];
switch (groupEvent) {
case GroupEvent.Added:
group.OnEntityAdded -= _addEntityCache;
group.OnEntityAdded += _addEntityCache;
break;
case GroupEvent.Removed:
group.OnEntityRemoved -= _addEntityCache;
group.OnEntityRemoved += _addEntityCache;
break;
case GroupEvent.AddedOrRemoved:
group.OnEntityAdded -= _addEntityCache;
group.OnEntityAdded += _addEntityCache;
group.OnEntityRemoved -= _addEntityCache;
group.OnEntityRemoved += _addEntityCache;
break;
}
}
}
group.OnEntityAdded、Group.OnEntityRemoved都会调用_addEntityCache的方法,Entity无论Add还是Removed Component,Entity都会被添加到缓存池中。
所以,如果添加了OnRemoved,则ReactiveSystem中对应的Execute(entities)传入的Entities会包含Added和Removed的Entity。
这个操作无法理解对吧,理论上应该OnAdded的传入的就是Add了Component的Entity,OnRemoved的传入的就是Remove了Component的Entity,但实际上并不是,真奇葩。
所以又提供了Where方法,通过Where去筛选出我们需要的Entity,最开始还以为Filter是脱了裤子放屁多此一举,但到这里才发现这个无语的设计,实际上可以在Entitas层面就避免这个问题,Where只是在特殊处理的时候再实现,过阵子有空的时候再修改下Entitas的代码实现自己筛选的功能。
Entity.Remove<>会报错
错误信息:
1
2
3
4
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.Collections.Generic.List`1+Enumerator[T].MoveNextRare () [0x00013] in <3dd5df5ef4974f29afeb2d3ba227c5da>:0
at System.Collections.Generic.List`1+Enumerator[T].MoveNext () [0x0004a] in <3dd5df5ef4974f29afeb2d3ba227c5da>:0
at Entitas.Entity+ListenerSystem`1[T].OnAdded (System.Collections.Generic.List`1[T] entities) [0x00047] in
这部分跟我新增的ListenerSystem <T>
事件有关。
将foreach()改成for()避免在事件时RemoveListener导致错误。
Context.Remove<>不存在。
Context.Add时,SingleEntity代表一个Comp一个Entity,如果删除Com,Entity不删除,则会导致Entity不断增加。
考虑新增Context.Remove方法,而其中需要调用Context.DestroyEntity
使用Entitas使用问题
- System具体做哪些内容(从官方例子Match-One看)
- System根据Entity对Comp的操作,触发修改其他Comp,也就行根据数据变化修改数据。所以逻辑也写在System,如果该逻辑可能在多处使用,再凑出来叫XXXLogic或XXXUtility.cs(守望先锋开发者用Utility,Entitas官方案例用Logic)静态类静态方法使用。
- 例如:
- BoardSystem
- Initialize 创建随机piece
- Execute 检测Board超出范围则添加DestroyComp
- FallSystem
- Execute 检测有MovableComp,修改PositionComp
- FillSystem
- Execute 检测到DestroyComp和BoardComp被添加,则创建随机P
- InputSystem 根据点击添加InputComp
- ProcessInputSystem 根据InputComp的值,点击到则为该Entity添加DestroyComp
- BoardSystem
- Unity的交互放在那里呢?交互后做什么?
- 放到所有继承MonoBehaviour的交互逻辑处。
- 例如:
- BurstModeButtonController 点击则增加或删除BurstModeComp
- Button.onClick.AddListener(() =>contexts.input.isBurstMode=!contexts.input.isBurstMode);
- 官方案例将Input的获取放到InputSystem,个人觉得不太合适,这样做不方便服务器代码运行,应该放到MonoBehaviour根据Input修改Input状态。
- BurstModeButtonController 点击则增加或删除BurstModeComp
- Unity的状态修改放在哪里呢?
- 为所有继承MonoBehaviour的类添加IListener增加监听,根据监听修改状态
- 例如:
- BurstModeButtonController 根据InputComp变化修改文字。(此处有InputEntity的疑问)
- CameraView AnyBoard监听变化,触发OnAnyBoard调用修改camera的orthographicSize和Transform
- ScoreLabelController 根据ScoreComp的变化修改分数
- 如使用Unity的碰撞交互会导致代码跟Unity挂钩严重,无法实现数据和可视化分离。
- 直观的想法有两个:
- 一是需要碰撞检测时再调用Unity的方法,这样代码在服务器就无法运行。
- 二是实现自己的碰撞检测,但就需要为所有Unity GameObject生成对应的数据。
- 大概思路是
- Unity获得数据,例如两个立方体数据or导航地形网格,然后在逻辑中继续计算。这需要在数据层就有碰撞检测等逻辑,不能直接使用Unity的接口。
- 直观的想法有两个:
- 不要为了监听增加没有数据的Comp,监听部分,如果需要绑定Entity使用则使用IListener,不需要则使用EventManager。
- 例如:UI事件。