Unity DOTS学习记录(五)-物理

环境:
Unity:6000.2.10f1
Entities:1.4.3

参考:
https://github.com/Unity-Technologies/EntityComponentSystemSamples

碰撞与刚体

Unity传统项目中的碰撞和刚体是由ColliderRigidBody组件实现的。
而DOTS中没有组件,不过Unity官方的示例工程中提供了一套方便编辑的碰撞组件。

需要在参考中的git仓库PhysicsSamples项目下的/Assets/Samples/Unity Physics目录拖到自己的项目中。
就可以添加这两个组件:

Physics Body相当于RigidBody
Physics Shape相当于Collider
Physics BodyPhysics Shape这两个组件在运行时不会存在,在烘焙阶段就会烘焙成实体上的数据。

射线检测

ECS世界和主场景中的物理是两套系统,互不干涉。
如果想要两个世界交互,只能通过互传数据桥接的方式。
例如:
玩家控制的角色在主场景,而海量的敌人在ECS世界中。这种情况下,如果玩家角色要攻击敌人,比如发射子弹,通过射线检测来判断是否命中敌人。不能在MonoBehaviour中直接使用Physics.RayCast()方法,而是需要用ECS世界中的PhysicsWorldSingleton

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
RaycastInput input = new RaycastInput
{
Start = ray.origin,
End = ray.origin + ray.direction * 100f,
Filter = CollisionFilter.Default
};
ref var physicsWorld =
ref SystemAPI.GetSingletonRW<PhysicsWorldSingleton>().ValueRW;
if (physicsWorld.CollisionWorld.CastRay(input, out RaycastHit hit))
{
Debug.Log($"击中实体: {hit.Entity.Index}, 位置: {hit.Position}");
if (SystemAPI.HasComponent<PhysicsCollider>(hit.Entity))
{
var collider = SystemAPI.GetComponent<PhysicsCollider>(hit.Entity);
Debug.Log($"Collider 类型: {collider.Value.Value.Type}");
}
}

Job中:
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
public void OnUpdate(ref SystemState state)
{
var ecb =
SystemAPI
.GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>()
.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter();
var physicsWorld = SystemAPI.GetSingleton<PhysicsWorldSingleton>();
//var collisionWorld = physicsWorld.CollisionWorld;
new BulletMoveJob()
{
DeltaTime = SystemAPI.Time.DeltaTime,
ECB = ecb,
PhysicsWorld = physicsWorld
}.ScheduleParallel();
}
[BurstCompile]
public partial struct BulletMoveJob : IJobEntity
{
[Unity.Collections.ReadOnly]
public PhysicsWorldSingleton PhysicsWorld;
void Execute([EntityIndexInQuery] int sortKey, ref LocalTransform transform,
ref BulletMoveComponent moveComponent,
ref BulletHitComponent hitComponent, Entity entity){
var rayInput = new RaycastInput
{
Start = start,
End = end,
Filter = CollisionFilter.Default
};


if (PhysicsWorld.CastRay(rayInput, out RaycastHit hit))
{
// 命中点
float3 hitPos = hit.Position;
// hit.SurfaceNormal
}
}
}

其他形状检测

同理,类似CastRay

1
2
3
4
PhysicsWorld.SphereCast();
PhysicsWorld.SphereCastAll();
PhysicsWorld.CapsuleCast();
PhysicsWorld.BoxCast();