본문 바로가기
Project/<teamECHO> 4-1

[문제해결/PJ] PhotonView Character Customizing 동기화 문제2

by 왹져박사 2024. 7. 19.

전에 올렸던 해결 방법에서 또 다른 문제가 발생하여 Photon 프로토콜에 대하여 공부해 보았다. 

 

현재 문제 대상인 Player prefab은 포톤 서버가 연결된 후에 커스텀을 변경시켜야 한다. 

이렇게 씬에 배치된 동적인 오브젝트를 변경시켜야 할 때는 IPunObservable를 상속받아 정보를 전달해 주어야 한다고 한다. 

 

using ExitGames.Client.Photon;
using ExitGames.Client.Photon.StructWrapping;
using Photon.Pun;
using Photon.Realtime;
using SeongMin;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using TMPro;
using UnityEngine;

namespace NHR
{
    public class PlayerController : MonoBehaviourPunCallbacks, IPunObservable
    {

        [Header("캐릭터 배열")]
        public Character[] characters;

        [Header("현재 캐릭터 정보")]
        public Character nowCharacter;
        public int nowCharacterID;

        public static PlayerController localPlayer;

        private void Awake()
        {
            if(photonView.IsMine)
            {
                GameDB.Instance.playerController = this;
                GameManager.Instance.lobbySceneManager.playerController = this;
                SeongMin.UIManager.Instance.robbySceneMenu.customPlayer.playerController = this;
            }
        }
        private void Start()
        {
		//인포 내용 할당
            if(photonView.IsMine)
            {
                localPlayer = this;
                Debug.LogFormat("<color=green>PlayerID : {0}</color>", InfoManager.Instance.PlayerInfo.nowCharacterId);
                this.nowCharacterID = InfoManager.Instance.PlayerInfo.nowCharacterId;

                this.characters[nowCharacterID].gameObject.SetActive(true);
                this.nowCharacter = this.characters[nowCharacterID];
                SeongMin.GameDB.Instance.playerMission.currentRunnerCharacrer = this.characters[nowCharacterID];
                
                this.UpdateCharacter(nowCharacterID);
            }
        }
        
	//캐릭터 커스텀 업데이트
        public void UpdateCharacter(int id)
        {
            Debug.Log("UpdateCharacter");
            photonView.RPC("UpdateCharacterRPC", RpcTarget.OthersBuffered, id);
            this.ApplyCharacter(id);
        }
        
	//캐릭터 부활
        public void CharacterOn()
        {
            nowCharacter.gameObject.SetActive(true);
            SeongMin.GameManager.Instance.playerManager.humanMovement.isDie = true;
        }

	//네트워크 전달
        [PunRPC]
        public void UpdateCharacterRPC(int id)
        {
            Debug.Log("UpdateCharacterRPC");

            this.nowCharacterID = id;
            this.ApplyCharacter(id);
        }
		
	//커스텀 적용
        public void ApplyCharacter(int id)
        {
            if(this.nowCharacter != null)
            {
                this.nowCharacter.gameObject.SetActive(false);
            }
            this.nowCharacter = this.characters[id];
            this.nowCharacterID = id;

            if (this.nowCharacter != null)
            {
                this.nowCharacter.gameObject.SetActive(true);
            }
            SeongMin.GameDB.Instance.playerMission.currentRunnerCharacrer = this.characters[id];
        }

	//IPunObservable 상속 구현
        public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
        {

        }
    }
}

 

이후에 Photon을 더 공부하며 알았지만, 처음에 RPC 호출이 불안정하게 되었던 이유는 순서가 정해지지 않은 채로 RPC를 호출하여 서로 꼬였던 것이다. 아래 사진과 같은 많은 RPC들이!

 

이를 해결하려면 Player의 RPC를 한 스크립트에서 관리하며 상속받은 OnPhotonSerializeView 메서드에서 stream을 통해 호출 순서를 정리해주어야 한다. 

 

포톤서버는 처음에 너무 어려웠지만 문제에 직면하고 배울수록 재밌다...!

포톤 공식 문서 보면 기존 생각보다 다양한 기능들이 많아서 혼자서라도 공부해보려 한다.