수정중인 페이지 입니다.

Spawning

소개

GameObject가 네트워크를 통해 존재하려면 다음을 수행해야 합니다:

  1. NetworkObject 컴포넌트가 있어야 하며,
  2. Runner.Spawn() 메소드를 사용하여 생성되어야 합니다.

NetworkObject는 모든 클라이언트가 인스턴스가 무엇인지를 합의하고 각 네트워크 개체의 상태를 올바르게 동기화할 수 있도록 Fusion에서 네트워크 전체의 고유 식별자를 할당하는 데 사용됩니다. Runner.Spawn() 메소드는 Fusion에 새 개체 인스턴스를 집합 네트워크 상태에 추가할 시기와 방법을 알려줍니다.

메인 화면으로

중요!

네트워크 객체에 유니티의 내장 GameObject.Instantiate()GameObject.Destroy()사용하지 마세요. 이렇게 하면 네트워크 상태가 끊어진 상태에서 Fusion 시뮬레이션 루프에서 완전히 분리된 로컬 게임 객체를 생성할 뿐입니다.

메인 화면으로

Runner.Spawn

NetworkRunner 인스턴스의 Runner.Spawn() 메소드는 유니티의 GameObject.Instantiate() 메소드처럼 보입니다. 메소드에 제공할 수 있는 파라미터는 다음과 같습니다:

  1. NetworkObject 타입의 프리팹.
  2. 위치
  3. 회전
  4. 개체에 대한 입력 권한이 있는 클라이언트를 식별하는 PlayerRef.
  5. 다른 인스턴스에서의 객체를 복제하기 전에 실행하기 위한 NetworkRunner.OnBeforeSpawned 타입의 delegate.
  6. 예측된 생성인 경우 NetworkObjectPredictionKey 타입의 예측 키

프리팹만 필수 파라미터이며, 이외 모든 파라미터는 선택입니다.

var obj = Runner.Spawn(prefab, Vector3.zero, Quaternion.identity, Runner.LocalPlayer, MyOnBeforeSpawnDelegate, key);

어떤 클라이언트라도 Runner.Spawn()를 호출할 수 있으나 네트워크 토폴로지에 따라 결과가 달라질 수 있습니다.

  • 호스트 또는 클라이언트/서버 모드의 서버에서는 생성된 객체의 소유권(상태 권한)이 서버에 할당되고 객체가 생성되어 즉시 리턴됩니다. 클라이언트는 다음 스냅샷의 일부로 객체를 받습니다.
  • 호스트 또는 클라이언트/서버 모드의 클라이언트에서는 기본 동작은 아무 일도 일어나지 않고 호출이 null을 리턴합니다. 그러나 Fusion은 즉각적인 피드백을 위한 임시 로컬 객체 생성을 지원합니다. 이를 "예측 스포닝"이라고 합니다.
  • 공유 모드에서는 상태 권한이 항상 호출자에게 할당되고 인스턴스가 즉시 리턴됩니다. 다른 클라이언트도 최종적으로 객체를 받게 됩니다.

어느 경우든 FixedUpdateNetwork에서 Spawn을 호출해야 하며 포워드 및 재시뮬레이션 단계에서 호출해도 됩니다. Fusion은 예측된 로컬 생성(예측 키가 일치한다고 가정)을 다시 시뮬레이션하는 동안 동일한 객체를 올바르게 반환하지만 권한 있는 스폰은 공유 모드 또는 호스트에서만 수행되며 둘 다 다시 시뮬레이션하지 않습니다.

메인 화면으로

입력 권한

입력 권한은 PlayerRef를 메소드에 전달하여 특정 클라이언트에 할당되며, 이는 선택 사항입니다. 입력 권한이 부여된 클라이언트는 객체에 대한 입력 데이터를 제공할 수 있으며 (호스트 또는 서버 외에도) GetInput()에서 해당 입력 구조체를 쿼리 할 수 있습니다.

객체에 입력이 필요하지 않거나 객체에 대한 입력 권한이 없는 경우 null을 대신 전달할 수 있습니다.

메인 화면으로

OnBeforeSpawned

The NetworkRunner.OnBeforeSpawned 파라미터는 메소드 또는 위임자 서명과 일치하는 람다 표현식을 받을 수 있습니다.

public delegate void OnBeforeSpawned(NetworkRunner runner, NetworkObject obj);

이 delegate는 객체가 생성된 후 모든 인스턴스에서 동기화되기 전에 호출됩니다. 이를 통해 호출자는 시스템의 다른 부분이 객체에 접근하기 전에 객체의 추가 사용자 지정 초기화를 수행할 수 있습니다. 사용자 지정 네트워크 속성을 초기화할 수 있는 좋은 위치입니다.

private void MySpawnFunction(){
    Runner.Spawn(
        _objPrefab, 
        Vector3.zero, 
        Quaternion.identity, 
        inputAuthority: null, 
        InitializeObjBeforeSpawn,
        predictionKey: null
        );
}

private void InitializeObjBeforeSpawn(NetworkRunner runner, NetworkObject obj)
{
    var objSB = obj.GetComponent<ObjSimulationBehaviour>();
    objSB.InitializeObjSettings(_currentExplosionForce);
}

메인 화면으로

Spawned

Fusion은 새 객체를 생성할 때 해당 객체에 대해 Spawned() 메서드를 호출합니다. Spawned() 콜백은 네트워크화되지 않은 변수 및 하위 시스템을 재설정하기 위한 것입니다. 예를 들어 애플리케이션서 객체 풀링을 사용하는 경우 객체가 재활용되어 더 이상 기본 상태가 아니므로 Spawned()는 값을 프리팹 기본값으로 재설정해야 할 수 있습니다. 모든 NetworkBehaviour 컴포넌트는 ISpawned 인터페이스를 구현하므로 NetworkBehaviour에서 상속된 모든 컴포넌트는 간단히 재정의하고 구현할 수 있습니다. 그러나 SimulationBehaviour 상속된 컴포넌트는 ISpawned와 그 메소드를 명시적으로 구현하여 Spawned() 메소드를 호출해야 합니다.

Fusion이 객체의 존재를 처음 알게 되면 Spawned()가 호출됩니다. 이것은 틱에 정렬되어있지 않거나 권위 있는 피어에 의해 객체가 원래 생성된 틱 근처가 아닙니다. 이러한 이유로 Networked 상태는 Spawned()에서 초기화해서는 안 되며 RPC들은 Spawned()으로 전송해서는 안 됩니다.

  • 상태 권한을 가진 피어의 경우 Spawned()Runner.Spawn() 바로 뒤에 호출됩니다.
  • 입력 권한이 있는 피어의 예측된 스폰의 경우 네트워크 상태가 할당될 때(즉, 생성 확인 시) Spawned()가 호출됩니다.
  • 프록시(피어에 입력 권한이나 상태 권한이 없는 개체)의 경우 Fusion이 로컬에 존재하지 않는 객체가 있는 네트워크 상태를 수신하면 Spawned()가 호출됩니다. 특히 늦게 조인하는 플레이어는 오래 전에 스폰된 객체를 받을 가능성이 높으며 그들의 "birth tick"으로부터 원시 상태는 적절하지 않습니다.

스폰에서 상태를 초기화해야 하는 경우 사전-스폰 NetworkRunner.OnBeforeSpawned 콜백이 Runner.Spawn()으로 제공됩니다.

메인 화면으로

Despawn

네트워크 객체를 제거하기 위해 객체에 대한 상태 권한을 가진 피어가 Runner.Despawn()을 호출할 수 있습니다.

메인 화면으로

Despawned

Runner.Spawn()Spawned() 메소드를 트리거하는 것과 유사하게 ISpawned, Despawn() 구현하는 클래스에 대한 호출은 IDespawned을 구현하는 클래스들에 대한 Despawned() 메소드를 호출해주게 됩니다.

모든 NetworkBehaviour들은 IDespawned를 구현하는 반면, SimulationBehaviour는 명시적으로 추가해주어야 합니다.

메인 화면으로

스폰 예측

스폰 예측은 호스트 / 서버 모드에서만 사용할 수 있습니다.

예측 스포닝은 권한 없는 클라이언트가 객체의 미래 존재를 예측할 수 있고 적절한 네트워크 객체의 존재가 성공 또는 실패로 확인될 때까지 로컬 자리 표시자를 시뮬레이션할 수 있기 때문에 이러한 이름이 붙습니다.

이 동작이 작동하려면 다음 두 가지가 필요합니다.

  1. 클라이언트가 임시 로컬 객체를 미래의 "실제" 인스턴스와 일치시킬 수 있도록 고유한 식별자를 만들어야 합니다. 이렇게 하면 스폰이 확인될 때 로컬 객체를 퍼스트 클래스 네트워크 개체로 업그레이드할 수 있습니다.
  2. 클라이언트 확인 또는 취소될 때까지 로컬 객체를 처리해야 합니다.

메인 화면으로

NetworkObjectPredictionKey

Runner.Spawn() 메소드내의 predictionKey 파라미터는 4 바이트로 구성되어 있습니다. 애플리케이션은 다음 사항을 고려하는 한 자체 키를 자유롭게 발명할 수 있습니다.

  1. 키는 클라이언트와 권한 있는 호스트/서버에서 동일해야 하므로 임의이거나 로컬 데이터를 기반으로 할 수 없습니다.
  2. 플레이어와 현재 틱에 따라 고유해야 합니다. 키에는 플레이어 ID와 함께 틱(또는 일부 하단 부분)을 포함하는 것이 좋습니다.
var predictionKey = new NetworkObjectPredictionKey {Byte0 = (byte) Runner.Simulation.Tick, Byte1 = playerIndex};

주의: 동일한 틱 동안 클라이언트가 여러 네트워크 객체를 예측하여 생성하는 경우(예: 공유 카운터) 생성된 다양한 NetworkObjects를 서로 구분하기 위해 추가 정보(예: 공유 카운터)가 필요합니다.

메인 화면으로

IPredictedSpawnBehaviour

스폰된 게임 객체가 예측된 상태에 있는 동안에는 Fusion 시뮬레이션의 일부가 되지 않으며 해당 객체의 네트워크 속성은 아직 접근할 수 있는 상태가 아니기 때문에 작동하지 않습니다. 예측된 객체가 실제 객체처럼 행동하기 위해서는 약간의 추가적인 로직이 필요합니다. 이 로직은 IPredictedSpawnBehaviour 인터페이스를 사용하여 구현해야 합니다.

public interface IPredictedSpawnBehaviour {
    void PredictedSpawnSpawned();
    void PredictedSpawnUpdate();
    void PredictedSpawnRender();
    void PredictedSpawnFailed();
    void PredictedSpawnSuccess();
  }

메인 화면으로

스폰, 업데이트, 렌더

세 가지 첫 번째 메소드는 기능적인 SimulationBehaviourNetworkBehaviour 컴포넌트에 있는 Spawned(), FixedUpdateNetwork()Render() 메소드와 일치합니다. 객체가 "예측된" 상태에 있을 때 배타적이고 명시적으로 호출된다는 차이가 있는 메소드와 동일한 조건에서 호출됩니다.

실제로 이러한 방법의 가능한 구현 방법 중 하나는 각각 Spawned(), FixedUpdateNetwork()Render()를 호출하는 것이지만, 애플리케이션은 네트워크 속성을 사용할 수 없다는 점을 고려해야 합니다. 이에 대한 한 가지 해결책은 예측 스폰 검사를 통해 네트워크 속성을 래핑하고 다음과 같은 두 가지 변수 집합을 유지하는 것입니다.

[Networked]
public Vector3 networkedVelocity { get; set; }
private Vector3 _predictedVelocity;
public Vector3 velocity
{
    get => Object.IsPredictedSpawn ? _predictedVelocity : networkedVelocity;
    set 
    {
      if (Object.IsPredictedSpawn) 
        _predictedVelocity = value; 
      else 
        networkedVelocity = value; 
    }    
}

메인 화면으로

실패와 성공

PredictedSpawnFailed()PredictedSpawnSuccess는 예측과 관련이 있으며 서버/호스트가 스폰의 성공 또는 실패를 확인할 때 트리거됩니다. 예측이 성공하면 PredictedSpawnSuccess()가 호출되고 그렇지 않으면 PredictedSpawnFailed()가 트리거됩니다.

임시 객체가 완전히 네트워크로 연결된 객체로 승격되고 아무것도 변경되지 않은 것처럼 계속 존재하기 때문에 애플리케이션은 성공적인 생성을 처리할 필요가 거의 없습니다. 그러나 예측 실패는 처리되어야 합니다. 가장 간단한 구현은 객체를 파괴하는 것입니다.

예측 객체에서 Runner.Despawn()를 사용할 때 문제의 객체가 예측 상태에 있었음을 나타내는 추가적인 파라미터가 필요합니다.

public void PredictedSpawnFailed()
{
    Runner.Despawn(Object, true);
}

Runner.Spawn()이 Fusion 객체 풀을 통해 임시 개체를 얻었기 때문에 Runner.Despawn()을 사용해야 합니다.

기술문서 TOP으로 돌아가기