수정중인 페이지 입니다.

Fusion 105 - 속성 변경

개요

네트워크 속성을 정의할 때 Fusion은 제공된 getset 스텁을 사용자 지정 코드로 대체하여 네트워크 상태에 접근합니다. 즉, 프로그램은 이러한 메소드를 사용하여 속성 값 변경을 처리할 수 없으며 별도의 setter 메서드를 만드는 것은 로컬에서만 작동합니다.

이 문제를 해결하기 위해 Fusion은 속성이 변경될 때마다 호출할 static 콜백 메소드를 지정하는 데 사용할 수 있는 [Networked] 속성에 아규먼트를 제공합니다.

이것은 상태 변화에 대응하여 로컬 시각 효과를 생성하거나 게임 플레이 로직에 직접적인 영향을 미치지 않는 다른 작업을 수행하는 데 유용합니다. 재시뮬레이션(또는 정확히는 예측에 따라 한 번, 잘못된 경우에는 다시 한번)으로 인해 속성이 여러 번 변경될 수 있으며 네트워크 상태보다 빠르게 두 값 사이에서 변경되는 경우(또는 패킷이 없어진 경우) 완전히 건너뛸 수 있으므로 매우 중요한 주의 사항입니다.

OnChanged 콜백은 유니티의 Update() 주기(정확하게 말하면 Update 전에 호출됨)의 일부로 호출되지만 시뮬레이션의 일부가 아니며 하나의 유니티 프레임 간의 변화에 반응할 뿐입니다. 이것이 값이 잠깐 토글 된 것이 감지되지 않는 또 다른 이유입니다. 단일 프레임에서 여러 스냅샷을 처리하고 마지막 스냅샷이 네트워크 속성을 원래 값으로 되돌리면 변경 사항이 감지되지 않습니다.

RPC와 같은 일반적인 메시지에 대해 변경 콜백을 사용하면 값이 변경된 체크 표시 직후에 콜백이 실행된다는 이점이 있습니다. 여기서 RPC는 게임이 완전히 다른 상태에 있을 때 나중에 도착할 수 있습니다.

이 주제에 관한 상세 설명은 매뉴얼을 참고하세요

메인 화면으로

변경 리스너 추가하기

변경된 속성 콜백은 [Networked] 속성 자체에서 OnChanged 파라미터로 정의되며 'Changed<T> 타입의 단일 파라미터를 받는 static 메소드의 이름을 사용합니다. 여기서 T는 Behaviour 타입입니다.

이렇게 하면 Fusion에서 객체의 각 인스턴스에 대해 delegate를 할당하는 대신 타입에 대해 단일 delegate를 가질 수 있으므로 제공된 콜백은 static 메소드여야 합니다.

이 예에서는 공이 발사될 때 큐브를 흰색으로 칠한 다음 파란색으로 페이드 하는 것이 목표입니다.

이 효과를 트리거 하기 위해 호스트는 네트워크 변수에서 단일 비트를 토글 합니다. 단일 틱(주어진 플레이어에 의해)에 한 개 이상의 공을 생성할 수 없기 때문에 각각 새롭게 스폰 된 플레이어는 이전 틱과 다른 값으로 비트 값을 변경하여 OnChanged 콜백을 트리거 합니다.

코드를 추가하기 전에 이 설계는 실패할 수 있음에 주의하세요. 앞서 언급한 바와 같이 특히 플립/플롭 유형인 경우 변경사항이 감지되지 않을 수 있음에 유의하십시오. 이를 보다 탄력적으로 하기 위해 NetworkBoolbyte 또는 int로 대체하고 호출할 때마다 값을 변경하게 할 수도 있습니다. 결국 시각적인 효과와 대역폭의 소모하는 것 중 어떤 것이 중요한지의 문제입니다.

이러한 문제는 별도로 고민해 보고, Player 클래스를 열고 콜백의 간단한 구현과 함께 새 속성을 추가합니다.

[Networked(OnChanged = nameof(OnBallSpawned))]
public NetworkBool spawned { get; set; }

public static void OnBallSpawned(Changed<Player> changed)
{
  changed.Behaviour.material.color = Color.white;
}

이것은 Player가 큐브 메시의 색상을 변경하는 데 사용할 수 있는 머터리얼 속성을 가지고 있다고 가정하므로, 진행하시고 새로운 속성을 추가합니다:

private Material _material;
Material material 
{
  get
  {
    if(_material==null)
      _material = GetComponentInChildren<MeshRenderer>().material;
    return _material;
  }
}

Render()에서 색상을 현재 색상에서 파란색으로 선형 보간으로 업데이트해야 합니다. 이 작업은 FixedUpdateNetwork() 이후 실행이 보장되고 Runner.DeltaTime 이 아닌 Time.deltaTime을 사용하기 때문에 Update()가 아닌 Render()에서 수행되는데 Runner.DeltaTime은 Fusion 시뮬레이션의 일부가 아닌 유니티의 렌더링 루프에서 실행되기 때문입니다.

public override void Render()
{
  material.color = Color.Lerp(material.color, Color.blue, Time.deltaTime );
}

남은 것은 Runner.Spawn()를 호출한 후 spawned 속성을 토글 하여 콜백을 트리거 하는 것입니다:

...
Runner.Spawn(_prefabBall, transform.position+_forward, Quaternion.LookRotation(_forward));
spawned = !spawned;
...

Spawn()을 호출하는 두 곳이 있으며 모두 spawned를 토글 해야 합니다.

메인 화면으로

왜 그런 건가요?

Q: 하지만 왜 스폰을 호출할 때 바로 색을 정하지 않나요?

둘 다 플레이어 입력을 기반으로 예측하기 때문에 호스트와 입력 권한이 있는 클라이언트에는 효과가 있지만 프록시에는 효과가 없습니다.

Q: 하지만 색상이 Render()의 모든 클라이언트에 로컬로 적용되는 네트워크 속성이라면 OnChanged 핸들러가 필요하지 않을 것 같은데 맞나요?

그렇게 하면 정말 동작하겠지만, 호스트에서 애니메이션을 해야 하고 불필요한 트래픽이 많이 발생하게 됩니다. 일반적으로 시각 효과는 상태 권한자에 의해 촉발되고 각 클라이언트에서 자율적으로 실행되도록 남겨져야 합니다. 모두가 불꽃을 좋아하는 만큼, 그 누구도 특정한 하나의 불꽃이 한 방향으로 날고 있는지 다른 방향으로 날고 있는지 신경 쓰지 않습니다.

메인 화면으로

이전 상태 접근하기

이 간단한 예제는 변경된 속성의 실제 값에 대해 신경을 쓰지 않았지만, Changed<T> 파라미터는 변경 발생 시점의 소스 동작에 대한 참조가 있는 콜백에 제공되어야 하고 애플리케이션이 해당 틱 동안 동작의 모든 네트워크 속성에 접근할 수 있도록 허용되어야 하는 것에 주목해야 합니다.

명백하진 않지만, 이전 동작 상태를 로드하여 모든 네트워크 속성에 대한 이전 체크 표시의 상태를 애플리케이션에 효과적으로 제공하는 방법도 있습니다:

  var newValue = changed.Behaviour.someNetworkedProperty;
  changed.LoadOld();
  var oldValue = changed.Behaviour.someNetworkedProperty;

마찬가지로, 애플리케이션은 LoadNew()를 사용하여 새 상태를 다시 로드할 수 있지만 상태는 이 특정 콜백의 컨텍스트에서만 관련되므로 종료하기 전에 상태를 재설정할 필요가 없습니다.

기술문서 TOP으로 돌아가기