해당 글은 유튜버 " 고라니TV - 게임개발 채널" 님의 "유니티 포톤PUN2 서버 개발" 재생목록을 참고하여 작성하였습니다.

https://www.youtube.com/watch?v=mPCNTi3Booo&list=PL3KKSXoBRRW3YE4UMnRH762vOhSHLdnpK

 

 

[ 환경 세팅 ]

1. 우선 https://www.photonengine.com/ko-kr 에 접속하여 회원가입/로그인을 한다.

2. 오른쪽 위 [ 관리 화면으로 이동 ] - [ 새 어플리케이션 만들기 ] 를 클릭한다.

3. Photon 종류는 [ Pun ] 으로 설정하고, 어플리케이션의 이름과 설명을 작성한 뒤 [ 작성하기 ] 를 클릭한다.

4. 어플리케이션 ID를 복사하고, Unity Asset Store에서 Photon Pun 2를 다운로드 후 import 해준다.

 

5. 복사한 어플리케이션 ID를 [ Assets ] - [ Photon ] - [ PhotonUnityNetworking ] - [ Resources ] - [ Photon Server Settings ]

    - [ Server/Cloud Settings ] 의 [ App Id PUN ] 에 붙여넣는다.

 

[ Photon 기능 함수 ]

Photon 기능 함수
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun; // MonoBehaviourPunCallbacks를 상속 받기 위해 추가
using Photon.Realtime; // MonoBehaviourPunCallbacks를 상속 받기 위해 추가

public class NetworkManager : MonoBehaviourPunCallbacks // MonoBehaviour이 아닌 MonoBehaviourPunCallbacks를 상속 받는다.
{
    public Text StatusText;
    public InputField roomInput, NickNameInput;
      
    void Awake() => Screen.SetResolution(960, 540, false);
    void Update() => StatusText.text = PhotonNetwork.NetworkClientState.ToString(); // PhotonNetwork.NetworkClientState.ToString()는 현재 상태를 문자열로 반환
    
    public void Connect() => PhotonNetwork.ConnectUsingSettings(); // Photon Online Server에 접속
    public override void OnConnectedToMaster() // Call back 함수
    {
        print("서버접속완료");
        PhotonNetwork.LocalPlayer.NickName = NickNameInput.text;
    }

    public void Disconnect() => PhotonNetwork.Disconnect(); //  Photon Online Server와의 연결 끊기
    public override void OnDisconnected(DisconnectCause cause) => print("연결끊김"); // Call back 함수

    public void JoinLobby() => PhotonNetwork.JoinLobby(); // 로비에 접속
    public override void OnJoinedLobby() => print("로비접속완료"); // Call back 함수

    public void CreateRoom() => PhotonNetwork.CreateRoom(roomInput.text, new RoomOptions { MaxPlayers = 2 }); // 방 생성 (방 이름, 최대 플레이어 수, 비공개 지정 가능)
    public override void OnCreatedRoom() => print("방만들기완료"); // Call back 함수

    public void JoinRoom() => PhotonNetwork.JoinRoom(roomInput.text); // 방 참가 (방 이름으로 입장 가능)
    public override void OnJoinedRoom() => print("방참가완료"); // Call back 함수

    public void JoinOrCreateRoom() => PhotonNetwork.JoinOrCreateRoom(roomInput.text, new RoomOptions { MaxPlayers = 2 }, null); // 방 참가, 방이 없으면 생성후 참가

    public void JoinRandomRoom() => PhotonNetwork.JoinRandomRoom(); // 방 랜덤 참가

    public void LeaveRoom() => PhotonNetwork.LeaveRoom(); // 방 떠나기
 
    public override void OnCreateRoomFailed(short returnCode, string message) => print("방만들기실패"); // Call back 함수

    public override void OnJoinRoomFailed(short returnCode, string message) => print("방참가실패"); // Call back 함수

    public override void OnJoinRandomFailed(short returnCode, string message) => print("방랜덤참가실패"); // Call back 함수

    // [ Script Component ] - [ 오른쪽 마우스 ] - [ 정보 ] 를 통해 실행 가능
    [ContextMenu("정보")]
    void Info()
    {
        if (PhotonNetwork.InRoom)
        {
            print("현재 방 이름 : " + PhotonNetwork.CurrentRoom.Name);
            print("현재 방 인원수 : " + PhotonNetwork.CurrentRoom.PlayerCount);
            print("현재 방 최대인원수 : " + PhotonNetwork.CurrentRoom.MaxPlayers);

            string playerStr = "방에 있는 플레이어 목록 : ";
            for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++) playerStr += PhotonNetwork.PlayerList[i].NickName + ", ";
            print(playerStr);
        }
        else
        {
            print("접속한 인원 수 : " + PhotonNetwork.CountOfPlayers);
            print("방 개수 : " + PhotonNetwork.CountOfRooms);
            print("모든 방에 있는 인원 수 : " + PhotonNetwork.CountOfPlayersInRooms);
            print("로비에 있는지? : " + PhotonNetwork.InLobby);
            print("연결됐는지? : " + PhotonNetwork.IsConnected);
        }
    }
}​

 

[ RPC란? ]

- Player의 움직임을 동기화하기 위해서는 "Photon View"와 "Photon Transform View" Script를 Component로 추가해준다.

 ~> "Photon Transform View" Script Component 의 Synchronize Options 에서 무엇을 동기화할 것인지 선택할 수 있다.

       (Position, Rotation, Scale 에 관한 동기화 선택이 가능하다.)

 ~> "Photon View" Script Component 의 Observed Components에 "Photon Transform View" Script Component 를

      드래그 앤 드롭으로 연결한다. (이는 "Photon Transform View" Script Component 를 관찰하여 동기화 한다는 것)

 ~> 동기화는 "Photon View" Script Component 의 Controlled locally가 true인 경우에만 가능하다.

      (Controlled locally는 PhotonView PV; PV.IsMine 으로 확인이 가능하다.)

- Position, Rotation, Scale 를 제외한 나머지는 어떻게 동기화 시킬까?

 ~> RPC 함수를 통해 동기화 시켜야 한다.

RPC 함수 선언 및 사용 예제
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;

public class PlayerScript : MonoBehaviourPunCallbacks
{
    public PhotonView PV;
    public SpriteRenderer SR;

    void Update()
    {
        if (PV.IsMine)
        {
            float axis = Input.GetAxisRaw("Horizontal");
            transform.Translate(new Vector3(axis * Time.deltaTime * 7, 0, 0));

            // RPC 함수 호출 (실행하고자 하는 함수 이름, 타겟, 인자)
            // RPCTarget.All은 그 즉시 호출되어 사라지지만, AllBuffered는 재접속될때 호출된다.
            if (axis != 0) PV.RPC("FlipXRPC", RpcTarget.AllBuffered, axis);
        }
    }

    // RPC 함수 선언
    [PunRPC]
    void FlipXRPC(float axis)
    {
        SR.flipX = axis == -1;
    }
}​

[ 애니매이션 동기화 ]

- Animation을 동기화하기 위해서는 "Photon View"와 "Photon Animator View" Script를 Component로 추가해준다.

 ~> "Photon Animator View" Script Component 의 Synchronize Layer Weights 와 Synchronize Parameters 선택지 중

      "Disabled" 는 "사용 안 함", "Discrete" 는 "On/Off시 호출", "Continuous" 는 "수시로 호출" 에 해당한다.

 ~> "Photon View" Script Component 의 Observed Components에 "Photon Animator View" Script Component 를

      드래그 앤 드롭으로 연결한다. (이는 "Photon Animator View" Script Component 를 관찰하여 동기화 한다는 것)

 

[ 변수 동기화 ]

- 변수를 동기화하기 위해서는 MonoBehaviourPunCallbacks 뿐만이 아닌 IPunObservable 도 상속 받는다.

 ~> IPunObservable 를 상속 받는 경우 OnPhotonSerializeView 인터페이스 구현이 필수다.

 ~> 동기화는 PhotonView를 반드시 거쳐가야 하기 때문에 위의 Script를  "Photon View" Script Component 의 Observed

      Components에 드래그 앤 드롭으로 연결한다.

변수 동기화 예제
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;

public class PlayerScript : MonoBehaviourPunCallbacks, IPunObservable // IPunObservable을 상속 받는다.
{
    // ...
    
    public Text txt;

    // ...

    [ContextMenu("더하기")]
    public void Plus() => txt.text = (int.Parse(txt.text) + 1).ToString();

    // OnPhotonSerializeView 인터페이스 구현
    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.IsWriting) stream.SendNext(txt.text); // Server에 보낼때
        else txt.text = (string)stream.ReceiveNext(); // Server로부터 받을때
    }
}​

 

 

+ Recent posts