Lapi는 2D RPG를 제작해보고자 하여 시작한 프로젝트다. 다른 RPG와 비교해서 특별한 것을 보여주고 싶은 마음은 없지만, 다른 RPG에서 제공하는 기본적인 기능들을 구현해보려고 했다. 그리고 구현한 기능들을 하나하나 정리하면 누군가에게 도움이 되지 않을까라는 마음으로 정리하고자 한다.
Lapi는 인벤토리, 장비, 스킬, 퀘스트 등 다양한 UI를 제공한다. 이들은 모두 사용자가 보고 이해하기 쉽도록 제작해야 한다. 그리고 각각은 독립적으로 테스트하기 좋게 만들어져야 하기 때문에 사용자에게 보여지는 UI와 서비스를 분리하기로 결정했다.
서비스 로케이터를 잘 모르겠다면 여기를 참고하세요.
Lapi에서는 서비스마다 다르지만 씬을 넘나들면서 필요한 서비스들도 존재한다.
유니티에서는 DontDestroyOnLoad와 Singleton을 활용하면 씬을 넘나들면서 참조해야 하는 서비스를 게임 내내 유지시킬 수 있다. 하지만 Singleton은 나름의 문제점도 많이 가지고 있다.
그래서 Singleton을 덜 사용해보고자 하는 취지에서 서비스 로케이터를 사용했다. 그렇다고 서비스 로케이터가 Singleton보다 압도적으로 좋다는 것은 아니다.
다만 전역적으로 존재하면서 씬을 넘나들면서 사용할 수 있다는 장점 이외에도 서비스 로케이터에서 각 서비스에 인터페이스로 접근하기 때문에 서비스를 다양한 방법으로 제공할 수 있다는 장점이 있다.
서비스 로케이터가 기본적으로 동작하는 방식은 다음과 같다.
예를 들어 로컬 인벤토리를 사용하던 게임에서 클라우드 인벤토리로 변경한다고 하더라도 인터페이스에 의존하는 덕분에 클라이언트의 코드는 변경될 이유가 전혀 없다.

public static class ServiceLocator
{
private static Dictionary<Type, object> m_services = new();
public static IDictionary<Type, object> Services => m_services;
// 없어도 무방하지만 동적으로 서비스를 갈아끼우는 구조가 아니라면 괜찮은 것 같다.
public static void Initialize()
{
// 위치시키고 싶은 서비스를 각 구현체에 맞춰 초기화를 할 수 있다.
// Lapi는 싱글플레이 게임이므로 로컬에서 데이터를 관리한다.
Register<IEXPService>(new LocalEXPService());
Register<IUserService>(new LocalUserService());
Register<IInventoryService>(new LocalInventoryService());
Register<IItemDataService>(new LocalItemDataService());
Register<IEquipmentService>(new LocalEquipmentService());
Register<ISkillService>(new LocalSkillService());
Register<IKeyService>(new LocalKeyService());
Register<IShortcutService>(new LocalShortcutService());
Register<INPCService>(new LocalNPCService());
Register<IDialogueService>(new LocalDialogueService());
Register<IQuestService>(new LocalQuestService());
}
// 서비스를 등록할 때 사용한다.
public static void Register<T>(T service)
{
if(!Services.ContainsKey(typeof(T)))
{
Services.TryAdd(typeof(T), service);
}
}
// 서비스를 참조할 때 사용한다.
public static T Get<T>()
{
if (!Services.TryGetValue(typeof(T), out var service))
{
throw new Exception($"{typeof(T)} 서비스가 존재하지 않습니다.");
}
else
{
return (T)service;
}
}
}
서비스 로케이터를 통해서 Lapi 및 게임에서 사용할 전반적인 서비스를 모두 관리할 예정이다.
내가 만든 코드가 정답은 아니니 보완할 부분들은 더 보완해서 사용하면 좋을 것 같다.