Dots最简实践(一),一枪打出1000个子弹
输入系统
using System.Collections; using System.Collections.Generic; using Unity.Entities; using UnityEngine; public class InputMono : MonoBehaviour { private EntityManager entityManager; private Entity playerGunEntity; void Start() { entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; //获取唯一挂载了 PlayerInputComponent 组件的实体 playerGunEntity = entityManager.CreateEntityQuery(typeof(PlayerInputComponent)).GetSingletonEntity(); } void Update() { var input = entityManager.GetComponentData<PlayerInputComponent>(playerGunEntity); input.firePressed = Input.GetMouseButtonDown(0); entityManager.SetComponentData(playerGunEntity, input); } }
放在sub scene里面的枪械
using System.Collections; using System.Collections.Generic; using UnityEngine; using Unity.Entities; public class GunAuthoring : MonoBehaviour { [Header("枪属性")] public int bulletsPerShot = 10000; public float bulletSpeed = 5f; public float bulletLifetime = 5f; public float damage = 5f; public GameObject bulletPrefab; class Baker : Baker<GunAuthoring> { public override void Bake(GunAuthoring authoring) { // 为当前GameObject创建或获取对应的Entity。 // TransformUsageFlags.Dynamic 的含义:动态的,表示这个对象的Transform会频繁变化,比如:移动的玩家、子弹、敌人等 var entity = GetEntity(TransformUsageFlags.Dynamic); // 枪械属性 AddComponent(entity, new GunComponent { bulletsPerShot = authoring.bulletsPerShot, bulletSpeed = authoring.bulletSpeed, bulletLifetime = authoring.bulletLifetime, damage = authoring.damage, bulletPrefab = GetEntity(authoring.bulletPrefab, TransformUsageFlags.Dynamic) }); // 给枪械添加输入组件 AddComponent(entity, new PlayerInputComponent { firePressed = false }); } } }
开火系统
using Unity.Collections; using Unity.Entities; using Unity.Mathematics; using Unity.Transforms; using Unity.Burst; using Unity.Jobs; using UnityEngine; using Unity.Rendering; // 输入组件 public struct PlayerInputComponent : IComponentData { public bool firePressed; // 是否按下开火键 } // 枪械组件 public struct GunComponent : IComponentData { public int bulletsPerShot; // 每次射击的子弹数量 public float bulletSpeed; // 子弹速度 public float bulletLifetime; // 子弹生存时间 public float damage; // 每颗子弹伤害 public Entity bulletPrefab; // 子弹预制体实体 } // 子弹组件,包含子弹的基本属性 public struct BulletComponent : IComponentData { public float3 velocity; // 速度向量 public float lifetime; // 剩余生存时间 public float maxLifetime; // 最大生存时间 public float damage; // 伤害值 public float speed; // 速度大小 } [UpdateInGroup(typeof(SimulationSystemGroup))] public partial struct ShotSystem : ISystem { private Unity.Mathematics.Random myRandom; [BurstCompile] public void OnCreate(ref SystemState state) { state.RequireForUpdate<BeginSimulationEntityCommandBufferSystem.Singleton>(); myRandom = new Unity.Mathematics.Random(1234); } [BurstCompile] public void OnUpdate(ref SystemState state) { // 获取枪械 var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; var playerGunEntity = entityManager.CreateEntityQuery(typeof(PlayerInputComponent)).GetSingletonEntity(); //获取输入组件有没有开火 var input = entityManager.GetComponentData<PlayerInputComponent>(playerGunEntity); if (!input.firePressed) { return; } Debug.Log("按下了开火按钮"); // 在第一次运行时获取并缓存 var ecb = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>(); var ecbWrite = ecb.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter(); // 处理射击 var fireJob = new FireBulletsJob { ECB = ecbWrite, random = myRandom, }; state.Dependency = fireJob.ScheduleParallel(state.Dependency);//固定写法,排队执行 } [BurstCompile] public partial struct FireBulletsJob : IJobEntity { public EntityCommandBuffer.ParallelWriter ECB; public Unity.Mathematics.Random random; void Execute([EntityIndexInQuery] int entityInQueryIndex, in GunComponent shotgun, in LocalTransform transform) { // 计算发射方向(假设向前发射) float3 forward = math.forward(transform.Rotation); // 发射子弹 for (int i = 0; i < shotgun.bulletsPerShot; i++) { // 计算子弹方向 float3 bulletDirection = forward; // 创建子弹实体 var bulletEntity = ECB.Instantiate(entityInQueryIndex, shotgun.bulletPrefab); // 设置子弹位置(在枪口位置稍微前面一点) int rangeX = random.NextInt(0, 100); int rangeY = random.NextInt(0, 100); float3 spawnPosition = transform.Position + forward * 2f + new float3(rangeX, rangeY, 0); ECB.SetComponent(entityInQueryIndex, bulletEntity, LocalTransform.FromPositionRotation( spawnPosition, quaternion.LookRotationSafe(bulletDirection, math.up()) )); // 添加子弹组件 ECB.AddComponent(entityInQueryIndex, bulletEntity, new BulletComponent { velocity = bulletDirection * shotgun.bulletSpeed, lifetime = shotgun.bulletLifetime, maxLifetime = shotgun.bulletLifetime, damage = shotgun.damage, speed = shotgun.bulletSpeed }); } } } } public static class MyHelper { public static int xx = 99; }
子弹移动系统
using Unity.Burst; using Unity.Entities; using Unity.Transforms; [BurstCompile] public partial struct BulletMoveSystem : ISystem { [BurstCompile] public void OnUpdate(ref SystemState state) { float deltaTime = SystemAPI.Time.DeltaTime; var moveJob = new MoveBulletsJob { DeltaTime = deltaTime }; state.Dependency = moveJob.ScheduleParallel(state.Dependency); } [BurstCompile] public partial struct MoveBulletsJob : IJobEntity { public float DeltaTime; //让所有同时拥有 LocalTransform 和 BulletComponent 的组件的 实体 ,进行移动 void Execute(ref LocalTransform transform, ref BulletComponent bullet) { // 移动子弹 transform.Position += bullet.velocity * DeltaTime; // 减少生存时间 bullet.lifetime -= DeltaTime; } } }