유니티 포톤을 이용한 멀티플레이 구현
유니티 게임개발캠프 TIL 43일차
오늘도 포톤을 이용한 멀티플레이 구현을 했다.
여전히 수많은 오류들과 간단해 보이는 작업들에서 끝없이 막혀만갔다.
먼저 로비라는 개념과 방이라는 개념이 이미 포톤매니저에 있어서
내가 이 프로젝트에서 만든 로비와 개념이 섞이면서 많이 헷갈리게 됐다.
Photon Unity Networking (PUN) 기초 설정 및 연결
주요 개념:
- 서버 연결: PhotonNetwork.ConnectUsingSettings()를 사용하여 Photon 서버에 연결합니다. 이는 멀티플레이어 상호작용을 위한 기본 네트워킹 환경을 설정합니다.
- 장점: 간단한 함수 호출로 서버에 쉽게 연결할 수 있으며, Photon의 강력한 서버 인프라를 활용할 수 있습니다.
- 필수 사항: 앱 ID 및 설정 파일이 올바르게 구성되어 있는지 확인해야 합니다.
using Photon.Pun;
public class NetworkManager : MonoBehaviourPunCallbacks
{
void Start()
{
PhotonNetwork.ConnectUsingSettings(); // 서버에 연결
}
public override void OnConnectedToMaster()
{
PhotonNetwork.JoinLobby(); // 마스터 서버에 연결되면 로비에 접속
}
}
로비 접속: PhotonNetwork.JoinLobby()를 사용하여 로비에 접속합니다. 로비는 플레이어들이 게임 시작 전에 대기할 수 있는 공간입니다.
- 장점: 로비에서 다른 플레이어와의 매칭이 이루어지므로, 게임 시작 전 대기 상태를 관리할 수 있습니다.
- 필수 사항: 서버에 연결된 후 로비에 접속하는 로직이 필요합니다.
public override void OnConnectedToMaster()
{
PhotonNetwork.JoinLobby(); // 로비에 접속
}
방 생성 및 참가: PhotonNetwork.CreateRoom()와 PhotonNetwork.JoinRandomRoom()를 사용하여 방을 생성하거나 참가합니다.
- 장점: 방을 생성하여 프라이빗 게임을 설정하거나, 랜덤으로 방에 참가하여 빠른 매칭을 할 수 있습니다.
- 필수 사항: 방 설정과 참가 로직을 구분하여 구현해야 합니다.
public void CreateRoom()
{
PhotonNetwork.CreateRoom("RoomName"); // 방 생성
}
public void JoinRandomRoom()
{
PhotonNetwork.JoinRandomRoom(); // 랜덤 방 참가
}
멀티플레이어 환경에서의 플레이어 생성 및 관리
주요 포인트:
- 플레이어 생성: PhotonNetwork.Instantiate()를 사용하여 네트워크 상의 플레이어 객체를 생성합니다.
- 장점: 모든 클라이언트에 동일한 플레이어 객체가 생성되어 동기화가 쉽습니다.
- 필수 사항: 네트워크 객체를 위한 프리팹을 준비해야 합니다.
void Start()
{
if (PhotonNetwork.IsConnectedAndReady)
{
PhotonNetwork.Instantiate("PlayerPrefab", Vector3.zero, Quaternion.identity); // 플레이어 생성
}
}
플레이어 구분: 로컬 플레이어와 네트워크 플레이어를 구분하여 처리합니다.
- 장점: 로컬 플레이어의 입력과 네트워크 플레이어의 동작을 구분하여 처리할 수 있습니다.
- 필수 사항: PhotonView 컴포넌트를 사용하여 로컬 플레이어를 식별합니다.
if (photonView.IsMine)
{
// 로컬 플레이어 처리
}
else
{
// 네트워크 플레이어 처리
}
씬 전환 시 객체 유지: DontDestroyOnLoad를 사용하여 씬이 전환될 때 플레이어 객체가 파괴되지 않도록 합니다.
- 장점: 플레이어 상태와 데이터를 유지할 수 있습니다.
- 필수 사항: 씬 전환 시 객체가 유지되도록 설정해야 합니다.
void Awake()
{
DontDestroyOnLoad(this.gameObject); // 객체 유지
}
싱글플레이와 멀티플레이의 차이점 처리
주요 인사이트:
- 게임 시작 처리: 싱글플레이와 멀티플레이의 게임 시작 로직을 다르게 관리합니다.
- 장점: 각각의 모드에 맞는 최적화된 게임 시작 방식 제공.
- 필수 사항: 모드에 따라 다른 게임 시작 로직을 구현합니다.
void StartGame()
{
if (isMultiplayer)
{
PhotonNetwork.LoadLevel("MultiplayerScene"); // 멀티플레이어 씬 로드
}
else
{
LoadSinglePlayerGame(); // 싱글플레이어 게임 시작
}
}
로컬 플레이어 생성: PhotonNetwork를 사용하지 않는 로컬 플레이어 객체를 생성합니다.
- 장점: 네트워크 연결이 필요 없는 싱글플레이어 모드를 지원합니다.
- 필수 사항: 로컬 플레이어를 위한 별도의 생성 로직이 필요합니다.
void StartSinglePlayer()
{
Instantiate(singlePlayerPrefab, Vector3.zero, Quaternion.identity); // 로컬 플레이어 생성
}
자동 씬 동기화: PhotonNetwork.AutomaticallySyncScene 설정을 통해 모든 플레이어가 동일한 씬으로 자동으로 이동하도록 합니다.
- 장점: 씬 전환이 자동으로 동기화되어 플레이어 간의 일관성을 유지할 수 있습니다.
- 필수 사항: 자동 씬 동기화를 설정합니다.
void Awake()
{
PhotonNetwork.AutomaticallySyncScene = true; // 자동 씬 동기화 설정
}
PhotonNetwork.LoadLevel() 사용 시의 주의점
주요 포인트:
- 씬 전환 시 플레이어 객체 재생성: PhotonNetwork.LoadLevel()을 사용할 때 모든 플레이어 객체가 올바르게 재생성되도록 합니다.
- 장점: 씬 전환 후에도 모든 플레이어가 동일한 환경을 유지합니다.
- 필수 사항: OnJoinedRoom()에서 객체를 재생성합니다.
public override void OnJoinedRoom()
{
PhotonNetwork.Instantiate("PlayerPrefab", Vector3.zero, Quaternion.identity); // 플레이어 재생성
}
동일한 씬으로 이동: LoadLevel()을 사용하여 모든 플레이어가 동일한 씬으로 이동하도록 합니다.
- 장점: 모든 플레이어가 같은 씬에서 게임을 진행할 수 있습니다.
- 필수 사항: 씬 로드를 동기화합니다.
public void LoadGameScene()
{
PhotonNetwork.LoadLevel("GameScene"); // 동일 씬으로 이동
}
OnJoinedRoom()에서 재설정: OnJoinedRoom()에서 네트워크 플레이어를 재생성하고, 카메라 타겟을 설정합니다.
- 장점: 씬 전환 후 플레이어와 카메라 설정이 일관되게 유지됩니다.
- 필수 사항: 씬 전환 후 객체와 카메라를 재설정합니다.
public override void OnJoinedRoom()
{
GameObject player = PhotonNetwork.Instantiate("PlayerPrefab", Vector3.zero, Quaternion.identity); // 플레이어 재생성
Camera.main.GetComponent<CameraFollow>().SetTarget(player.transform); // 카메라 타겟 설정
}
PhotonNetwork와 관련된 객체 정리
주요 포인트:
- 객체 정리: OnDestroy()에서 PhotonNetwork.Destroy()를 사용하여 객체를 정리합니다.
- 장점: 메모리 누수를 방지하고 자원을 효율적으로 관리할 수 있습니다.
- 필수 사항: 객체가 파괴될 때 정리 로직을 추가합니다.
void OnDestroy()
{
if (PhotonNetwork.IsConnected)
{
PhotonNetwork.Destroy(this.gameObject); // 객체 정리
}
}
씬 전환 및 게임 종료 시: PhotonNetwork.DestroyAll()을 사용하여 모든 객체를 정리합니다.
- 장점: 씬 전환이나 게임 종료 시 불필요한 객체가 남지 않도록 합니다.
- 필수 사항: 씬 전환 또는 게임 종료 시 정리 로직을 추가합니다.
public void OnGameEnd()
{
PhotonNetwork.DestroyAll(); // 모든 객체 정리
}