值 | 要调用的委托。 |
订阅此事件以读取物理模拟步骤期间发生的所有碰撞。
此事件的每个订阅者都会使用物理场景和 ContactPairHeader 的原生数组进行调用。每个 ContactPairHeader 包含一个 ContactPair 数组,每个 ContactPair 包含一个 ContactPairPoint 数组。
您可以使用此事件来加速碰撞处理,因为它比 MonoBehaviour.OnCollisionEnter 和其他消息快得多。您还可以使用此事件来调度使用提供的原生数组的作业。从此事件调度的作业必须在下一个 Physics.Simulate、PhysicsScene.Simulate 或 PhysicsScene.RunSimulationStages 与 RunSimulation 阶段调用之前完成。默认情况下,完成这些作业的理想位置是 MonoBehaviour.FixedUpdate。
备注
true
或附加具有 OnCollisionStay 方法的 MonoBehaviour 脚本。using System.Collections.Generic; using Unity.Collections; using Unity.Jobs; using UnityEngine;
public class BounceScipt : MonoBehaviour { [SerializeField] private float m_ImpulseMultiplier = 5f;
private struct JobResultStruct { public int thisInstanceID; public int otherInstanceID; public Vector3 averageNormal; }
private NativeArray<JobResultStruct> m_ResultsArray; private int m_Count; private JobHandle m_JobHandle;
private readonly Dictionary<int, Rigidbody> m_RigidbodyMapping = new Dictionary<int, Rigidbody>();
private void OnEnable() { m_ResultsArray = new NativeArray<JobResultStruct>(16, Allocator.Persistent);
Physics.ContactEvent += Physics_ContactEvent;
var allRBs = GameObject.FindObjectsOfType<Rigidbody>(); foreach (var rb in allRBs) m_RigidbodyMapping.Add(rb.GetInstanceID(), rb); }
private void OnDisable() { m_JobHandle.Complete(); m_ResultsArray.Dispose();
Physics.ContactEvent -= Physics_ContactEvent;
m_RigidbodyMapping.Clear(); }
private void FixedUpdate() { m_JobHandle.Complete(); // The buffer is valid until the next Physics.Simulate() call. Be it internal or manual
// Do something with the contact data. // E.g. Add force based on the average contact normal for that body for (int i = 0; i < m_Count; i++) { var thisInstanceID = m_ResultsArray[i].thisInstanceID; var otherInstanceID = m_ResultsArray[i].otherInstanceID;
var rb0 = thisInstanceID != 0 ? m_RigidbodyMapping[thisInstanceID] : null; var rb1 = otherInstanceID != 0 ? m_RigidbodyMapping[otherInstanceID] : null;
if (rb0) rb0.AddForce(m_ResultsArray[i].averageNormal * m_ImpulseMultiplier, ForceMode.Impulse); if (rb1) rb1.AddForce(m_ResultsArray[i].averageNormal * -m_ImpulseMultiplier, ForceMode.Impulse); } }
private void Physics_ContactEvent(PhysicsScene scene, NativeArray<ContactPairHeader>.ReadOnly pairHeaders) { int n = pairHeaders.Length;
if (m_ResultsArray.Length < n) { m_ResultsArray.Dispose(); m_ResultsArray = new NativeArray<JobResultStruct>(Mathf.NextPowerOfTwo(n), Allocator.Persistent); }
m_Count = n;
AddForceJob job = new AddForceJob() { pairHeaders = pairHeaders, resultsArray = m_ResultsArray };
m_JobHandle = job.Schedule(n, 256); }
private struct AddForceJob : IJobParallelFor { [ReadOnly] public NativeArray<ContactPairHeader>.ReadOnly pairHeaders;
public NativeArray<JobResultStruct> resultsArray;
public void Execute(int index) { Vector3 averageNormal = Vector3.zero; int count = 0;
for (int j = 0; j < pairHeaders[index].pairCount; j++) { ref readonly var pair = ref pairHeaders[index].GetContactPair(j);
if (pair.IsCollisionExit) continue;
for (int k = 0; k < pair.ContactCount; k++) { ref readonly var contact = ref pair.GetContactPoint(k); averageNormal += contact.Normal; }
count += pair.ContactCount; }
if (count != 0) averageNormal /= (float)count;
JobResultStruct result = new JobResultStruct() { thisInstanceID = pairHeaders[index].bodyInstanceID, otherInstanceID = pairHeaders[index].otherBodyInstanceID, averageNormal = averageNormal };
resultsArray[index] = result; } } }
此脚本读取缓冲区中的所有碰撞,并计算每个 ContactPairHeader 的平均法线。然后根据结果应用力。