Photon Pun2 사용과 더불어 오브젝트 풀링 사용
using Photon.Pun;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Pool;
[System.Serializable]
public class Pool
{
public GameObject Prefab;
public int MinSize;
public int MaxSize;
}
[RequireComponent(typeof(PhotonView))]
public class ObjectPoolManager : Singleton<ObjectPoolManager>
{
public List<Pool> Pools;
private Dictionary<string, ObjectPool<GameObject>> poolDic;
protected override void Awake()
{
base.Awake();
poolDic = new Dictionary<string, ObjectPool<GameObject>>();
foreach (var pool in Pools)
{
ObjectPool<GameObject> objectPool = new ObjectPool<GameObject>(
createFunc: () =>
{
GameObject newObj = PhotonNetwork.Instantiate("Items/"+pool.Prefab.name, Vector3.zero, Quaternion.identity);
newObj.SetActive(false);
return newObj;
},
actionOnGet: (obj) => obj.SetActive(true),
actionOnRelease: (obj) => obj.SetActive(false),
actionOnDestroy: (obj) => PhotonNetwork.Destroy(obj),
collectionCheck: false,
defaultCapacity: pool.MinSize,
maxSize: pool.MaxSize
);
poolDic.Add(pool.Prefab.name, objectPool);
}
}
public GameObject GetObject(string rcode)
{
if (poolDic.ContainsKey(rcode))
{
return poolDic[rcode].Get();
}
Debug.LogWarning("No pool with prefab name: " + rcode);
return null;
}
public void ReleaseObject(string rcode, GameObject obj)
{
if (poolDic.ContainsKey(rcode) && obj != null)
{
poolDic[rcode].Release(obj);
}
else
{
Debug.LogWarning("No pool with prefab name: " + rcode);
}
}
}
기존의 오브젝트풀링에서 `Photon Pun2` 서버를 사용하게 되니까 코드 수정이 약간 필요했다.
1. PhotonView 컴포넌트 추가
[RequireComponent(typeof(PhotonView))]
오브젝트가 모두의 눈에 보이게 동기화하려면 `PhotonView` 컴포넌트를 부착해야한다.
2. 오브젝트 생성
GameObject newObj = PhotonNetwork.Instantiate("Items/"+pool.Prefab.name, Vector3.zero, Quaternion.identity);
오브젝트를 생성할 때는 그냥 `Instantiate`보다는 `PhotonNetwork.Instantiate`를 사용해야 한다.
주의할 점은 그냥 `Instantiate`는 매개변수에 프리팹을 넣었지만, `PhotonNetwork.Instantiate`는 프리팹의 이름을 넣어야한다.
3. 오브젝트 파괴
PhotonNetwork.Destroy(obj)
오브젝트를 파괴할 때도 `PhotonNetwork`로!
Photon & 오브젝트 풀링 & 아이템 스폰 & 아이템 줍기 의 복합적인 문제
보통 포톤 서버를 사용할 때 아이템 스폰은 오브젝트를 `PhotonNetwork.Instantiate`로 생성하고, `PhotonNetwork.Destroy`로 파괴한다.
그런데 아이템이 점차 많아질 수록 최적화가 필요했기 때문에 오브젝트 풀링을 사용했다.
다만 오브젝트 풀링은 파괴가 아니라 `SetActive` `True` `False`로 관리를 하다보니 문제가 생겼다.
`PhotonNetwork.Instantiate`과 `PhotonNetwork.Destroy`를 사용하면 모든 클라이언트들 눈에 아이템이 생기고 사라지는 것이 동기화가 잘 된다.
그런데 `SetActive` `True` `False`는 동기화를 직접 설정해줘야 한다.
그래서 아래와 같은 흐름으로 코드를 작성하여 문제를 해결했다.
1. 아이템 주울 때 모든 클라이언트에게 알려주기
photonView.RPC("OnPickedUp", RpcTarget.All);
2. 아이템 스폰할 때 모든 클라이언트에게 알려주기
[PunRPC]
public void OnPickedUp()
{
ObjectPoolManager.Instance.ReleaseObject(Item.Rcode, gameObject);
Spawner.photonView.RPC("SpawnItem", RpcTarget.All);
}
[PunRPC]
public void SpawnItem()
{
if (!PhotonNetwork.IsMasterClient)
return;
Vector3 spawnPos = ReturnRandPos();
Pool pool = ReturnRandPool();
if (pool != null)
{
string poolName = pool.Prefab.name;
GameObject spawnedObject = ObjectPoolManager.Instance.GetObject(poolName);
if (spawnedObject != null)
{
spawnedObject.transform.position = spawnPos;
var itemPickUp = spawnedObject.GetComponent<ItemPickUp>();
itemPickUp.Spawner = this;
}
else
{
Debug.LogWarning("Failed to get object from pool: " + poolName);
}
}
}
3. 아이템 스폰은 마스터 클라이언트가 해주기
if (!PhotonNetwork.IsMasterClient)
return;
스폰을 해줄 때 마스터 클라이언트인지 체크를 해준다.
'스파르타 게임개발종합반(Unity) > TIL - 본캠프 매일 공부 기록' 카테고리의 다른 글
2024.06.28 TIL - 유니티 렌더링 파이프라인(URP - Unity Rendering Pipeline) (0) | 2024.06.28 |
---|---|
2024.06.26 TIL - 아이템 오브젝트가 SetActive(false)일 때 코루틴 사용 (0) | 2024.06.27 |
2024.06.24 TIL - Photon Pun2 (0) | 2024.06.24 |
2024.06.21 TIL - 이벤트 구독 취소의 중요성 (0) | 2024.06.21 |
2024.06.20 TIL - 유니티 아이소메트릭(Isometric) 타일맵(Tilemap)에서 오브젝트 랜덤 생성하기 (2) | 2024.06.20 |
댓글