| 모드 | 설명 | 사용 시점 |
|---|---|---|
| Host | Server + Client 를 동시에 실행. 자신이 방장이자 참가자가 됨. | 기본 방식 |
| Client | 이미 실행 중인 서버(또는 Host)에 접속하는 참가자 | 방 참가자의 실행 모드 |
| Server | 플레이어 없이 게임 상태만 관리 | 전용 서버(Dedicated Server) 환경에서 사용 |
NetworkManager.Singleton.IsServer 와 IsClient 가 동시에 true를 반환if (IsServer) 로 분기 (Host 도 포함)if (IsClient && !IsServer) 로 분기// 호스트(서버 + 클라이언트)로 시작
NetworkManager.Singleton.StartHost();
// 클라이언트로 시작 (다른 Host 에 접속)
NetworkManager.Singleton.StartClient();
// 전용 서버로 시작
NetworkManager.Singleton.StartServer();
// 네트워크 종료
NetworkManager.Singleton.Shutdown();
| 콜백 | 발생 시점 |
|---|---|
| OnClientConnectedCallback | 클라이언트가 접속 직후 (서버와 클라이언트 양쪽에서 호출) |
| OnClientDisconnectCallback | 클라이언트 연결이 끊긴 직후 |
| OnServerStarted | 서버가 시작되었을 때 (Host / Server 측에서 호출) |
using UnityEngine;
using UnityEngine.UI;
using Unity.Netcode;
public class NetworkBootstrap : MonoBehaviour
{
[SerializeField] private Button _startHostButton;
[SerializeField] private Button _startClientButton;
[SerializeField] private Button _disconnectButton;
private bool _isCallbacksBound;
private void OnEnable()
{
BindNetworkCallbacks();
BindButtonEvents();
}
private void OnDisable()
{
UnbindNetworkCallbacks();
UnbindButtonEvents();
}
private void BindButtonEvents()
{
_startHostButton.onClick.AddListener(StartHost);
_startClientButton.onClick.AddListener(StartClient);
_disconnectButton.onClick.AddListener(Disconnect);
}
private void UnbindButtonEvents()
{
_startHostButton.onClick.RemoveListener(StartHost);
_startClientButton.onClick.RemoveListener(StartClient);
_disconnectButton.onClick.RemoveListener(Disconnect);
}
private void BindNetworkCallbacks()
{
if (_isCallbacksBound) return;
if (NetworkManager.Singleton == null) return;
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnect;
NetworkManager.Singleton.OnServerStarted += OnServerStarted;
_isCallbacksBound = true;
}
private void UnbindNetworkCallbacks()
{
if (!_isCallbacksBound) return;
if (NetworkManager.Singleton == null) return;
NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected;
NetworkManager.Singleton.OnClientDisconnectCallback -= OnClientDisconnect;
NetworkManager.Singleton.OnServerStarted -= OnServerStarted;
_isCallbacksBound = false;
}
private void StartHost() => NetworkManager.Singleton.StartHost();
private void StartClient() => NetworkManager.Singleton.StartClient();
private void Disconnect() => NetworkManager.Singleton.Shutdown();
private void OnClientConnected(ulong clientId) => Debug.Log($"<color=green>[Network] 접속: {clientId}</color>");
private void OnClientDisconnect(ulong clientId) => Debug.Log($"<color=red>[Network] 해제: {clientId}</color>");
private void OnServerStarted() => Debug.Log("<color=green>[Network] 서버 시작</color>");
}
NetworkTransform · NetworkVariable · ServerRpc는 NetworkObject 컴포넌트가 붙은 GameObject 위에서만 동작NetworkBehaviour 를 상속하면 그 스크립트 안에서 IsOwner, IsServer, ServerRpc 같은 네트워크 기능을 사용할 수 있음.public class PlayerController : NetworkBehaviour // MonoBehaviour 가 아님
{
public override void OnNetworkSpawn()
{
if (!IsOwner) return;
// 소유자 전용 초기화
}
}
NetworkBehaviour가 붙은 GameObject에는 반드시 NetworkObject 컴포넌트도 함께 있어야 함.NetworkBehaviour 는 일반 MonoBehaviour 라이프사이클 위에 네트워크 전용 라이프사이클이 추가됨.
👉 Awake → OnEnable → OnNetworkSpawn(이 시점부터 IsOwner / IsServer 등이 유효) → Start → Update
네트워크 속성에 의존하는 초기화는 반드시 OnNetworkSpawn() 에서 수행
| 속성 | 질문 | 대표 용도 |
|---|---|---|
| IsOwner | "이 오브젝트 를 내가 소유하는가?" | 입력 처리, 권위 있는 상태 변경 허용 |
| IsLocalPlayer | "이 오브젝트가 내 플레이어 캐릭터 인가?" | 로컬 카메라 추적, 내 HP 바 표시 |
| IsServer | "이 피어(peer)가 서버인가?" | 서버 권위 연산 (데미지 계산 등) |
using UnityEngine;
using Unity.Netcode;
public class PlayerController : NetworkBehaviour
{
[SerializeField] private float _moveSpeed = 5f;
public override void OnNetworkSpawn()
{
if (!IsOwner) return;
// 소유자 전용 입력 바인딩 등 초기화
}
private void Update()
{
if (!IsOwner) return;
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector3 move = new Vector3(h, 0f, v) * _moveSpeed * Time.deltaTime;
transform.position += move;
}
}
오브젝트의 Position · Rotation · Scale 을 네트워크로 자동 동기화하는 컴포넌트
권한이 있는 피어가 로컬에서 transform을 변경하면, NetworkTransform이 변경값을 다른 모든 피어에 자동으로 전파
네트워크 지연으로 인해 위치 갱신이 불연속적으로 수신될 수 있기 때문에, NetworkTransform은 수신된 위치 값을 보간(Interpolate) 해서 부드럽게 표현
주요 설정
| 항목 | 설명 |
|---|---|
| Authority Mode | Server (기본) 또는 Owner. 플레이어 캐릭터는 Owner 로 설정하는 것이 일반적 |
| Sync Position X / Y / Z | 축별로 위치 동기화 여부를 개별 설정. 2D 게임이라면 불필요한 축을 끌 수 있음. |
| Sync Rotation X / Y / Z | 축별 회전 동기화 여부. 기본값은 모두 활성화 |
| Sync Scale | 스케일 동기화 여부. 대부분의 게임에서 필요 없으므로 꺼 두는 것이 트래픽 절약에 좋음. |
| Interpolate | 수신 데이터를 부드럽게 보간해 표시. 기본값 true 를 유지하는 것을 권장. |
| In Local Space | true 면 World Space 가 아닌 부모 기준 Local Space 로 동기화. 차량 탑승 같은 부모-자식 구조에 사용 |
| 장르 | 권장 Authority | 이유 |
|---|---|---|
| 경쟁 FPS / PvP | Server Authority | 치팅 방지 필수 |
| 협동 PvE | Owner Authority | 치팅 위험 낮음, 반응성 우선 |
| 캐주얼 · 파티 게임 | Owner Authority | 구현 간단, 지연 체감 최소화 |
| MMORPG | Server Authority | 아이템 · 경제 시스템 서버 검증 필수 |
// 권한이 있는 피어에서만 호출 가능
// (Server 모드면 서버, Owner 모드면 소유자)
var netTransform = GetComponent<NetworkTransform>();
netTransform.Teleport(spawnPoint.position, Quaternion.identity, Vector3.one);
transform.position += ... 같은 변경은 NetworkTransform이 감지해 자동으로 동기화.Teleport() 를 사용.