5 - 속성 변경
개요
이 섹션에서는 네트워크화된 속성
을 사용하여 플레이어의 위치 외에 네트워크를 통해 추가 데이터를 동기화하는 방법을 보여줍니다.
네트워크화된 속성
NetworkTransform
컴포넌트를 추가하면 NetworkObjects
변환이 동기화됩니다. 스크립트의 변수와 같은 다른 상태는 네트워크를 통해 동기화되지 않습니다. 네트워크를 통해 상태를 동기화하려면 [Networked]
속성이 필요합니다. 네트워크화된 속성
은 상태를 StateAuthority
에서 다른 모든 클라이언트로 동기화합니다.
클라이언트가 StateAuthority
가 없는 객체의 네트워크화된 속성을 변경하는 경우 네트워크를 통해 동기화되지 않고 로컬 예측으로 적용되며 향후 StateAuthority
의 변경으로 인해 재정의될 수 있습니다. 모든 클라이언트에 대해 업데이트하려면 StateAuthority
의 네트워크화된 속성만 업데이트하도록 주의하십시오.
네트워크 속성의 간단한 예로 플레이어의 색상을 들 수 있습니다. 먼저 새 스크립트를 만들고 PlayerColor
라고 이름을 붙입니다. 네트워크 속성과 객체의 MeshRender
를 참조할 수 있는 공용 필드를 추가합니다.
이 예제에서 목표는 공이 발사될 때 플레이어 큐브를 흰색으로 색칠한 다음 파란색으로 색칠하는 것입니다.
네트워크화된 속성 선언하기
효과를 트리거 하기 위해, 호스트는 네트워크화된 변수에서 단일 비트를 토글 할 것입니다. 단일 틱에서 (특정 플레이어에 의해) 하나 이상의 볼을 생성할 수 없기 때문에, 각각의 새로운 스폰은 비트의 값을 이전 틱과 다른 것으로 변경하여 변경 감지를 유발합니다.
코드를 추가하기 전에 이 설계는 실패 할 수 있습니다. 이미 언급한 바와 같이, 특히 플립/플롭 방식의 경우에는 이 감지되지 않을 수 있습니다. 이를 보다 복원력 있게 하기 위해서는 bool
을 a byte
또는 int
로 교체하고, 대신 각 호출에 충돌시킬 수 있습니다. 결국 시각적 효과가 얼마나 중요한지, 아니면 얼마나 많은 대역폭을 소비하는지의 문제입니다.
Player
클래스를 열고 새 네트워크 속성을 추가합니다:
C#
[Networked]
public bool spawnedProjectile { get; set; }
네트워크 속성을 정의할 때 Fusion은 제공된 get 및 set 스텁을 사용자 지정 코드로 대체하여 네트워크 상태에 접근합니다. 이는 애플리케이션이 이러한 방법을 사용하여 속성 값의 변화를 처리할 수 없으며 별도의 setter 메소드를 만드는 것은 로컬에서만 작동한다는 것을 의미합니다.
이를 해결하기 위해서는 ChangeDector
를 사용하여 변경사항을 확인할 수 있습니다. 다음과 같이 ChangeDector
를 스크립트에 새로 추가하고 Spawned
에서 초기화합니다:
C#
private ChangeDetector _changeDetector;
public override void Spawned()
{
_changeDetector = GetChangeDetector(ChangeDetector.Source.SimulationState);
}
또한 큐브 머티리얼을 참조할 머티리얼 필드를 추가하고 Awake
에서 필드를 설정합니다:
C#
public Material _material;
private void Awake()
{
...
_material = GetComponentInChildren<MeshRenderer>().material;
}
그리고 다음과 같이 Render
함수를 추가합니다:
C#
public override void Render()
{
foreach (var change in _changeDetector.DetectChanges(this))
{
switch (change)
{
case nameof(spawnedProjectile):
_material.color = Color.white;
break;
}
}
}
이 코드는 마지막으로 ChangeDetector
를 호출한 이후 네트워크화된 속성
에 발생한 모든 변경 사항을 반복합니다. 따라서 이 경우 마지막 Render
이후로 색상 값의 변화가 클라이언트에서 감지되면 MeshRenderer
가 업데이트됩니다.
이는 상태 변화에 대응하여 로컬 시각 효과를 스폰 하거나 게임 플레이 로직에 직접적인 영향을 미치지 않는 다른 작업을 수행하는 데 유용합니다. 이는 속성 변화가 재시뮬레이션으로 인해 여러 번(또는 정확하게는 예측 시 하나, 예측이 잘못된 경우 다시 두 번) 발생하거나 네트워크 상태보다 빠르게 속성이 두 값 사이를 왔다 갔다 하는 경우(또는 패킷이 드롭되는 경우) 완전히 생략될 수 있기 때문에 중요한 주의 사항입니다.
RPC와 같은 일반적인 메시지보다 변경 콜백을 사용하는 것의 주요 이점은 값이 변경되는 틱 직후에 콜백이 실행되는 반면, RPC는 게임이 완전히 다른 상태에 있을 때 나중에 도착할 수 있다는 것입니다.
색 지우기
색상은 현재 색상에서 파란색으로 선형 보간으로 Render()
에서 업데이트해야 합니다.
이는 FixedUpdateNetwork() 이후 실행이 보장되므로 Update()
가 아닌 Render()
에서 실행되며 Fusion 시뮬레이션의 일부가 아닌 유니티의 렌더 루프에서 실행되므로 Runner.DeltaTime
이 아닌 Time.deltaTime
을 사용합니다.
Render
함수의 끝에 다음 행을 추가합니다.
C#
_material.color = Color.Lerp(_material.color, Color.blue, Time.deltaTime);
Runner.Spawn()
을 호출한 후 spawnedProjectile
속성을 토글 하여 콜백을 트리거 하기만 하면 됩니다:
C#
...
Runner.Spawn(_prefabBall, transform.position+_forward, Quaternion.LookRotation(_forward));
spawnedProjectile = !spawnedProjectile;
...
Spawn()
이 호출되고 spawnedProjectile
이 전환되어야 하는 두 곳이 있음을 명심하십시오.
그런데 왜죠?
Q: 하지만 스폰을 호출할 때 색상을 바로 설정하는 것은 어떨까요?
호스트와 입력 권한을 가진 클라이언트 모두 플레이어의 입력을 기반으로 예측하기 때문에 이것은 작동하지만 프록시에서는 작동하지 않습니다.
Q: 하지만 색상이 Render()
의 모든 클라이언트에 단순히 로컬로 적용되는 네트워크 속성이라면 변경 감지기가 필요 없는 것인가요?
그렇게 하면 정말 효과가 있겠지만, 호스트에서 애니메이션으로 제작되어야 하고 불필요한 트래픽을 많이 발생시킬 수 있습니다. 일반적으로 시각 효과는 상태 권한자에 의해 트리거 되고 나서 각 클라이언트에서 자율적으로 실행되도록 두어야 합니다. 모든 사람들이 스파크를 사랑하는 만큼, 아무도 특정 스파크가 한 방향 또는 다른 방향으로 날아가든 신경 쓰지 않습니다.
Back to top