由于官方暂无文档,且为临时版本,随时可能更新,所以本文档内容皆为胡编乱造,造谣生事,事在人为,为所欲为,为所欲为,为所欲为,为所欲为,为所欲为
1. package环境
- Entities
- Hybrid.Renderer
- Burst
- Collections
- Jobs
- Mathematics
- Unity Physics
2. GameObject转Entity
添加convertToEntity
,原GameObject中自带的collider
和rigidbody
会自动转换为PhysicsShape
和PhysicsBody
,但仍然建议手动移除后重新添加新的Physics脚本
3. Physics Debug和 物理引擎设置
新建一个空GO,并添加脚本: converToEntity
,physicsStep
,physicsDebugDisplay
UnityPhysics貌似存在些计算上的bug,如: 两个垂直放置的静止的GO,会发生位移(HavokPhysics中无该问题):
4. 鼠标点击与碰撞检测
碰撞检测关键类:CollisionWorld
namespace Unity.Physics
{
public struct CollisionWorld : ICollidable, IDisposable, ICloneable
{
public CollisionWorld(int numBodies);
public NativeSlice<RigidBody> Bodies { get; }
public int NumBodies { get; set; }
public float CollisionTolerance { get; }
public Aabb CalculateAabb();
public Aabb CalculateAabb(RigidTransform transform);
public bool CalculateDistance(PointDistanceInput input);
public bool CalculateDistance<T>(ColliderDistanceInput input, ref T collector) where T : struct, ICollector<DistanceHit>;
public bool CalculateDistance(ColliderDistanceInput input, ref NativeList<DistanceHit> allHits);
public bool CalculateDistance(ColliderDistanceInput input, out DistanceHit closestHit);
public bool CalculateDistance(ColliderDistanceInput input);
public bool CalculateDistance<T>(PointDistanceInput input, ref T collector) where T : struct, ICollector<DistanceHit>;
public bool CalculateDistance(PointDistanceInput input, ref NativeList<DistanceHit> allHits);
public bool CalculateDistance(PointDistanceInput input, out DistanceHit closestHit);
public bool CastCollider(ColliderCastInput input, ref NativeList<ColliderCastHit> allHits);
public bool CastCollider(ColliderCastInput input, out ColliderCastHit closestHit);
public bool CastCollider(ColliderCastInput input);
public bool CastCollider<T>(ColliderCastInput input, ref T collector) where T : struct, ICollector<ColliderCastHit>;
public bool CastRay<T>(RaycastInput input, ref T collector) where T : struct, ICollector<RaycastHit>;
public bool CastRay(RaycastInput input, ref NativeList<RaycastHit> allHits);
public bool CastRay(RaycastInput input, out RaycastHit closestHit);
public bool CastRay(RaycastInput input);
public object Clone();
public void Dispose();
public bool OverlapAabb(OverlapAabbInput input, ref NativeList<int> allHits);
public JobHandle ScheduleUpdateDynamicLayer(ref PhysicsWorld world, float timeStep, float3 gravity, int numThreadsHint, JobHandle inputDeps);
}
}
4.1 准备工作
Physics Category Names
physics检测与filter设置:
- 创建: Create -> DOTS -> Physics -> Physics Category Names
- 代码相关:
hitFilter记录
/// <summary>
/// hitFilter记录
/// </summary>
public struct MousePick : IComponentData
{
/// <summary>
/// 一般为 int.maxValue
/// </summary>
public int belongTo;
/// <summary>
/// 碰撞过滤
/// </summary>
public int filterHit;
public int filterPlane;
}
[RequiresEntityConversion]
public class CMousePick : MonoBehaviour, IConvertGameObjectToEntity
{
public bool ignoreTrigger = false;
//belongTo取最大
//public int belongTo = 0;
public int filterHit = 0;
public int filterPlane = 0;
public PhysicsCategoryNames categoryNames;
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
dstManager.AddComponentData(entity, new MousePick {
belongTo = int.MaxValue,
filterHit = filterHit,
filterPlane = filterPlane,
});
}
}
CMousePickEditor代码
: 注意新建一个名为 editor
的文件夹
using UnityEditor;
[CustomEditor(typeof(CMousePick))]
public class CMousePickEditor : Editor
{
CMousePick Instance;
string[] names = new string[32];
private void OnEnable()
{
Instance = target as CMousePick;
GetNames();
}
private void GetNames()
{
if (Instance.categoryNames)
{
for (int i = 0; i < Instance.categoryNames.CategoryNames.Count; i++)
{
names[i] = (Instance.categoryNames.CategoryNames[i] != "") ? Instance.categoryNames.CategoryNames[i] : "(empty) " + i.ToString();
}
}
else
{
for (int i = 0; i < names.Length; i++)
{
names[i] = "";
}
}
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
EditorGUI.BeginChangeCheck();
{
if (Instance.categoryNames && names[0] != "")
{
//Instance.belongTo =EditorGUILayout.MaskField("belongTo", Instance.belongTo, names);
Instance.filterHit = EditorGUILayout.MaskField("射线点击过滤", Instance.filterHit, names);
Instance.filterPlane = EditorGUILayout.MaskField("Plane过滤", Instance.filterPlane, names);
}
else
{
EditorGUILayout.HelpBox("尚未导入物理碰撞种类名", MessageType.Error);
GetNames();
}
}
if (EditorGUI.EndChangeCheck())
{
EditorUtility.SetDirty(Instance);
}
}
}
- 创建Entity: 场景中新建一个空物体,添加
convertToEntity
和CMousePick
,并设置 filter
最终效果:
4.2 CastRay
射线检测
官方实例使用了IJob
进行射线检测,但是我不想用,所以:
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Physics;
using Unity.Physics.Systems;
using RaycastHit = Unity.Physics.RaycastHit;
namespace PhysicsCollisionUtiltity
{
public class PhysicsUtiltity
{
static BuildPhysicsWorld m_BuildPhysicsWorldSystem;
/// <summary>
/// 获取过滤的同时完成Job
/// </summary>
/// <param name="jobSystem"></param>
/// <param name="inputDependencies"></param>
/// <param name="layerMask"></param>
/// <returns></returns>
static CollisionFilter GetFilter( ref JobHandle inputDependencies,int layerMask)
{
var filter = new CollisionFilter
{
BelongsTo = CollisionFilter.Default.BelongsTo,
CollidesWith = (uint)layerMask,
GroupIndex = CollisionFilter.Default.GroupIndex,
};
if (m_BuildPhysicsWorldSystem == null)
{
m_BuildPhysicsWorldSystem = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<BuildPhysicsWorld>();
}
///等待BuildPhysicsWorldSystem 和 依赖项完成后才获取射线数据
inputDependencies = JobHandle.CombineDependencies(inputDependencies, m_BuildPhysicsWorldSystem.FinalJobHandle);
inputDependencies.Complete();
return filter;
}
public static bool Raycast(ref JobHandle inputDependencies, float3 start, float3 end,
int layerMask = int.MaxValue)
{
var RayInput = new RaycastInput
{
Start = start,
End = end,
Filter = GetFilter(ref inputDependencies, layerMask),
};
return m_BuildPhysicsWorldSystem.PhysicsWorld.CollisionWorld.CastRay(RayInput);
}
/// <summary>
///
/// </summary>
/// <param name="jobSystem">用于EntityPhysics世界获取</param>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="hitOutData"></param>
/// <param name="layerMask"></param>
/// <returns></returns>
public static bool Raycast(ref JobHandle inputDependencies, float3 start,float3 end,
out RaycastHit hitOutData,int layerMask = int.MaxValue)
{
var RayInput = new RaycastInput
{
Start = start,
End = end,
Filter = GetFilter(ref inputDependencies, layerMask),
};
return m_BuildPhysicsWorldSystem.PhysicsWorld.CollisionWorld.CastRay(RayInput, out hitOutData);
}
public static bool Raycast( ref JobHandle inputDependencies, UnityEngine.Ray ray, float distance,
out RaycastHit hitOutData, int layerMask = int.MaxValue)
{
var RayInput = new RaycastInput
{
Start = ray.origin,
End = ray.origin + ray.direction * distance,
Filter = GetFilter( ref inputDependencies, layerMask),
};
return m_BuildPhysicsWorldSystem.PhysicsWorld.CollisionWorld.CastRay(RayInput, out hitOutData);
}
public static bool RaycastAll( ref JobHandle inputDependencies, UnityEngine.Ray ray, float distance,
ref NativeList<RaycastHit> hits, int layerMask = int.MaxValue)
{
var RayInput = new RaycastInput
{
Start = ray.origin,
End = ray.origin + ray.direction * distance,
Filter = GetFilter( ref inputDependencies, layerMask),
};
return m_BuildPhysicsWorldSystem.PhysicsWorld.CollisionWorld.CastRay(RayInput, ref hits);
}
public static bool RaycastAll( ref JobHandle inputDependencies, float3 start, float3 end,
ref NativeList<RaycastHit> hits, int layerMask = int.MaxValue)
{
var RayInput = new RaycastInput
{
Start = start,
End = end,
Filter = GetFilter( ref inputDependencies, layerMask),
};
return m_BuildPhysicsWorldSystem.PhysicsWorld.CollisionWorld.CastRay(RayInput, ref hits);
}
}
}
调用: 实现鼠标点击 entity 并在 plane 上移动
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Physics.Systems;
using PhysicsCollisionUtiltity;
using UnityEngine;
using RaycastHit = Unity.Physics.RaycastHit;
using Unity.Mathematics;
using Unity.Transforms;
public struct EntityDrag
{
public Entity Entity;
public bool Dragging;
public float3 heightFromPlane;
public float3 positionHitPlane;
}
/// <summary>
/// 注意system的 Update 先后顺序
/// 注意该事件只处理射线投射, 如果进行physics数据修改,修改结果将不会生效
/// </summary>
[UpdateAfter(typeof(BuildPhysicsWorld)), UpdateBefore(typeof(EndFramePhysicsSystem))]
public class CMouseClickSystem : JobComponentSystem
{
BuildPhysicsWorld m_BuildPhysicsWorldSystem;
EntityQuery m_MouseGroup;
public EntityDrag entityDragging;
public JobHandle? jobHandleDepend;
///获取filter
public int filterHit, filterPlane;
protected override void OnCreate()
{
base.OnCreate();
m_BuildPhysicsWorldSystem = World.GetOrCreateSystem<BuildPhysicsWorld>();
m_MouseGroup = GetEntityQuery(new EntityQueryDesc
{
All = new ComponentType[] { typeof(MousePick) }
});
entityDragging = new EntityDrag
{
Dragging = false
};
}
/// <summary>
/// 移除处理
/// </summary>
protected override void OnDestroy()
{
base.OnDestroy();
entityDragging.Dragging = false;
}
protected override JobHandle OnUpdate(JobHandle inputDependencies)
{
if (m_MouseGroup.CalculateEntityCount() == 0)
{
return inputDependencies;
}
///鼠标按下
if (Input.GetMouseButtonDown(0))
{
Vector2 mousePosition = Input.mousePosition;
UnityEngine.Ray unityRay = Camera.main.ScreenPointToRay(mousePosition);
///获取filter
using (var pickFilter = m_MouseGroup.ToComponentDataArray<MousePick>(Allocator.TempJob))
{
filterHit = pickFilter[0].filterHit;
filterPlane = pickFilter[0].filterPlane;
}
///rayCast
if (PhysicsUtiltity.Raycast( ref inputDependencies, unityRay, 100, out RaycastHit hit, filterHit))
{
entityDragging.Dragging = true;
entityDragging.Entity = m_BuildPhysicsWorldSystem.PhysicsWorld.Bodies[hit.RigidBodyIndex].Entity;
///计算距离地面高度
///向下发射射线
float3 positionEntity = EntityManager.GetComponentData<Translation>(entityDragging.Entity).Value;
if (PhysicsUtiltity.Raycast(ref inputDependencies, positionEntity, positionEntity - math.up() * 10,
out RaycastHit hitPlane, filterPlane))
{
entityDragging.heightFromPlane = positionEntity - hitPlane.Position;
}
//Debug.Log(entityDragging.heightFromPlane);
}
}
if (Input.GetMouseButtonUp(0))
{
entityDragging.Dragging = false;
}
///平面移动
if (entityDragging.Dragging)
{
Vector2 mousePosition = Input.mousePosition;
UnityEngine.Ray unityRay = Camera.main.ScreenPointToRay(mousePosition);
if (PhysicsUtiltity.Raycast(ref inputDependencies, unityRay, 100, out RaycastHit hit, filterPlane))
{
entityDragging.positionHitPlane = hit.Position;
}
}
return inputDependencies;
}
}
/// <summary>
/// 数据修改
/// </summary>
[UpdateBefore(typeof(BuildPhysicsWorld))]
public class MouseSpringSystem : JobComponentSystem
{
CMouseClickSystem mouseClickSystem;
// EntityQuery m_MouseGroup;
protected override void OnCreate()
{
base.OnCreate();
mouseClickSystem = World.GetOrCreateSystem<CMouseClickSystem>();
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
if (mouseClickSystem.jobHandleDepend != null)
{
JobHandle.CombineDependencies(inputDeps, mouseClickSystem.jobHandleDepend.Value).Complete();
}
if (mouseClickSystem.entityDragging.Dragging)
{
ComponentDataFromEntity<Translation> Positions = GetComponentDataFromEntity<Translation>();
var from = Positions[mouseClickSystem.entityDragging.Entity].Value;
var to = mouseClickSystem.entityDragging.heightFromPlane + mouseClickSystem.entityDragging.positionHitPlane;
Positions[mouseClickSystem.entityDragging.Entity] = new Translation
{
Value = //Vector3.MoveTowards(from, to, 20 * Time.DeltaTime)
mouseClickSystem.entityDragging.positionHitPlane + mouseClickSystem.entityDragging.heightFromPlane
};
//EntityManager.SetComponentData(mouseClickSystem.entityDragging.Entity,
// new Translation
// {
// Value = mouseClickSystem.entityDragging.positionHitPlane
// + mouseClickSystem.entityDragging.heightFromPlane
// });
}
return inputDeps;
}
}
注意:
- 射线投射检测 与 physics数据修改 应分为两个system执行,因为
在UpdateAfter(typeof(BuildPhysicsWorld))后执行的transform修改将不能生效
system | 执行顺序设置 |
---|---|
RayCast | [UpdateAfter(typeof(BuildPhysicsWorld)), UpdateBefore(typeof(EndFramePhysicsSystem))] |
Move | [UpdateBefore(typeof(BuildPhysicsWorld))] |
- 暂未发现 OnTriggerEnter 等事件,目前只能手动判断,判断后在另一个system中计算并处理
来源:CSDN
作者:DearMyDear
链接:https://blog.csdn.net/qq_26022539/article/details/103650084