4 - 물리
개요
Fusion 104는 서버 권위 있는 게임에서 Fusion이 PhysX와 어떻게 상호작용하는지 조사할 것입니다.
이 섹션의 끝부분에, 프로젝트는 플레이어가 물리적으로 제어되는 공을 생성하고 상호작용할 수 있도록 합니다.
설정
호스트 모드에서, Fusion은 호스트에서 물리 시뮬레이션을 수행하고 클라이언트는 이 결과를 따르지만 애플리케이션은 물리가 객체들을 제어할지라도 선택적으로 클라이언트들이 예측할 수 있도록 허용합니다.
이 기능을 켜려면 Fusion 메뉴로 이동하여 네트워크 프로젝트 구성
을 선택하십시오. 이렇게 하면 Fusion 구성 파일이 인스펙터에서 열립니다. 서버 물리 모드
에서 클라이언트 예측
을 선택합니다.
클라이언트 예측을 활성화하면 계산 비용이 더 많이 들지만 보다 정확한 이동을 할 수 있습니다.
물리 객체
PhysX 제어 네트워크 개체(PhysX 제어되는)의 프리팹은 일반 유니티 PhysX 객체와 동일한 Rigidbody
를 사용하지만 NetworkRigidbody
라는 비주얼 하위 개체를 동기화하는 Fusion 컴포넌트가 다릅니다. 이것은 네트워킹에 관한 한 NetworkTransform
을 대체합니다.
- 유니티 편집기에서 새로운 빈 GameObject를 생성합니다.
GameObject
에서PhysxBall
로 이름을 변경합니다.- 새로운
NetworkRigidbody
컴포넌트를 추가합니다. - Fusion이 누락된
NetworkObject
컴포넌트에 대해 경고를 하므로,Add Network Object
를 누릅니다. PhysX 시뮬레이션에 필요하기 때문에 Fusion은 자동적으로 일반 유니티 RigidBody를 추가해 줍니다. Interpolation Data Source
를Predicted
로 변경하고World Space
로 설정합니다.PhysxBall
에 구체 자식을 추가합니다.- 모든 방향에서 자식의 스케일을 0.2로 낮춥니다.
- 부모 객체의 NetworkTransform 컴포넌트의
InterpolationTarget
로 자식 객체를 드래그합니다. - 구체에서 콜라이더를 제거합니다.
- 반지름이 0.1인 상위 객체에 새 구체 콜라이더를 만들어 하위 객체를 완전히 덮습니다.
- 게임 오브젝트에 새로운 스크립트를 추가하고
PhysxBall.cs
로 이름을 변경합니다. - 전체 객체를 프로젝트 폴더로 끌어 프리팹을 만듭니다.
- 네트워크 객체를 베이크 하기 위해 씬을 저장하고 씬에서 프리팹 인스턴스를 삭제합니다.
PhysxBall 스크립트
공이 PhysX에 의해 구동되고 NetworkRigidbody가 네트워크 데이터를 관리하기 때문에 키네마틱 형제에 비해 작업하는 데 특별한 코드가 덜 필요합니다. PhysxBall.cs
에 추가가 필요한 것은 몇 초 뒤 공이 사라지는 타이머(키네마틱 공과 정확히 동일)와 초기 전진 속도를 설정하는 메소드입니다.
두 개 모두 다음과 같은 Init()
메소드에 의해 다루어집니다:
C#
using UnityEngine;
using Fusion;
public class PhysxBall : NetworkBehaviour
{
[Networked] private TickTimer life { get; set; }
public void Init(Vector3 forward)
{
life = TickTimer.CreateFromSeconds(Runner, 5.0f);
GetComponent<Rigidbody>().velocity = forward;
}
public override void FixedUpdateNetwork()
{
if(life.Expired(Runner))
Runner.Despawn(Object);
}
}
입력
볼을 스폰 하려면 키네마틱 공과 동일한 3단계에 따라 코드를 확장해야 하지만 대신 두 번째 마우스 버튼을 사용하도록 변경해야 합니다:
1. NetworkInputData
NetworkInputData.cs
에서 새로운 버튼 플래그를 추가합니다:
C#
using Fusion;
using UnityEngine;
public struct NetworkInputData : INetworkInput
{
public const byte MOUSEBUTTON1 = 0x01;
public const byte MOUSEBUTTON2 = 0x02;
public byte buttons;
public Vector3 direction;
}
2. BasicSpawner
BasicSpawner.cs
에서 첫 번째와 같은 방식으로 두 번째 마우스 버튼을 폴링하고 이에 따라 플래그를 설정합니다:
C#
private bool _mouseButton0;
private bool _mouseButton1;
private void Update()
{
_mouseButton0 = _mouseButton0 || Input.GetMouseButton(0);
_mouseButton1 = _mouseButton1 || Input.GetMouseButton(1);
}
public void OnInput(NetworkRunner runner, NetworkInput input)
{
var data = new NetworkInputData();
...
if (_mouseButton1)
data.buttons |= NetworkInputData.MOUSEBUTTON2;
_mouseButton1 = false;
input.Set(data);
}
3. 플레이어
Player.cs
는 실제 볼 프리팹을 생성하는 코드를 가지고 있기 때문에 이와 같은 프리팹 참조가 필요합니다.
C#
[SerializeField] private PhysxBall _prefabPhysxBall;
Player
는 스폰을 반드시 호출해야 하고, 이전에 생성된 Init()
메소드를 사용해서 속도(상수에 최종 전진 방향을 곱하는)를 설정합니다.
C#
public override void FixedUpdateNetwork()
{
if (GetInput(out NetworkInputData data))
{
data.direction.Normalize();
_cc.Move(5*data.direction*Runner.DeltaTime);
if (data.direction.sqrMagnitude > 0)
_forward = data.direction;
if (delay.ExpiredOrNotRunning(Runner))
{
if ((data.buttons & NetworkInputData.MOUSEBUTTON1) != 0)
{
delay = TickTimer.CreateFromSeconds(Runner, 0.5f);
Runner.Spawn(_prefabBall,
transform.position+_forward,
Quaternion.LookRotation(_forward),
Object.InputAuthority,
(runner, o) =>
{
// Initialize the Ball before synchronizing it
o.GetComponent<Ball>().Init();
});
}
else if ((data.buttons & NetworkInputData.MOUSEBUTTON2) != 0)
{
delay = TickTimer.CreateFromSeconds(Runner, 0.5f);
Runner.Spawn(_prefabPhysxBall,
transform.position+_forward,
Quaternion.LookRotation(_forward),
Object.InputAuthority,
(runner, o) =>
{
o.GetComponent<PhysxBall>().Init( 10*_forward );
});
}
}
}
}
마지막으로 새로운 공을 테스트하기 위해서는 생성된 프리팹을 Player
프리팹의 Prefab Physx Ball
필드에 할당하고 빌드 및 실행하세요.