개요
개요
Physics 애드온은 Rigidbody 및 Rigidbody2D 컴포넌트의 클라이언트 예측 및 동기화에 필요한 컴포넌트를 포함합니다.
NetworkRigidbody3D
- 상태 권한에서 다른 피어로 Rigidbody 상태를 동기화합니다.NetworkRigidbody2D
- 상태 권한에서 다른 피어로 Rigidbody 2D 상태를 동기화합니다.RunnerPhysicsSimulate3D
- NetworkRunner GameObject에 추가할 수 있는 옵션 컴포넌트. Fusion이 Physics 시뮬레이션을 처리할 수 있도록 합니다.RunnerPhysicsSimulate2D
- NetworkRunner GameObject를 추가할 수 있는 옵션 컴포넌트로 Fusion이 Physics2D 시뮬레이션을 처리할 수 있습니다.
사용법
Network Rigidbody 컴포넌트를 사용하려면 다음 단계를 수행합니다:
- 강체 프리팹이나 씬 객체에
NetworkRigidbody3D
(또는 2D의 경우NetworkRigidbody2D
)와NetworkObject
를 추가합니다. 이 컴포넌트는 강체 상태를 상태 권한에서 다른 피어로 복제합니다. 또한 클라이언트 예측 재시뮬레이션을 위해 강체의 리셋과 조정을 처리합니다. NetworkRunner
프리팹에RunnerSimulatePhysics3D
(또는 해당하는 경우 2D)를 추가합니다. 이 컴포넌트는 유니티의 Physics.Simulate() 호출을 이어받습니다.- 모든 시뮬레이션/컨트롤러 코드가 FixedUpdateNetwork() 내부에서 실행되는지 확인합니다.
Fusion 1에서 Fusion 2로 마이그레이션
IBeforePhysicsStep
및IAfterPhysicsStep
콜백은 제거되었고RunnerSimulatePhysics
으로 대체할 수 있습니다. 아래의 콜백을 참고하세요.
확장 / 변경
NetworkRigidbody
및 RunnerSimulatePhysics
컴포넌트는 대부분의 사용 사례에서 작동하도록 설계되었습니다. 그러나 프로젝트별 요구 사항에 맞게 수정할 수 있습니다. 이러한 클래스의 일부 멤버들은 가상화되어 있으므로 무시할 수 있습니다. 그러나 대부분의 경우 이러한 컴포넌트를 가이드로 사용하여 자신만의 클래스를 만들고 싶거나 직접 수정할 수도 있습니다. Fusion 코어의 내부 멤버는 이러한 컴포넌트에 의존하지 않으므로(일부 샘플 및 데모는 가능하지만) 적합하다고 판단되는 대로 수정할 수 있습니다.
NetworkRigidbody2D / NetworkRigidbody3D
NetworkRigidbody3D
및 NetworkRigidbody2D
는 NetworkTRSP
클래스에서 상속됐고, 모든 AOI 처리를 상속합니다. 관심 영역에 대한 자세한 내용은 본 설명서의 Network TRSP 섹션을 참조하십시오.
스케일 동기화
활성화되었을 때, transform.localScale
이 동기화됩니다.
부모 동기화
활성화하면 transform.parent
가 동기화됩니다. 부모 Rigidbody가 있는 Rigidbody는 운동학적으로 설정해야 합니다. 부모 Rigidbody는 자동으로 AreaOfInterest 객체를 부모 네트워크 객체로 설정합니다.
몇 가지 주의사항이 있습니다:
- 부모 변환에는 반드시
NetworkBehaviour
컴포넌트가 있어야 합니다.NetworkBehaviourId
를 사용하여 부모를 찾는 방법입니다. NetworkRigidbody
는 네트워크 객체의 루트에 있어야 합니다(어쨌든 일반적으로 해당됩니다).- 부모 변환은 Network Object의 자식 변환일 수 있습니다. 예를 들어 플레이어의 손 등입니다.
내삽 대상
Render()
중에 보간을 위해 이동되는 변환입니다. 일반적으로 충돌기를 포함하지 않는 강체(Rigidbody)의 자식 변환입니다.
null일 때 Network Rigidbody의 루트는 보간을 위해 이동되고, 시뮬레이션 루프가 시작될 때 틱 정확한 위치로 돌아갑니다. InterpolationTarget
값은 코드를 통해 런타임에 변경될 수 있습니다.
루트가 아닌 보간 대상을 사용하면 보간을 통해 객체에 대한 물리적 캐싱이 깨지지 않는다는 이점이 있습니다. 그러나 이렇게 하면 모든 하위 Rigidbody에 대해 SyncScale이 유효하지 않습니다.
Interpolation Target을 null로 두는 것이 좋습니다. 원하지 않는 강체 행동(마찰/스택과 관련하여)이 발생하는 경우에만 보간 대상을 null로 두는 것이 좋습니다.
보간 대상이 필요한 경우:
MovePosition()
을 사용하여 운동학적 강체를 이동합니다. 보간 대상 보간은 사용하지 않고 transform.position과 rotation을 설정하여 수행합니다. 그러나 이와 같이 변환을 직접 변경하면 변환이 수정된 후에 이루어지더라도 RB에 대한 모든MovePosition()
호출이 재정의됩니다.- 물리학은 보간의 영향을 받지 않아야 합니다. 변환을 직접 이동하여 보간하면 강체의 정적 마찰 및 수면이 깨지는 등의 부작용이 있습니다. Render Sleep Thresholds는 이를 완화하지만, 간섭을 허용할 수 없는 경우도 있을 수 있습니다.
내삽 대상을 사용하는 경우, 충돌기가 없는지 확인하십시오. 충돌기를 이동시키면 강체가 더러워지기 때문입니다. 모든 코스메틱 효과는 이 보간 대상에 포함되어야 합니다.
노트: 스케일과 페어런팅을 모두 사용하는 경우 보간 대상을 사용해도 정확한 결과를 얻을 수 없습니다. GameObject 스케일은 부모 스케일의 영향을 받아 코드를 통한 복제가 거의 불가능하므로 정확한 스케일 결과를 위해서는 InterpolationTarget
을 null로 남겨두는 것이 좋습니다.
노트: 일반적인 실수는 카메라가 보간 대상을 따르지 않는 것입니다. 카메라가 또한 보간 되도록 카메라가 보간 대상을 따르도록 하는 것이 중요합니다.
수면 임곗값
활성화하면 현재 변환 상태의 변경 내용이 표시된 임곗값보다 모두 낮으면 루트 변환의 보간이 수행되지 않습니다. 그러면 루트 변환을 이동할 때 발생하는 영향이 완화되어 물리 캐싱이 깨지고 슬립이 방지됩니다. 슬립을 허용하는 것은 서버 권한 인스턴스에서 특히 중요한데, 아주 약간만 이동해도 네트워크 트래픽이 발생하기 때문입니다. 강체의 슬립을 허용하면 네트워크 트래픽이 크게 감소합니다.
노트: 수면 임곗값만 적용 가능한 것은 내삽 대상을 사용하지 않을 때뿐입니다.
렌더 수면 임곗값 사용
임계값에 대한 검사를 활성화합니다. 비활성화하면 객체가 항상 보간 됩니다.
렌더 임곗값
- Use Energy - 국소 강체의 속도와 각속도의 에너지 수준이 수면 임곗값을 초과하는지 테스트하고, 초과하는 경우 보간합니다.
- Position: 보간을 통해 이 값보다 큰 현재 변환 상태로 위치가 변경되면 보간이 발생합니다. 값이 0이면 Position은 테스트에서 제외됩니다.
- Rotation: 보간이 이 값보다 더 큰 현재 변환 상태로 회전 각도 변화를 생성하면 보간이 발생합니다. 값이 0이면 테스트에서 회전이 제외됩니다.
- Scale: 보간이 이 값보다 큰 현재 변환 상태에 대한 로컬 스케일 변화를 생성하면 보간이 발생합니다. 값이 0이면 검정에서 스케일이 제외됩니다.
Teleport()
NetworkTransform.Teleport를 참고하세요.
MovingTeleport()
이동 텔레포트를 시작합니다. RunnerSimulatePhysics3D
및 RunnerSimulatePhysics2D
가 물리를 시뮬레이션하기 전에 FixedUpdateNetwork()
에서 이 메소드를 호출해야 합니다. 이 텔레포트는 물리가 시뮬레이션 된 후까지 지연되며 시뮬레이션 전후의 위치 및 회전 값을 모두 캡처합니다. 이를 통해 텔레포트 전에 유효한 대상 타깃을 얻기 위해 텔레포트로 이어지는 보간을 수행할 수 있습니다. 이는 한 틱 동안 보간이 동결되는 기본 Teleport()의 대안입니다.
RunnerPhysicsSimulate2D / RunnerPhysicsSimulate3D
이러한 컴포넌트는 NetworkRunner
프리팹에 추가될 수 있으며 물리 시뮬레이션을 처리할 방법을 지정할 수 있습니다. 모든 FixedUpdateNetwork()
가 해당되는 물리를 Simulate()
라고 부릅니다.
물리 권한
Fusion이 이 컴포넌트를 사용하여 Physics.Simulate()
/Physics2D.Simulate()
를 호출할 것인지 또는 유니티의 물리 설정(자동 시뮬레이션 또는 스크립트 모드)에 맡길 것인지를 나타냅니다.
Auto
는 다음과 같은 경우 Fusion이 Simulate()
호출을 인수한다는 것을 나타냅니다:
- 게임은 공유 모드 이외의 모든 게임 모드에서 실행되고 있습니다. 공유 모드는 기본적으로 사용자가
FixedUpdateNetwork()
외부로 개체를 이동하는 것으로 가정합니다. 컨트롤러 코드가FixedUpdateNetwork()
내부에 적용되는 경우 이 컴포넌트를 추가하고 물리 권한을 Fusion으로 설정해야 합니다. - Multi-Peer 모드가 활성화되어 있습니다. 유니티는 기본이 아닌 물리 씬을 자동으로 시뮬레이션하지 않으므로 멀티-피어 모드를 사용할 때마다 Fusion은
Simulate()
호출을 제어해야 합니다.
물리 타이밍
Fusion이 물리 권한
인 경우 사용할 타이밍 세그먼트를 나타냅니다.
클라이언트 물리 시뮬레이션
클라이언트의 물리 시뮬레이션을 제어합니다. 옵션은 다음과 같습니다:
- Disabled: 물리 시뮬레이션은 클라이언트에서 실행되지 않으며 변환은 PhysX 엔진과 동기화되지 않습니다.
- SyncTransforms: 모든 틱에서 UnityEngine.Physics.SyncTransform()이 호출됩니다.
- SimulateForward: 재시뮬레이션 틱에서 UnityEngine.Physics.SyncTransform()이 호출됩니다. 포워드 틱에서는 UnityEngine.Physics.Simulate()이 호출됩니다.
- SimulateAlways: 모든 틱에서 UnityEngine.Physics.Simulate()가 호출됩니다.
⚠️ 서버는 항상 물리를 시뮬레이션합니다. 공유 모드에서 SimulateForward
와 SimulateAlways
는 순방향 틱만 시뮬레이션하는 것과 동일하게 동작합니다.
DeltaTime 승수
물리의 Simulate()
에 전달된 값의 승수입니다. 1보다 큰 값을 사용하면 시간의 흐름이 빨라지고 0에서 1 사이의 값을 사용하면 시간이 느려집니다.
FixedTimestep 설정
활성화하면 유니티의 Time FixedTimestep
값이 Fusion의 DeltaTime과 일치하도록 설정됩니다. FixedUpdate 내부의 사용자 코드가 Fusion의 틱과 거의 일치하는지 확인하는 데 도움이 됩니다.
중요: FixedUpdate()
와 FixedUpdateNetwork()
는 완전히 정렬되지는 않습니다. 이 두 타이밍 세그먼트의 사용이 혼합되지 않도록 모든 시도를 해야 합니다. 일반적으로 Fusion의 경우 모든 시뮬레이션 코드는 FixedUpdateNetwork()
에 있어야 하며, Update()
'의 변경이 필요하거나 필요한 공유 모드는 제외됩니다.
콜백
INetworkRunnerCallbacks.IBeforePhysicsStep
및 INetworkRunnerCallbacks.IAfterPhysicsStep
은 Fusion 2에서 제거되었고 다음으로 교체되었습니다.
OnBeforeSimulate / OnAfterSimulate
등록이 완료되면 RunnerSimulatePhysics
에서 시뮬레이션할 때마다 이러한 방법이 호출됩니다.
C#
using Fusion;
using Fusion.Addons.Physics;
using UnityEngine;
public class FusionPhysicsAddonExample : NetworkBehaviour
{
private RunnerSimulatePhysics3D _physicsSimulator;
public override void Spawned()
{
// Get our RunnerSimulatorPhysics instance (this needs to be added to the Runner)
_physicsSimulator = Runner.GetComponent<RunnerSimulatePhysics3D>();
// Register callback for EVERY simulation tick
_physicsSimulator.OnBeforeSimulate += OnBeforeEverySimulate;
}
public override void Despawned(NetworkRunner runner, bool hasState)
{
// Unregister (a good practice)
_physicsSimulator.OnBeforeSimulate -= OnBeforeEverySimulate;
}
void OnBeforeEverySimulate() {
// Implement code to execute before every Physics.Simulate
}
}
QueueBeforeSimulationCallback / QueueAfterSimulationCallback
이 콜백들은 다음에 시뮬레이션이 발생할 때 트리거 할 한 번의 콜백을 대기열에 넣습니다.
C#
using Fusion;
using Fusion.Addons.Physics;
using UnityEngine;
public class FusionPhysicsAddonExample : NetworkBehaviour
{
private RunnerSimulatePhysics3D _physicsSimulator;
public override void Spawned()
{
// Get our RunnerSimulatorPhysics instance (this needs to be added to the Runner)
_physicsSimulator = Runner.GetComponent<RunnerSimulatePhysics3D>
}
public override void FixedUpdateNetwork()
{
if (_physicsSimulator.HasSimulatedThisTick)
{
Debug.LogWarning($"Component is running FixedUpdateNetwork AFTER Physics Simulation, check my Script Exec Order");
PostSimulateActivity();
} else {
// Queue our method for a one time deferred callback
_physicsSimulator.QueueAfterSimulationCallback(PostSimulateActivity);
}
}
void PostSimulateActivity() {
// Implement code to execute after specific Physics.Simulate calls
}
}
알려진 문제점
- 자식 강체는 (Kinematic으로 설정된 경우에도) 예측할 수 없는 방식으로 물리학과 상호 작용하며, 시뮬레이션 중에 강체가 이전 위치에 있는 것처럼 물체와 충돌할 수 있습니다. 따라서 운반되는 물체는 충돌에 의존하지 않는 것이 좋고, 충돌기는 중첩된 상태에서 비활성화하는 것이 좋습니다.
- 중첩을 사용한 스케일(부모화)은 보간 대상이 없는 모든 부모에 의존합니다. 스케일링을 네스팅과 결합하고 보간 대상을 사용하려는 경우 보간 대상을 루트에서 분리하여 부모의 보간 대상에 다시 부모화할 수 있는 사용자 정의 처리를 작성합니다. 기본적으로 관련된 모든 보간 대상을 사용하여 강체 콜라이더/변환 계층 구조의 복사본을 만듭니다.
MovePosition()
및MoveRotation
은 보간 타깃을 사용해야 합니다. 대신 transform.position과 transform.rotation 값을 설정하여 운동학적 강체를 이동시키는 것은 이 조건을 직접적으로 피할 수 있습니다.