控制组件状态关闭/开启
在平时开发的需求中,我们可能会遇到需要单独控制某一个组件开启关闭,我们可以将其从 entity 上面 Add/Remove ,但是这其实是一个 Structural changes
(即会导致 unity 重新组织 chunk 或者 chunk 的内容的操作)。这是非常耗时的,因此我们就有了需要开启/关闭组件状态的需求。
RotationSpeedAuthoring
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| namespace HelloCube.EnableableComponents { public class RotationSpeedAuthoring : MonoBehaviour { public bool StartEnable; public float DegreesPerSecond = 360.0f;
public class Baker : Baker<RotationSpeedAuthoring> { public override void Bake(RotationSpeedAuthoring authoring) { var entity = GetEntity(TransformUsageFlags.Dynamic | TransformUsageFlags.NonUniformScale); AddComponent(entity, new RotationSpeed { RadiansPerSecond = math.radians(authoring.DegreesPerSecond) }); SetComponentEnabled<RotationSpeed>(entity, authoring.StartEnable); } } }
struct RotationSpeed : IComponentData, IEnableableComponent { public float RadiansPerSecond; } }
|
第一个改动是 authoring,主要有三个改动的点:
- 添加了一个变量
StartEnbale
来控制开始的时候是否启用组件
- 在
Bake
的最后使用 SetComponentEnabled
来设置了组件状态
RotationSpeed
实现了一个新的接口 IEnableableComponent
RotationSystem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| namespace HelloCube.EnableableComponents { public partial struct RotationSystem : ISystem { private float timer; private const float interval = 1.3f; [BurstCompile] public void OnCreate(ref SystemState state) { timer = interval; state.RequireForUpdate<Execute.EnableableComponents>(); }
[BurstCompile] public void OnUpdate(ref SystemState state) { float deltaTime = SystemAPI.Time.DeltaTime; timer -= deltaTime;
if (timer < 0) { foreach (var rotationSpeedEnabled in SystemAPI.Query<EnabledRefRW<RotationSpeed>>() .WithOptions(EntityQueryOptions.IgnoreComponentEnabledState)) { rotationSpeedEnabled.ValueRW = !rotationSpeedEnabled.ValueRO; }
timer = interval; } foreach (var (transform, speed) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<RotationSpeed>>()) { transform.ValueRW = transform.ValueRO.RotateY(speed.ValueRO.RadiansPerSecond * deltaTime); } } } }
|
第二处改动位于 RotationSystem
,此处实现了应该小的计时器,也就是每次组件停用/启动时的间隔。其他的代码基本上不用管,直接看 if (timer < 0)
里面的组件状态切换逻辑。此处有两个值得注意的地方:
EnableRefRW
查询的是 RotationSpeed
组件的 Enable
状态值而不是其组件本身功能。
- 后面添加了一个
EntityQueryOptions.IgnoreComponentEnabledState
的 option 来确保不会只查询到 Enable
已启用的组件,而忽略了没有启用的组件。