Unity 6.3
0 онлайн 83 гостей 3 в системе
Вход

Physics.ContactEvent

Параметры

Параметр Описание
значение Представитель для вызова.

Описание

Подпишитесь на это событие, чтобы прочитать все столкновения, которые произошли во время этапа моделирования физики.

Каждый подписчик на это событие вызывает физическую сцену и собственный массив ContactPairHeaderс. Каждый ContactPairHeader содержит массив ContactPairс и каждая ContactPair содержит массив ContactPairPoints.

Вы можете использовать это событие, чтобы ускорить обработку контактов, так как это намного быстрее, чем MonoBehaviour.OnCollisionEnter Это событие также можно использовать для планирования заданий, использующих предоставленный основной массив. Задания, запланированные с помощью этого события, должны быть выполнены до следующего Physics.Simulate, PhysicsScene.Simulate, или PhysicsScene.RunSimulationStages с SimulationStage.RunSimulation по умолчанию хорошим местом для выполнения этих работ является MonoBehaviour.FixedUpdate.

Примечания:

  • В этом событии сообщается только о столкновениях Collider, и в предоставленном буфере не появляется никаких событий триггера.
  • Все данные в предоставленном буфере доступны только для чтения. Запись не разрешена.
  • Событие вызывается после синхронизации преобразования.
  • Чтобы получать контакты от Collider, установите свойство Collider.providesContacts на true или подключите скрипт MonoBehaviour с методом OnCollisionStay.
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. Затем применяет силу на основе результата.