게임 개발/유니티
커스텀 라이브러리를 만든 경험 - 2
- -
전 후 비교
이번에는 설명 이전에 바로 라이브러리를 사용하기 전과 후의 코드를 비교해 보자.
Before:
NetworkedSingleton 타입에 접근해서 해당 인스턴스의 이벤트에 네트워크 생명주기에 따른 구독이 필요한 경우가 많다.
이를 위해서는 다음과 같은 보일러플레이트 코드가 필요하다.
private void Awake()
{
InstanceFinder.ClientManager.OnClientConnectionState += ManageSubscription;
}
private void OnDestroy()
{
// 만약 구독해제 하고 싶다면?
InstanceFinder.ClientManager.OnClientConnectionState -= ManageSubscription;
}
private async void ManageSubscription(ClientConnectionStateArgs con)
{
switch (con.ConnectionState)
{
case LocalConnectionState.Started:
await UniTask.WaitUntil(() => MonsterStoreFinder.Instance is not null);
MonsterStoreFinder.Instance.OnPurchaseSuccessFx += PlayPurchaseSuccessSound;
MonsterStoreFinder.Instance.OnPurchaseFailureFx += PlayPurchaseFailureSound;
MonsterStoreFinder.Instance.OnRerollSuccessFx += PlayRerollSuccessSound;
MonsterStoreFinder.Instance.OnRerollFailureFx += PlayRerollFailureSound;
break;
case LocalConnectionState.Stopping:
if (MonsterStoreFinder.Instance is not null)
{
MonsterStoreFinder.Instance.OnPurchaseSuccessFx -= PlayPurchaseSuccessSound;
MonsterStoreFinder.Instance.OnPurchaseFailureFx -= PlayPurchaseFailureSound;
MonsterStoreFinder.Instance.OnRerollSuccessFx -= PlayRerollSuccessSound;
MonsterStoreFinder.Instance.OnRerollFailureFx -= PlayRerollFailureSound;
}
break;
}
}
After:
private void Awake()
{
_eventManager = MonsterStoreFinder.SubscribeEvent(
instance =>
{
instance.OnPurchaseSuccessFx += PlayPurchaseSuccessSound;
instance.OnPurchaseFailureFx += PlayPurchaseFailureSound;
instance.OnRerollSuccessFx += PlayRerollSuccessSound;
instance.OnRerollFailureFx += PlayRerollFailureSound;
instance.OnRerollFalldownFx += PlayRerollFalldownSound;
},
instance =>
{
instance.OnPurchaseSuccessFx -= PlayPurchaseSuccessSound;
instance.OnPurchaseFailureFx -= PlayPurchaseFailureSound;
instance.OnRerollSuccessFx -= PlayRerollSuccessSound;
instance.OnRerollFailureFx -= PlayRerollFailureSound;
instance.OnRerollFalldownFx -= PlayRerollFalldownSound;
});
}
private void OnDestroy()
{
// 해당 이벤트 자체의 구독 해제도 가능하다.
_eventManager.Unsubscribe();
}
- 보일러 플레이트 코드들이 많이 사라졌다.
- 또한 직관적이지 않은 부분(왜 Instance가 null 이 아닌 동안 wait를 해야 하는가? Client가 Connected 되면 자동으로 동시에 Instance가 생겨야 하는것 아닌가? -> 네트워크 연결 상태 관련 이벤트들이 약간 타이밍이 어긋나서 wait해주지 않으면 null reference 에러가 발생한다)을 가려준다.
다른 Variation으로도 옵션을 지정해서 사용 가능하다.
// 바리에이션 1. 구독만 하는 경우 (네트워크 생명주기 내내 구독해야 하는 경우)
var eventManager = MonsterStoreFinder.SubscribeEvent(instance =>
{
instance.OnRerollFailureFx += PlayReRollFailureVfx;
instance.OnRerollSuccessFx += PlayReRollSuccessVfx;
});
eventManager.Unsubscribe();
// 바리에이션 2. 구독, 구독해제, 구독 시작 조건, 구독과 구독 해제 타이밍 설정
var eventManager = MonsterStoreFinder.SubscribeEvent(
onSubscribe: instance =>
{
instance.OnRerollFailureFx += PlayReRollFailureVfx;
instance.OnRerollSuccessFx += PlayReRollSuccessVfx;
},
onUnsubscribe: instance =>
{
instance.OnRerollFailureFx -= PlayReRollFailureVfx;
instance.OnRerollSuccessFx -= PlayReRollSuccessVfx;
},
isSubscriptionReady: () =>
NetworkConditions.IsManagerReady<MonsterStoreFinder, MonsterStoreManager>(InstanceFinder.ClientManager.Connection),
subscriptionSettings: new SubscriptionSettings(
asServer: false,
targetConnection: null,
subscribeTiming: LocalConnectionState.Started,
unsubscribeTiming: LocalConnectionState.Stopping));
eventManager.Unsubscribe();
// 바리에이션 3. ConnectionEventManager 직접 생성, 및 수동 Subscribe.
var eventManager = new ConnectionEventManager<MonsterStoreFinder, MonsterStoreManager>(
() => NetworkConditions.IsManagerReady<MonsterStoreFinder, MonsterStoreManager>(),
instance =>
{
instance.OnRerollFailureFx += PlayReRollFailureVfx;
instance.OnRerollSuccessFx += PlayReRollSuccessVfx;
},
instance =>
{
instance.OnRerollFailureFx -= PlayReRollFailureVfx;
instance.OnRerollSuccessFx -= PlayReRollSuccessVfx;
},
SubscriptionSettings.StaticClient
)
.Subscribe();
eventManager.Unsubscribe();
이 외에도 너무 많다.
asServer 옵션을 true로 하고, target Connection을 지정하면 서버에서 실행되는 코드 일때, 원하는 클라이언트 소유의 네트워크 오브젝트에 이벤트 구독과 구독해제가 가능하다.
자주 쓰는 옵션들은 미리 만들어 놓았기 때문에 그냥 가져다 쓰면 된다.
예를들면
SubscriptionSettings.StaticClient
NetworkConditions.IsManagerReady<>()
만들고 나서 보니...
오히려 더 복잡해진것 같기도...?한데...
일단 가장 일반적인 경우(클라이언트가 connection 되어 있는 한 항상 존재하는 네트워크싱글톤의 이벤트에 구독할때)에는 더 간단해졌고, 논리적으로 쉽게 한눈에 이해 안되는 이상한 조건 설정을 안해도 된다.
또한 옵션을 지정하더라도, 일단 구조를 만들어 놓았기때문에 나중에 봤을때 이해가 안될일은 없을 것 같다.
만약 이렇게 구조화를 해 놓지 않았더라면 미묘하게 어긋나는 인스턴스 생성 타이밍과 커넥션 상태에 따른 이벤트 발생 타이밍에 대해 또 다시 고민하고 분석을 해야 할 것이다.
'게임 개발 > 유니티' 카테고리의 다른 글
상용 에셋의 버그를 찾아 고쳤더니 선물을 받았다. (0) | 2024.02.16 |
---|---|
커스텀 라이브러리를 만든 경험 - 1 (0) | 2024.02.16 |
HDRP 환경에서 TextMeshPro의 Distance field overlay 쉐이더 사용 (1) | 2024.01.25 |
[유니티 디자인패턴] 싱글톤 (0) | 2023.12.25 |
유니티 오브젝트 풀링 (0) | 2023.12.25 |
Contents
소중한 공감 감사합니다