Dots最简实践(一),一枪打出1000个子弹

image

 输入系统

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;
        }
    }
}

 

posted @ 2025-08-31 12:27  三页菌  阅读(19)  评论(0)    收藏  举报