1. 구현 동작
2. 문제점
3. 해결과정
    □ 어디서 문제가 발생하는가?
    □ GetHashCode()로 해결가능
4. 해결 방법
    □ PhonView의 IsMine
    □ 최종 코드
5. 결론

 

📝 1. 구현 중인 동작

  zep처럼 특정 구역에 들어가면, 오른쪽에 카메라가 켜고 꺼지는 동작을 구현중.

  내가 플레이하는 캐릭터 기준으로, 특정구역 들어갔을 때 사람이 있으면 사람 수 대로 오른쪽에 카메라가 생성되고, 

특정구역에 나갔을 때 카메라가 전부 삭제되어야 한다.

 

📝 2. 문제

  특정 오브젝트에서 모든 플레이어의 충돌을 감지하여 , 내가 조종하는 캐릭터가 아닌 다른 사람의 캐릭터가 오브젝트에 충돌할 시, 내 화면에도 UI가 켜지고 꺼지는 것을 확인했다. 

 

📝 3. 해결과정 

1. 해당문제가 발생하는 코드

  현재 "특정구역"에 Conference라는 스크립트를 넣어 충돌을 감지하고 있다.

public class ConferenceBox : MonoBehaviour
{
    [SerializeField]
    private string _chanelName = "ConferenceRoom";

    private void OnTriggerEnter2D(Collider2D collision)
    {
        // 플레이어가 들어오면 
        if (collision.gameObject.layer == LayerManger.Instnace.PlayerLayerNum) 
        {
            // Ui 켜기
            UiManager.Instnace._conferenceCameraPanel.SetActive(true);

            // Agora - 조인
            VideoChatManger.Instnace.Join(_chanelName);        
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {

        // 플레이어가 들어오면 
        if (collision.gameObject.layer == LayerManger.Instnace.PlayerLayerNum)
        {
            // Ui 끄기
            UiManager.Instnace._conferenceCameraPanel.SetActive(false);

            // Agora - 떠나기
            VideoChatManger.Instnace.Leave();
        }
    }
}

 

  여기서 하나 생각 못한 부분이 있다.

포톤에서 플레이어를 인스턴스화할 때 같은 프리팹으로 한다. 즉 생성되는 모든 플레이어는 같은 Player 레이어를 가지고 있다.

 

 

  같은 프리팹을 사용해서 인스턴스화하는 중.......

 

  즉 다른 사람(LayerMask가 Player)이 '특정구역'의 충돌 조건에 만족하는 것이다. 

 

🔖 내가 원했던 동작

  충돌을 할 때, 내가 플레이하는 캐릭터가 충돌 했을 때를 검사하고싶다.

내가 플레이 하는 캐릭터가 '특정구역'에 들어갔을 때, 나갔을 때에 조건을 검사해야 한다.

 

2. GetInstance()로 검사하면 되지 않을까?

  PhotonInstance로 생성한 오브젝트의 GetHashCode와, 충돌 시 매개변수로 들어온 충돌체의 GetHashCode를 검사해서 같으면, 내가 플레이하는 캐릭터를 알 수 있지 않을까?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ConferenceBox : MonoBehaviour
{
    [SerializeField]
    private string _chanelName = "ConferenceRoom";

    private void OnTriggerEnter2D(Collider2D collision)
    {
        var hash = PhotonManager.Instnace.photonPlayer.GetHashCode();

        // 플레이어가 들어오면 
        if (collision.gameObject.layer == LayerManger.Instnace.PlayerLayerNum
            && hash == collision.gameObject.GetHashCode() ) 
        {
            // Ui 켜기
            UiManager.Instnace._conferenceCameraPanel.SetActive(true);

            // Agora - 조인
            VideoChatManger.Instnace.Join(_chanelName);        
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        var hash = PhotonManager.Instnace.photonPlayer.GetHashCode();

        // 플레이어가 들어오면 
        if (collision.gameObject.layer == LayerManger.Instnace.PlayerLayerNum
            && hash == collision.gameObject.GetHashCode() )
        {
            // Ui 끄기
            UiManager.Instnace._conferenceCameraPanel.SetActive(false);

            // Agora - 떠나기
            VideoChatManger.Instnace.Leave();
        }
    }
}

  원하는 대로 잘 동작한다.

PotonManger의 player는 항상 로컬 플레이어 오브젝트를 가지고 있기 때문에, 충돌체가 내가 플레이하고 있는 오브젝트인지 
(로컬 인지) , 다른 사람의 오브젝트인지 (리모트 인지) 검사할 수 있다. 

 

📝 4. 해결방법

  GetHashCode()를 사용하지 않고도 해결할 수 있다.

  내가 원하는 동작은 즉 "충돌체가 로컬 오브젝트"인지 검사해야 한다.

→ 로컬 오브젝트 인지 알 수 있는 방법은 PhotonView의 IsMine 사용하면 된다.

  플레이어 오브젝트는 동기화를 위해서 
PhotonView, Photon Trasform View, Photon Animator View의 컴포넌트를 추가해 놓은 상태이다 

  PhotonNetwork.Instantiate() 로 오브젝트를 생성하면, 로컬인지 리모트인지에 관한 정보가 Photon View에 저장된다.

(포톤이 알아서 정보를 저장해 준다 고마워 따봉포톤아!)

           로컬이면 IsMine이 true로 설정

           리모트이면 IsMine이 false로 설정 

 

PhotonView의 IsMine이 true일 때만 충돌한다! 

 

- 최종 코드

using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ConferenceBox : MonoBehaviour
{
    [SerializeField]
    private string _chanelName = "ConferenceRoom";

    // 플레이어의 포톤 정보 가져오기 
    [SerializeField]
    private PhotonView _playerView;

    private void OnTriggerEnter2D(Collider2D collision)
    {
        _playerView = collision.GetComponent<PhotonView>();

        // 플레이어가 들어오면 + 로컬 플레이어면 
        if (collision.gameObject.layer == LayerManger.Instnace.PlayerLayerNum
            && _playerView.IsMine ) 
        {
            // Ui 켜기
            UiManager.Instnace._conferenceCameraPanel.SetActive(true);

            // Agora - 조인
            VideoChatManger.Instnace.Join(_chanelName);        
        }
    }

    private void OnTriggerExit2D(Collider2D collision)
    {
        _playerView = collision.GetComponent<PhotonView>();

        // 플레이어가 들어오면 + 로컬플레이어면
        if (collision.gameObject.layer == LayerManger.Instnace.PlayerLayerNum
            && _playerView.IsMine)
        {
            // Ui 끄기
            UiManager.Instnace._conferenceCameraPanel.SetActive(false);

            // Agora - 떠나기
            VideoChatManger.Instnace.Leave();
        }
    }
}

 

 

- 로컬오브젝트의 충돌만 검사해서 Ui를 끄고켬!

 

 

 

📝 5. 결론

멀티플레이 게임을 만들 때 충돌검사를 할 시 로컬인지 리모트인지 검사하는 것이 중요하다는 것을 깨달았다.

또한 충돌처리가 있는 부분마다 검사해줘야 한다 생각하니 멀티게임이 왜 만들기 까다로운지 알게 되었다

 


스파르타-유니티 개인과제 깃허브

https://github.com/kimYouChae/Sparta_Metaverse

 

GitHub - kimYouChae/Sparta_Metaverse

Contribute to kimYouChae/Sparta_Metaverse development by creating an account on GitHub.

github.com

 

+ Recent posts