TIL_2025_02_21 Photon Fusion_주요 속성 및 함수

김효중·2025년 2월 21일

Photon Fusion이란?

Photon Fusion은 Photon에서 개발한 차세대 네트워크 엔진으로, Unity에서 멀티플레이어 게임을 개발할 때 사용됩니다. 기존에 사용하던 Photon PUN과 Bolt의 장점을 결합하여 높은 성능과 유연성을 제공합니다. 그러면서 기존과 방식과 사용 함수가 다소 다르기 때문에 주의해야합니다.

자세한 변경사항은 다음과 같습니다.

주요 속성 및 함수

Fusion의 주요 컴포넌트는 NetworkRunner와 NetworkObject가 있습니다.

- NetworkRunner

NetworkRunner는 Fusion의 핵심으로 네트워킹의 주체라고 볼 수 있습니다. NetworkRunner는 네트워킹과 시뮬레이션을 모두 관리하는 단일 오브젝트입니다.

- NetworkObject

NetworkObject는 유니티의 프리팹 또는 객체가 네트워크에 존재하기 위해 필요한 컴포넌트입니다. NetworkObject를 추가하면 런타임시 네트워크 ID가 할당 되고 동기화 된 틱 기반 시뮬레이션에서 동작합니다.

이를 위해서는 SimulationBehaviour 및 NetworkBehaviour의 상속이 필요합니다.

- Networked

[Networked] public byte life { get; set; }

위처럼 Netword은 거의 모든 속성에 사용할 수 있으며 해당 값은 네트워크상에서 공유됩니다.
bool값은 예외적으로 NetworkBool을 사용합니다.

[Networked(OnChanged = "OnTypeChanged")] public Type type { get; set; }

public static void OnTypeChanged(Changed<TheClassWhichHasTheProperty> changed)
{
  // your code here - check API docs for more details
}

또한 위와 같이 변경될때마다 호출 되는 콜백을 등록 할 수도 있습니다.

NetworkBehaviour

NetworkBehaviour는 기존의 MonoBehaviour를 대처합니다.
MonoBehaviour의 동작을 네트워크에서도 동작 할 수 있게합니다.
또한 NetworkTransform를 통해 네트워크에서 동기화된 이동을 스냅샵 보간을 통해 자연스럽게 움직일 수 있으며 NetworkRigidbody를 통한 물리연산 제어도 시행합니다.
휴머노이드 기반의 아바타의 경우 NetworkCharacterController를 통해 이동을 구현할 수 있습니다.

SimulationBehaviour

SimulationBehaviour 라이프 사이클

네트워크 상에서 동작하기 위해서는 SimulationBehaviour의 라이프 사이클을 따른다.
Awake, Start등의 내장 코드는 사용 가능하지만 안전을 위해 대처한다.
Start()는 Spawned()로 전환하면 객체가 처음 활성화 될 때 호출된다.
또한 FixedUpdateNetwork()는 가장 중요한 함수로 고정된 네트워크 틱마다 호출 된다.
NetworkTransform, NetworkRigidbody는 이때 호출하는게 안전하다.

transform.position += transform.forward * Runner.DeltaTime;

Runner.DeltaTime는 Time.DeltaTime 처럼 일정한 속도를 구현하는데 필요하다.
Render()는 FixedUpdateNetwork()에 대한 모든 호출 후 LateUpdate() 전에 실행되어 네트워크 진행 후 결과를 표시할 때 사용한다.

입력 처리

Fusion은 입력 처리를 두 단계로 나눠진다.

  1. 로컬 하드웨어에서 입력을 저장한 후 서버로 전송
  2. FixedUpdateNetwork()에서 이 입력을 읽어 게임 상태를 변경

첫 번째 단계는 Fusion이 OnGetInput() 콜백에서 폴링하고 두 번째 단계는 일반적으로 메인 캐릭터의 SimulationBehaviour에 의해 FixedUpdateNetwork() 내에서 GetInput() 또는 TryGetInput()을 호출하여 처리된다.

	// 입력 예시
	public void OnInput(NetworkRunner runner, NetworkInput input)
    {
        var data = new NetworkInputData();

        if (Input.GetKey(KeyCode.W))
            data.direction += Vector2.up;

        if (Input.GetKey(KeyCode.S))
            data.direction += Vector2.down;

        if (Input.GetKey(KeyCode.A))
            data.direction += Vector2.left;

        if (Input.GetKey(KeyCode.D))
            data.direction += Vector2.right;

        data.buttons.Set(NetworkInputData.MOUSEBUTTON0, _mouseButton0);
        _mouseButton0 = false;
        
        input.Set(data);
    }
    
	// 입력 처리 예시
    public override void FixedUpdateNetwork()
    {
        if (GetInput(out NetworkInputData data))
        {
            // move
            data.direction.Normalize();
            _cc.Move(5 * data.direction * Runner.DeltaTime);
        }
    }

RPC(원격 프로시저 호출)

RPC는 void를 반환타입으로 가는 함수를 선언하고 [Rpc] 태그하고 호출 위치와 실행 위치를 지정합니다.

[Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)]
public void RPC_Configure(string name, Color color)
{
    playerName = name;
    playerColor = color;
}

위 코드는 RpcSources.InputAuthority(입력 권한을 가진 클라이언트) 권한을 가지는 클라이언트에서 호출 할 수 있으며 RpcTargets.StateAuthority(상태를 관리하는 주체) 를 가지는 클라이언트에서 실행 됩니다. 즉 플레이어 클라이언트에서 호출할 수 있고 실행은 서버(호스트)에서 실행 됩니다.

참고
https://doc.photonengine.com/ko-kr/fusion/v1/fusion-intro

profile
도전하는 개발자

0개의 댓글