Dots最简实践(二),添加碰撞

image

 导入Unity Physics包,并且导入 Samples 案例,否则没有碰撞信息。

1.首先是墙壁,有Collider组件就行

image

 2.然后是子弹设置,因为子弹是运动的,需要添加PhysicsShape,并且设置Collision Response 设置为 Collide Raise Collision Events,同时给子弹添加Rigidbody

image

 3.最后是代码

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Physics;
using Unity.Physics.Systems;
using UnityEngine;

[BurstCompile]
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
public partial struct BulletCollisionSystem : ISystem
{
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate<EndFixedStepSimulationEntityCommandBufferSystem.Singleton>();
        state.RequireForUpdate<SimulationSingleton>(); // 物理仿真单例
    }

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var ecb = SystemAPI
            .GetSingleton<EndFixedStepSimulationEntityCommandBufferSystem.Singleton>()
            .CreateCommandBuffer(state.WorldUnmanaged)
            .AsParallelWriter();

        var job = new CollisionJob
        {
            BulletLookup = SystemAPI.GetComponentLookup<BulletTag>(true),
            WallLookup   = SystemAPI.GetComponentLookup<WallTag>(true),
            Ecb          = ecb
        };

        var sim = SystemAPI.GetSingleton<SimulationSingleton>();
        state.Dependency = job.Schedule(sim, state.Dependency);
    }

    [BurstCompile]
    private struct CollisionJob : ICollisionEventsJob
    {
        [ReadOnly] public ComponentLookup<BulletTag> BulletLookup;
        [ReadOnly] public ComponentLookup<WallTag>   WallLookup;
        public EntityCommandBuffer.ParallelWriter     Ecb;

        public void Execute(CollisionEvent evt)
        {
            var a = evt.EntityA;
            var b = evt.EntityB;

            if (BulletLookup.HasComponent(a) && WallLookup.HasComponent(b))
            {
                Ecb.DestroyEntity(0, a); // sortKey 用 0 即可
                Debug.LogError("销毁物体A");
            }
            else if (BulletLookup.HasComponent(b) && WallLookup.HasComponent(a))
            {
                Ecb.DestroyEntity(0, b);
                Debug.LogError("销毁物体B");
            }
        }
    }
}

public struct BulletTag : IComponentData {}
public struct WallTag   : IComponentData {}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;

public class WallAuthoring : MonoBehaviour
{
    class Baker : Baker<WallAuthoring>
    {
        public override void Bake(WallAuthoring authoring)
        {
            // 为当前GameObject创建或获取对应的Entity。
            // TransformUsageFlags.Dynamic 的含义:动态的,表示这个对象的Transform会频繁变化,比如:移动的玩家、子弹、敌人等
            var entity = GetEntity(TransformUsageFlags.Renderable);
            
            // 给枪械添加输入组件
            AddComponent(entity, new WallTag());
        }
    }
}

记得给子弹添加对应的Tag

 

对ShotSystem做了一些修改

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);
                int rangeZ = random.NextInt(0, 10);
                float3 spawnPosition = transform.Position + forward * 2f + new float3(rangeX, rangeY, rangeZ);
                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
                });
                
                ECB.AddComponent(entityInQueryIndex, bulletEntity, new BulletTag());
            }
        }
    }
}

public static class MyHelper
{
    public static int xx = 99;
}

 

posted @ 2025-09-03 23:54  三页菌  阅读(24)  评论(0)    收藏  举报