콜백
소개
Quantum의 충돌 및 트리거 콜백은 시스템 시그널을 통해 처리됩니다. 특정 엔티티에 대해 콜백을 실행하는 데 필요한 두 가지 단계는 다음과 같습니다.
- 엔티티에 대한 특정 유형의 콜백을 사용하도록 설정합니다.
- 해당 시그널을 구현합니다.
콜백을 활성화하는 방법과 코드를 작성하는 방법을 배우기 전에 먼저 다양한 콜백 유형과 콜백이 실행되는 원인을 이해하는 것이 중요합니다.
콜백 유형
충돌 및 트리거는 물리적 엔진의 충돌 감지 단계에서 생성된 2-엔티티 또는 엔티티-스태틱 쌍으로 시작됩니다. 엔티티에 연결된 물리적 컴포넌트의 조합과 트리거 속성 값(true/false)에 따라 아래 표에는 실행될 콜백 유형이 나와 있습니다.
엔티티 vs 엔티티
충돌 쌍이 두 개의 동적 엔티티 A 및 B로 구성된 경우, 다음과 같은 콜백이 실행될 수 있습니다(사용되는 컴포넌트 및 트리거 속성에 따라 다름).
컴포넌트 (엔티티 A 및 B) | PhysicsCollider 만 | PhysicsCollider (Trigger on) | PhysicsCollider + PhysicsBody |
---|---|---|---|
PhysicsCollider 만 | None | OnTrigger | OnCollision |
PhysicsCollider (Trigger on) | OnTrigger | None | OnTrigger |
PhysicsCollider + PhysicsBody | OnCollision | OnTrigger | OnCollision |
엔티티 vs 정적 콜라이더
콜라이더 페어가 동적 객체와 정적 충돌기로 구성될 때 가능한 조합은 다음과 같습니다.
컴포넌트 (엔티티 및 정적) | 정적 콜라이더 | 정적 콜라이더 (Trigger on) |
---|---|---|
PhysicsCollider 만 | None | OnTrigger |
PhysicsCollider (Trigger on) | OnTrigger | None |
PhysicsCollider + PhysicsBody | OnCollision | OnTrigger |
엔티티에 콜백 활성화하기
각 엔티티에 대해 활성화되는 콜백 유형(및 다른 콜라이더 종류)을 제어할 수 있습니다. 이 작업은 유니티의 엔티티 프로토타입을 통해 수행되거나 물리 엔진 API의 SetCallbacks 기능을 통해 코드로 수행되며, 이 기능은 엔티티와 충돌 콜백 플래그를 가져옵니다.
엔티티 프로토타입을 통해
물리 콜백은 PhysicsCollider(2D/3D)가 있는 모든 엔티티 프로토타입에서 설정할 수 있습니다.
각 엔티티는 여러 개의 콜백을 가질 수 있습니다.
주의: 엔티티 프로토타입에서만 콜백을 활성화하면 특정 엔티티에 대한 콜백이 설정됩니다. 여전히 코드에 해당하는 시그널을 구현해야 합니다. 자세한 내용은 아래의 콜백 시그널 섹션을 참조하십시오.
코드를 통해
콜백 플래그는 비트 마스크이며 다음에 예시된 것처럼 비트 단위 작업을 사용하여 여러 콜백 유형을 지정할 수 있습니다.
다음 코드에서는 다른 동적 엔티티에 대한 전체 OnTrigger 콜백 집합을 활성화합니다(OnDynamicTrigger, OnDynamicTrigger OnDynamicTriggerEnter 및 OnDynamicTriggerExit).
C#
CallbackFlags flags = CallbackFlags.OnDynamicTrigger;
flags |= CallbackFlags.OnDynamicTriggerEnter;
flags |= CallbackFlags.OnDynamicTriggerExit;
// for 2D
f.Physics2D.SetCallbacks(entity, flags);
// for 3D
f.Physics3D.SetCallbacks(entity, flags);
다음은 기본 콜백 플래그입니다(물리 엔진에 의해 충돌이 더 이상 감지되지 않을 때까지 해당하는 신호는 모든 틱으로 호출됩니다).
- CallbackFlags.OnDynamicCollision
- CallbackFlags.OnDynamicTrigger
- CallbackFlags.OnStaticTrigger
다음은 해당하는 Enter/Exit 콜백(위 항목과 독립적으로 활성화할 수 있음)입니다:
CallbackFlags.OnDynamicCollisionEnter
CallbackFlags.OnDynamicCollisionExit
CallbackFlags.OnDynamicTriggerEnter
CallbackFlags.OnDynamicTriggerExit
CallbackFlags.OnStaticCollisionEnter
CallbackFlags.OnStaticCollisionExit
CallbackFlags.OnStaticTriggerEnter
CallbackFlags.OnStaticTriggerExit
엔티티 별로 콜백을 활성화해야 하는 것은 기본 시뮬레이션을 최대한 빠르게 수행하기 위한 의도적인 설계 선택입니다. 또한 기본 콜백에 비해 Enter/Exit 콜백이 약간 더 많은 메모리 및 CPU 사용량이 발생하므로 가능한 한 적은 시뮬레이션을 위해 이러한 콜백을 피해야 합니다.
콜백 시그널
주의: 엔티티 대 엔티티 및 엔티티 대 정적 쌍에 대한 충돌 및 트리거 콜백은 통합 신호 API로 그룹화됩니다.
다음은 2D 물리 시그널입니다:
C#
namespace Quantum {
public interface ISignalOnCollision2D : ISignal {
void OnCollision2D(Frame f, CollisionInfo2D info);
}
public interface ISignalOnCollisionEnter2D : ISignal {
void OnCollisionEnter2D(Frame f, CollisionInfo2D info);
}
public interface ISignalOnCollisionExit2D : ISignal {
void OnCollisionExit2D(Frame f, ExitInfo2D info);
}
public interface ISignalOnTrigger2D : ISignal {
void OnTrigger2D(Frame f, TriggerInfo2D info);
}
public interface ISignalOnTriggerEnter2D : ISignal {
void OnTriggerEnter2D(Frame f, TriggerInfo2D info);
}
public interface ISignalOnTriggerExit2D : ISignal {
void OnTriggerExit2D(Frame f, ExitInfo2D info);
}
}
그리고 3D 물리 시그널:
C#
namespace Quantum {
public interface ISignalOnCollision3D : ISignal {
void OnCollision3D(Frame f, CollisionInfo3D info);
}
public interface ISignalOnCollisionEnter3D : ISignal {
void OnCollisionEnter3D(Frame f, CollisionInfo3D info);
}
public interface ISignalOnCollisionExit3D : ISignal {
void OnCollisionExit3D(Frame f, ExitInfo3D info);
}
public interface ISignalOnTrigger3D : ISignal {
void OnTrigger3D(Frame f, TriggerInfo3D info);
}
public interface ISignalOnTriggerEnter3D : ISignal {
void OnTriggerEnter3D(Frame f, TriggerInfo3D info);
}
public interface ISignalOnTriggerExit3D : ISignal {
void OnTriggerExit3D(Frame f, ExitInfo3D info);
}
}
콜백을 수신하려면 하나 이상의 활성 시스템에서 해당 시그널 인터페이스를 구현해야 합니다(비활성화된 시스템은 해당 시스템에서 어떠한 시그널도 실행되지 않습니다).
C#
public class PickUpSystem : SystemSignalsOnly, ISignalOnTriggerEnter3D
{
public void OnTriggerEnter3D(Frame f, TriggerInfo3D info)
{
if (!f.Has<PickUpSlot>(info.Entity)) return;
if (!f.Has<PlayerID>(info.Other)) return;
var item = f.Get<PickUpSlot>(info.Entity).Item;
var itemAsset = f.FindAsset<ItemBase>(item.Id);
itemAsset.OnPickUp(f, info.Other, itemAsset);
f.Destroy(info.Entity);
}
}
위의 코드는 시그널을 구현할 때 사용할 수 있는 또 다른 최적화의 예입니다. SystemSignalsOnly에서 상속하여 시스템이 빈 업데이트 기능을 예약할 필요가 없는 상태에서 신호를 처리할 수 있도록 합니다(필요 없이 작업 시스템 오버헤드가 발생합니다).
CollisionInfo
OnCollisionEnter
및 OnCollision
시그널은 CollisionInfo
구조체를 통해 충돌 주체에 대한 추가 정보를 제공합니다.
컨택 포인트
컨택 포인트의 정보는 ContactPoints
API를 통해 접근할 수 있습니다.
Average
: 모든 컨택 포인트의 평균Count
: 컨택 포인트의 개수Length
: 모든 컨택 포인트의 버퍼First
: 첫 번째 삼각형의 컨택 포인트 리턴
First
는 접점이 하나뿐이고 평균이 아니어도 되는 경우 계산을 저장하는 데 도움이 될 수 있습니다.
ContactPoints
도 반복기입니다. 메시와 충돌할 때 모든 삼각형 충돌 접점을 반복하는 데 사용할 수 있습니다.
C#
while(info.ContactPoints.Next(out var cp)) {
Draw.Sphere(cp, radius);
}
Sphere-Triangle 충돌은 단일 접점을 가지므로 Average
및 ContactPoints[0]
는 모두 동일한 접점을 반환합니다. 다른 유형의 충돌은 더 많은 접점을 가질 수 있습니다.
메시 충돌
엔티티가 메시와 충돌할 때 Count
와 Average
는 특정 메시에 속하는 모든 삼각형 충돌을 고려합니다.
엔티티가 충돌하는 각 삼각형에 대해 콜백을 받는 대신 이러한 충돌 삼각형은 단일 CollisionInfo
구조체로 그룹화됩니다.
메시 충돌의 경우 info.ContactNormal
및 info.Penetration
은 해당 메시의 삼각형 충돌의 평균 값을 반환합니다. 이 값은 info.MeshTriangleCollisions.AverageNormal
및 info.MeshTriangleCollisions.AveragePenetration
을 통해 동일한 데이터를 사용할 수 있습니다.
평균 정규 분포 외에도 각 삼각형 충돌을 반복하고 삼각형 데이터 자체와 같은 특정 정보에 접근할 수 있습니다. MeshTriangleCollisions
도 반복기이며, 각 삼각형의 충돌 데이터를 반복하고 메시별 충돌 데이터를 검색하는 데 사용할 수 있습니다.
C#
if (info.IsMeshCollision) {
while(info.MeshTriangleCollisions.Next(out var triCollision)) {
Draw.Ray(triCollision.Triangle->Center, triCollision.ContactNormal * triCollision.Penetration);
}
}
상세 정보 및 FAQ
충돌 콜백 작업 시 유용한 정보:
- 두 엔티티의 콜백 집합이 동일한 경우 콜백은 연결된 엔티티당 한 번씩 두 번 호출됩니다. 두 호출 사이의 유일한 차이점은 스왑 될 엔티티 및 기타 의 값입니다.
- 트리거 및 정적 충돌기와의 충돌은 정규/점/침투 데이터를 계산하지 않습니다.
- 유니티의 정적 충돌기는 "에셋" 필드에 Quantum DB 자산을 연결할 수 있습니다. 원하는 사용자 지정 자산 유형에 따라 데이터를 캐스팅하는 것은 정적 충돌 콜백에 임의 데이터를 추가하는 좋은 방법입니다.