Unity-EntitiesSamples-HelloCube-12

发布于 2024-08-04  71 次阅读


之前看的差不多了,就从之前的进度开始写

运行效果

代码解读

SliderHandler.cs

using Unity.Entities;
using UnityEngine;
using UnityEngine.UI;

namespace HelloCube.FixedTimestep
{
    public class SliderHandler : MonoBehaviour
    {
        public Text sliderValueText;

        public void OnSliderChange()
        {
            float fixedFps = GetComponent<Slider>().value;

            // WARNING: accessing World.DefaultGameObjectInjectionWorld is a broken pattern in non-trivial projects.
            // GameObject interaction with ECS should generally go in the other direction: rather than having
            // GameObjects access ECS data and code, ECS systems should access GameObjects.

            var fixedSimulationGroup = World.DefaultGameObjectInjectionWorld
                ?.GetExistingSystemManaged<FixedStepSimulationSystemGroup>();
            if (fixedSimulationGroup != null)
            {
                // The group timestep can be set at runtime:
                fixedSimulationGroup.Timestep = 1.0f / fixedFps;
                // The current timestep can also be retrieved:
                sliderValueText.text = $"{(int)(1.0f / fixedSimulationGroup.Timestep)} updates/sec";
            }
        }
    }
}

在scene中将唯一的拖动条将OnValueChange设为OnSliderChange,将slider对应的文本赋值到sliderValueText。

当Slider的值改变时,获取ECS中的FixedStepSimulationSystemGroup(还能这样的?!)。这个Group内的代码都相当于传统Mono中的FixedUpdate。最后在if语句中改变Fps并更改slider的文本内容。

FixedStepSimulationSystemGroup与SimulationSystemGroup的结构如图:

ProjectileAuthoring

using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;

namespace HelloCube.FixedTimestep
{
    public class ProjectileAuthoring : MonoBehaviour
    {
        class Baker : Baker<ProjectileAuthoring>
        {
            public override void Bake(ProjectileAuthoring authoring)
            {
                var entity = GetEntity(TransformUsageFlags.Dynamic);
                AddComponent<Projectile>(entity);
            }
        }
    }

    public struct Projectile : IComponentData
    {
        public float SpawnTime;
        public float3 SpawnPos;
    }
}

该代码附在预制体内,即上方示例图中生成的片状方块内。

设计了个名为Projectile的data,记录生成的时间与生成的位置。

Baker将预制体从GameObject转换成ECS内的Entity,并加上Projectile的data

DefaultRateSpawnerAuthoring

using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;

namespace HelloCube.FixedTimestep
{
    public class DefaultRateSpawnerAuthoring : MonoBehaviour
    {
        public GameObject projectilePrefab;

        class Baker : Baker<DefaultRateSpawnerAuthoring>
        {
            public override void Bake(DefaultRateSpawnerAuthoring authoring)
            {
                var entity = GetEntity(TransformUsageFlags.None);

                var spawnerData = new DefaultRateSpawner
                {
                    Prefab = GetEntity(authoring.projectilePrefab, TransformUsageFlags.Dynamic),
                    SpawnPos = GetComponent<Transform>().position,
                };
                AddComponent(entity, spawnerData);
            }
        }
    }

    public struct DefaultRateSpawner : IComponentData
    {
        public Entity Prefab;
        public float3 SpawnPos;
    }
}

该代码附在Subscene的VaribleSpawner内

MoveProjectilesSystem

using Unity.Burst;
using Unity.Entities;
using Unity.Transforms;

namespace HelloCube.FixedTimestep
{
    public partial struct MoveProjectilesSystem : ISystem
    {
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<ExecuteFixedTimestep>();
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            var ecbSingleton = SystemAPI.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>();

            new MoveJob
            {
                TimeSinceLoad = (float)SystemAPI.Time.ElapsedTime,
                ProjectileSpeed = 5.0f,
                ECBWriter = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter()
            }.ScheduleParallel();
        }
    }

    [BurstCompile]
    public partial struct MoveJob : IJobEntity
    {
        public float TimeSinceLoad;
        public float ProjectileSpeed;
        public EntityCommandBuffer.ParallelWriter ECBWriter;

        void Execute(Entity projectileEntity, [ChunkIndexInQuery] int chunkIndex, ref LocalTransform transform,
            in Projectile projectile)
        {
            float aliveTime = TimeSinceLoad - projectile.SpawnTime;
            if (aliveTime > 5.0f)
            {
                ECBWriter.DestroyEntity(chunkIndex, projectileEntity);
            }
            transform.Position.x = projectile.SpawnPos.x + aliveTime * ProjectileSpeed;
        }
    }
}

OnCreate内为所有示例的通用部分,在所有示例都在一个工程文件下的情况,控制是否启用system。

OnUpdate内获取FixedStepSimulationSystemGroup内最晚执行的commandBuffer,和当前时间还有移动速度载入MoveJob内。

MoveJob过滤所有有Entity,LocalTransform和Projectile的Entity,并执行Execute内的操作。

场景内所有的移动都通过该system完成

FixedRateSpawnerAuthoring

基本与前文DefaultRateSpawnerAuthoring相同,附在Subscene的FixedSpawner内

DefaultRateSpawnerSystem

using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

namespace HelloCube.FixedTimestep
{
    public partial struct DefaultRateSpawnerSystem : ISystem
    {
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<ExecuteFixedTimestep>();
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            float spawnTime = (float)SystemAPI.Time.ElapsedTime;

            foreach (var spawner in
                     SystemAPI.Query<RefRW<DefaultRateSpawner>>())
            {
                var projectileEntity = state.EntityManager.Instantiate(spawner.ValueRO.Prefab);
                var spawnPos = spawner.ValueRO.SpawnPos;
                spawnPos.y += 0.3f * math.sin(5.0f * spawnTime);

                SystemAPI.SetComponent(projectileEntity, LocalTransform.FromPosition(spawnPos));
                SystemAPI.SetComponent(projectileEntity, new Projectile
                {
                    SpawnTime = spawnTime,
                    SpawnPos = spawnPos,
                });
            }
        }
    }
}

控制生成位置,通过Projectile记录生成时间和生成位置

FixedRateSpawnerSystem

基本与DefaultRateSpawnerSystem相同。唯一不同处为

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
public partial struct FixedRateSpawnerSystem : ISystem

让该system在FixedStepSimulationSystemGroup内。

null
最后更新于 2024-08-24