Carrot
본문 바로가기
Unity/멋쟁이사자처럼 부트캠프

[멋쟁이사자처럼부트캠프] 유니티 게임 개발 5기(110일차/Final Project) - 오브젝트풀 멀티 연동

by 독기품은토끼 2025. 11. 4.
✅ 오늘의 백로그
1. 오브젝트 풀 멀티 연동

1. 오브젝트풀 연동

오늘은 오브젝트풀을 연동시켜야 하는데

찾아보니까 Fusion에서 오브젝트풀 자체를 제공하고 있는 것을 확인하였다.

 

 

Fusion 2 - Fusion 객체 폴링 | Photon Engine

Fusion 객체 폴링 샘플은 NetworkRunner가 생성하는 모든 NetworkObject에 대해 새 프리팹을 인스턴스화하지 않고도 객체를 풀링 하는 방법을 보여줍니다. 이를 위해 맞춤형 INetworkObjectProvider 구현을 사용

doc.photonengine.com

 

 

내가 이 문서를 보고 이해한 내용은..

 

어제 스폰매니저를 구현했을 때 처럼

네트워크가 접목되면 instantiate, destroy를 사용할 수 없기때문에

 

INetworkObjectProvider 라는 인터페이스를 활용해서

 

오브젝트 활성화는 AcquirePrefabInstance 함수를,

오브젝트 비활성화 및 리턴은 ReleaseInstance 함수를 사용해주어야 한다.

 

이렇게 오브젝트풀을 재활용할 수 있도록 만들었다면

Network Runner가 이 사실을 알아야 하므로

Network Runner가 StartGame() 함수를 호출할 때 INetworkObjectProvider 해당 인터페이스를 인자로 전달해주어야 한다.

 

이렇게 인데.. 맞는지 한번 트라이해보좌!

 

1. Register 함수

기존에 프레임 드랍 방지를 위해서

Get하기 전에 미리 큐를 생성해놓기 위해 만들어둔 함수이다.

 

이걸 멀티플레이로 연동하려면 

- 프리팹에 Network Object 컴포넌트가 붙어있을 것

- 컴포넌트가 붙어있다면 NetworkId를 기준으로 추가하기

 

 

해보다가 잘 안돼서 다시 확인해보니

저런 주석문이 있었다.

 

 

Fusion 2 - NetworkObjectProvider | Photon Engine

Spawned가 호출되면, StartGame()의 StartArgs에서 전달된 INetworkObjectProvider가 연결될 GameObject를 가져오거나 생성하는 작업을 수행합니다. INetworkObjectProvider의 기본 구현체는 NetworkObjec

doc.photonengine.com

 

이 클래스는..

 

Spawned가 호출되면, StartGame() StartArgs에서 전달된 INetworkObjectProvider가 연결될 GameObject를 가져오거나 생성하는 작업을 수행합니다.

 

라고 설명되어있다.

 

아 그러니까 INetworkObjectProvider로 인터페이스를 만들면

프로바이더가 중간에 껴서 동작되는 것 같다..

 

결론은 NetworkObjectProvider 를 구현해주어야 오브젝트풀이 작동된다는 것 같음 ㅠ

 

 

 

그래서 우선 INetworkRunnerCallbacks을 상속받은 스크립트에서

StartGame() 메서드 안에 프로바이더를 장착해주었고

 

/// <summary>
/// Fusion 2용 프로바이더
/// 기본 프로바이더를 상속하고 풀의 Get/Return 메서드 연결
/// </summary>
public sealed class FusionPoolProvider : NetworkObjectProviderDefault
{
    readonly ObjectPoolManager _pool;

    public FusionPoolProvider(ObjectPoolManager pool)
    {
        _pool = pool;
    }

    // Fusion이 네트워크 스폰을 요청할 때 호출됨
    protected override NetworkObject InstantiatePrefab(NetworkRunner runner, NetworkObject prefab)
    {
        // 풀에서 꺼내기
        var pooled = _pool.Get(prefab.gameObject);

        // 위치/회전/활성화는 Runner.Spawn 경로에서 처리할것
        return pooled.GetComponent<NetworkObject>();
    }

    // Fusion이 네트워크 디스폰을 요청할 때 호출
    protected override void DestroyPrefabInstance(NetworkRunner runner, NetworkPrefabId prefabId, NetworkObject instance)
    {
        if (instance)
            _pool.Return(instance.gameObject);
    }
}

 

프로바이더 클래스에서

오브젝트풀을 받아와 프리팹이 생성/삭제 되도록 연결해주었다.

 

그리고 천우인은 비처럼 쏟아지는 녀석이기 때문에

동기화 작업을 해주지 않았다.

워낙 빠르게 흐르기도 하고 양도 많아서 플레이어끼리 비교할 대상이 안될 것 같고

플레이어끼리 같을 필요도 없기 때문에!!

 

플레이어끼리 위치가 같아야하는 흑기 이상현상을 토대로 테스트해보려고 한다.

 

 

그래서 흑기 스크립트에서

기존에 검은 구체를 로컬로 생성하는 부분을

네트워크로 생성하도록 변경해주었다.

 

 

잘 되겠지를 희망에 품으며 게임을 시작해보았으나ㅋ

역시나! 에러 투성이다.

 

에러를 해석해보니

AcquirePrefabInstance가 ObjectPoolManager.Get(prefab) 안에서 null 값이라 프리팹 스폰이 실패된 것 같다.

 

Get(prefab) 안에서 null이 일어나려면..

Register를 호출해서 등록이 안됐다는 뜻인데..

 

코루틴으로 딜레이를 줘도 계속 똑같은 반응이다.

그래서 어느 프리팹이 그렇게 할당이 안되는가 로그를 찍어봤는데

 

 

여기가 비어있었음 ^^... 하아 ㅠㅠ ㅋㅋㅋㅋㅋ 진짜 장난하노ㅑ!!

 

 

구체를 연결해주고 실행해보니

구체 위치는 똑같아 보이긴 하는데...

이젠 크기가 다른 문제 발생 ㅋㅋㅋㅋ아아악!! 아아악!!! 🚨 위잉 위잉 힘들면 울리는 사이렌 등장 위이이잉!!!!!!!!!!!!!!

 

 

다행히 이건 손쉽게 해결 가능했다

Network Transform에서 크게 동기화를 해주는 게 있었따 ㅠㅠ

 

 

 

히히 똑같은 위치, 똑같은 크기로 동기화 완료!!

 

 

그러나 무시무시한 문제점이 하나 있었으니..

아까 에러 잡겠다고 로그를 엄청 남겨놔서 발견하게된 문제점인데 ㅠ

 

풀매니저가 Network Object 컴포넌트를 갖고 있는 모든 애들에게 다 접근하고있다..

get함수로 갖고오는 애는 DarkAura 뿐인데 왜 Player랑 Dark Sphere을 갖고오는 걸까..?

 

 

위에서 연결한 프로바이더 때문이었다..!

이 작업을 하지 않아도 멀티 연동이 되기 때문에 이 로직을 삭제해주었더니 해결되었다.