[Unity][멀티플레이] 게임에서 충돌 시 동기화 문제
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