0. 개요
이전 글에서 기본 설정 하는 법을 읽지 않았다면 이전 글을 먼저 읽고 오자. (접은글을 펼치자!)
이제, 서버에 연결하는 법을 알았으니, 상태를 제어해야한다.
설명을 위해 지금 개발중인 게임을 예로 들어서 작성하겠다.
1. 서버접속
서버에 접속하기 위해선 일단 서버에 접속하는 함수를 불러와야한다.
Photon PUN에서는 해당 기능을 제공하는 함수를 제공하고있다.
다음 스크립트를 살펴보자.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;
public class NetworkManager : MonoBehaviourPunCallbacks
{
[SerializeField] Text stateText;
// Start is called before the first frame update
void Start()
{
Connected();
}
// Update is called once per frame
void Update()
{
stateText.text = "서버상태 : " + PhotonNetwork.NetworkClientState.ToString();
}
//ServerConnect
public void Connected() => PhotonNetwork.ConnectUsingSettings();
public override void OnConnected() => print("서버 연결 완료");
public override void OnDisconnected(DisconnectCause cause) => print("연결 종료");
}
서버의 상태를 직관적으로 보기 위해 Text오브젝트를 생성하였다.
Start()함수에 서버에 연결하는 함수를 두어, 게임을 실행하면 제일먼저 서버에 접속 시도부터 하게 하였다.
추후에, 각 클라이언트는 개개인의 서버로 활용할것이고, 멀티 플레이를 위해서 각 클라이언트에 접속할것이다. 이는 추후에 설명하려고 한다.
이어서, Update()함수에서는 만들어둔 Text오브젝트에 상태를 계속 표시해주기 위해 PhotonNetwork.NetworkClientState.ToString(); 를 호출하여 계속 표시하도록 하고 있다.
PhotonNetwork.NetworkClientState
위의 기능을 호출하면 순서에 따라서 다음과 같은 스테이트를 가지게 된다.
ConnectingToNameServer |
클라이언트가 네임서버에 연결됩니다. 이 프로세스에는 낮은 수준의 연결 및 암호화 설정이 포함됩니다. 완료되면 상태는 ConnectedToNameServer가 됩니다. |
ConnectedToNameServer | 클라이언트가 NameServer에 연결되어 있고 암호화가 이미 설정되어 있습니다. OpGetRegions 또는 ConnectToRegionMaster를 호출해야 합니다. |
Authenticating | 서버에 연결하는 동안의 전환 상태입니다. Photon 클라우드에서는 AppId 및 AuthenticationValues(UserID)를 보냅니다. |
ConnectingToMasterServer | MasterServer에 연결합니다(인증 값 전송 포함). |
ConnectedToMasterServer | MasterServer에 연결되었습니다. 지금 매치메이킹을 사용하거나 로비에 참가할 수 있습니다. |
즉, Connected()함수가 호출되면 위와 같은 단계를 거쳐, 매치메이킹과 로비 참가기능을 사용할 수 있는 상태가 된다.
위의 코드는 Connected가 정상적으로 호출 완료 되면, 그 이후에 PhotonNetwork.ConnectUsingSettings();를 호출하게 된다.
ConnectUsingSetting이 실질적인 서버 접속함수가 되는것이다. 이 함수가 호출되면 콜백함수로 OnConnected함수가 호출되게 된다.
이후 OnConnected함수가 호출되면, 호출이 성공적으로 되었다는 의미로 서버연결완료라는 메세지를 print하게 된다.
2. 방 만들기
//RoomCreate
public void CreateRoom() => CheckCreateRoom();
public override void OnCreatedRoom() => AfterCreateRoom();
public override void OnCreateRoomFailed(short returnCode, string message) => print("방 생성 실패");
void AfterCreateRoom(){
print("방 생성완료");
SceneManager.LoadScene("MenuScene");
}
void CheckCreateRoom(){
if(playerNickNameInput.text == ""){
print("닉네임을 입력해야합니다.");
}
else{
print("닉네임이 있음.");
PhotonNetwork.LocalPlayer.NickName = playerNickNameInput.text;
PhotonNetwork.CreateRoom("100",new RoomOptions { MaxPlayers = 2 });
}
}
위의 코드에서 이어지는 코드이다.
방을 만드는 기능또한 Photon에서 제공하는 기능이고, Connect와 전체적인 구조는 동일하게 진행된다.
OnCreateRoom()은 콜백함수이고, 이 함수가 정상적으로 실행이 완료 된다면 자동으로 AfterCreateRoom()이라는 직접 정의한 함수를 호출하도록 했다.
AfterCreateRoom함수는 정상적으로 방이 생성된다면 씬을 MenuScene으로 전환되게 하였다.
또한, CreateRoom이 실행된다면 닉네임 필드가 정상적으로 입력되어 있는지 확인하는 기능을 추가해, 플레이어가 게임에 참여할때, 닉네임을 필수로 입력하도록 하였다.
3. 방 참가하기
public void JoinRoom() => CheckJoinRoom();
public override void OnJoinedRoom() => AfterJoinRoom();
public override void OnJoinRoomFailed(short returnCode, string message) => print("방 참가 실패");
void AfterJoinRoom(){
print("방 참가완료" + PhotonNetwork.CurrentRoom.Name);
SceneManager.LoadScene("MenuScene");
}
void CheckJoinRoom(){
if(playerNickNameInput.text == "" && roomCodeInput.text == ""){
print("InputField를 입력해야합니다.");
}
else{
print("닉네임이 있음.");
PhotonNetwork.LocalPlayer.NickName = playerNickNameInput.text;
PhotonNetwork.JoinRoom(roomCodeInput.text);
}
}
방을 참가하는 기능은 JoinRoom이라는 함수를 중심으로 작성하였다.
특별히 설명할 기능은 없는것 같고, 위의 코드를 응용해서 작성하면 될 듯 하다.
아래의 CheckJoinRoom 함수에서 else문 내부의 PhotonNetwork.JoinRoom 함수를 보면, 참여하려는 방의 이름을 매개변수로 받고 있다.
4. 마치며
현재 기능은 아직 로컬에서만 플레이 되도록 만들어둔 기술이라, 게임을 빌드하여 여러 클라이언트를 생성해 실험해보면 될 듯 하다. 추가로 전체 코드는 접어두겠다.
NetworkManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class NetworkManager : MonoBehaviourPunCallbacks
{
[SerializeField] InputField roomCodeInput;
[SerializeField] InputField playerNickNameInput;
// Start is called before the first frame update
void Start()
{
Connected();
}
// Update is called once per frame
void Update()
{
}
//ServerConnect
public void Connected() => PhotonNetwork.ConnectUsingSettings();
public override void OnConnected() => print("서버 연결 완료");
public override void OnDisconnected(DisconnectCause cause) => print("연결 종료");
//RoomCreate
public void CreateRoom() => CheckCreateRoom();
public override void OnCreatedRoom() => AfterCreateRoom();
public override void OnCreateRoomFailed(short returnCode, string message) => print("방 생성 실패");
void AfterCreateRoom(){
print("방 생성완료");
SceneManager.LoadScene("MenuScene");
}
void CheckCreateRoom(){
if(playerNickNameInput.text == ""){
print("닉네임을 입력해야합니다.");
}
else{
print("닉네임이 있음.");
PhotonNetwork.LocalPlayer.NickName = playerNickNameInput.text;
PhotonNetwork.CreateRoom("100",new RoomOptions { MaxPlayers = 2 });
}
}
//JoinRoom
public void JoinRoom() => CheckJoinRoom();
public override void OnJoinedRoom() => AfterJoinRoom();
public override void OnJoinRoomFailed(short returnCode, string message) => print("방 참가 실패");
void AfterJoinRoom(){
print("방 참가완료" + PhotonNetwork.CurrentRoom.Name);
SceneManager.LoadScene("MenuScene");
}
void CheckJoinRoom(){
if(playerNickNameInput.text == "" && roomCodeInput.text == ""){
print("InputField를 입력해야합니다.");
}
else{
print("닉네임이 있음.");
PhotonNetwork.LocalPlayer.NickName = playerNickNameInput.text;
PhotonNetwork.JoinRoom(roomCodeInput.text);
}
}
}
NetworkStatus.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using UnityEngine.UI;
using Photon.Realtime;
public class NetworkStatus : MonoBehaviour
{
[SerializeField] Text stateText;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
stateText.text = "서버상태 : " + PhotonNetwork.NetworkClientState.ToString();
print(stateText.text);
}
}
NetworkStatus를 분리해둔 이유는, NetworkManager스크립트 안에 버튼 기능을 구현해뒀더니, NetworkManager스크립트를 사용하는 모든 버튼에서도 State를 표시하는 텍스트를 참조하려고 하는 현상이 귀찮아서 그냥 분리했다....
'Develop > Unity' 카테고리의 다른 글
[Unity] '객체 지향 프로그래밍'이란 무엇인가 1(object-oriented programming)(OOP) (3) | 2024.05.07 |
---|---|
[Unity] 리스트의 정렬 검색 - 하이 우동 호텔! (2) | 2024.03.20 |
[Unity] 멀티 플레이를 위해 포톤을 연동하자!(Photon) - 0. 기본설정과 가입방법 (0) | 2023.12.09 |
[Unity] 로그라이크 맵 생성하기 (배열) (0) | 2023.11.29 |
[Unity] 오브젝트 풀링 (1) | 2023.11.22 |