4. 첫 번째 스크립트

프레임워크 전체를 여는 단 하나의 패턴과, 가장 먼저 쓰게 될 다섯 가지 서비스의 복사-붙여넣기 스니펫.

4.1 빠른 시작

새 C# 스크립트를 만들어 아래 내용을 붙여 넣고, 아무 씬의 아무 GameObject에나 올린 뒤 Play를 누르세요:

using CommonGameSystem.Core;
using UnityEngine;

public class HelloCgs : MonoBehaviour
{
    private void Start()
    {
        var scheduler = ServiceLocator.Resolve<IScheduler>();
        var tween     = ServiceLocator.Resolve<ITweenService>();

        scheduler.After(1f, () => Debug.Log("One second after Play."));

        tween.To(1f, 2f, 0.5f,
            scale => transform.localScale = Vector3.one * scale,
            EaseType.OutBack);
    }
}

오브젝트가 탄력 있는 오버슈트와 함께 두 배 크기로 튀어 오르고, 1초 뒤 메시지가 나타납니다. 없는 것에 주목하세요: 매니저 프리팹도, 초기화 씬도, 셋업 컴포넌트도 없습니다. 부트스트랩이 여러분의 Start가 실행되기 전에 23개 서비스를 모두 등록했습니다.

4.2 서비스 해석(resolve)의 동작 방식

모든 CGS 서비스는 같은 방식으로 접근합니다: 서비스 로케이터에 필요한 인터페이스를 요청하세요.

var save = ServiceLocator.Resolve<ISaveService>();

세 가지 규칙이 이것을 빠르고 안전하게 유지합니다:

  • 일찍 해석하고, 결과를 캐시하세요. 서비스는 첫 씬이 로드되기 전에 등록되므로 AwakeStart 모두 해석하기 안전한 위치입니다. 참조를 필드에 저장해 재사용하세요 — 절대 Update 안에서 Resolve를 호출하지 마세요.
  • 없는 서비스는 예외를 던집니다. 해당 인터페이스에 등록된 것이 없으면 Resolve<T>()는 명확한 예외를 던집니다. 부드러운 확인이 필요하면 ServiceLocator.TryResolve(out T service) 또는 ServiceLocator.IsRegistered<T>()를 사용하세요.
  • 무엇이든 교체할 수 있습니다. ServiceLocator.Replace<T>(instance)는 언제든 자체 구현이나 아무것도 하지 않는 널 버전으로 바꿔 넣습니다(1장 1.4절).

전형적인 소비자는 이런 모습입니다:

public class GameHud : MonoBehaviour
{
    private ISaveService _save;   // cached once, used many times

    private void Awake()
    {
        _save = ServiceLocator.Resolve<ISaveService>();
    }
}

4.3 가장 먼저 쓰게 될 다섯 가지 서비스

아래 각 스니펫은 4.1절의 using 선언 아래, MonoBehaviour 안에서 실행됩니다.

저장과 로드

직렬화 가능한 클래스라면 무엇이든 세이브 파일이 될 수 있습니다. 쓰기는 원자적입니다 — 저장 도중 크래시가 나도 이전 파일은 결코 손상되지 않습니다. 전체 레퍼런스: Save/Load.

[System.Serializable]
public class PlayerData { public int Level; public float Health; }

var save = ServiceLocator.Resolve<ISaveService>();
save.Save("slot0", new PlayerData { Level = 3, Health = 75f });

var result = save.Load<PlayerData>("slot0");
if (result.Status == SaveStatus.Ok)
    Debug.Log("Loaded level " + result.Value.Level);

이벤트

어떤 클래스든 이벤트가 될 수 있습니다. 발행자와 구독자는 서로를 참조하지 않습니다 — 오직 이벤트 타입만 참조합니다. 전체 레퍼런스: Event Bus.

public sealed class CoinCollected { public int Amount; }

var events = ServiceLocator.Resolve<IEventBus>();
System.IDisposable ticket = events.Subscribe<CoinCollected>(
    e => Debug.Log("Coins gained: " + e.Amount));

events.Publish(new CoinCollected { Amount = 5 });
ticket.Dispose();   // stop listening (do this in OnDestroy)

타이머

타이머는 예약된 순서대로 발화합니다. 일회성 타이머는 스스로 정리되고, 반복 타이머는 dispose할 때까지 계속 돕니다. 전체 레퍼런스: Scheduler.

var scheduler = ServiceLocator.Resolve<IScheduler>();

scheduler.After(2f, () => Debug.Log("Two seconds later, exactly once."));

System.IDisposable heartbeat =
    scheduler.Every(0.5f, () => Debug.Log("Every half second."));
heartbeat.Dispose();   // stop the repeating timer when done

트위닝

트윈은 값을 한 숫자에서 다른 숫자로 애니메이션하며 각 단계를 여러분에게 건네줍니다. 기본적으로 트윈은 게임플레이 클럭에서 돌아가므로 게임이 일시정지되면 함께 일시정지됩니다. 전체 레퍼런스: Tween.

var tween = ServiceLocator.Resolve<ITweenService>();
CanvasGroup group = GetComponent<CanvasGroup>();

tween.To(1f, 0f, 0.75f,
    alpha => group.alpha = alpha,
    EaseType.OutQuad,
    onComplete: () => Debug.Log("Fade finished."));

입력

입력은 여러분의 input actions 애셋에 있는 이름 있는 액션 맵을 통해 읽습니다. "Gameplay""Jump"를 여러분의 애셋에 있는 이름으로 바꾸세요. InputAction 타입을 위해 using UnityEngine.InputSystem;을 추가하세요. 전체 레퍼런스: Input.

private IInputService _input;
private InputAction _jump;

private void Start()
{
    _input = ServiceLocator.Resolve<IInputService>();
    _jump  = _input.GetAction("Gameplay", "Jump");
}

private void Update()
{
    if (_jump != null && _input.WasPressedThisFrame(_jump))
        Debug.Log("Jump!");
}

4.4 다음 단계

이제 프레임워크 전체를 여는 단 하나의 패턴을 알게 되었습니다: 인터페이스를 해석하고, 캐시하고, 호출한다. 여기서부터는:

  • 서비스 레퍼런스. 모든 서비스에 자체 페이지가 있습니다 — 문서 색인에서 시작하거나, 프로젝트의 Assets/CommonGameSystem.Core/Documentation/Modules/(예: SaveLoad.md, Tween.md)에서 보세요. 각 페이지는 전체 API, 흔한 패턴, 중요한 주의사항을 다룹니다.
  • 샘플. RPG Starter Sample(3장)은 위 서비스 여러 개가 하나의 작은 게임 조각 안에서 협력하는 모습을 보여줍니다.
  • 이 매뉴얼의 나머지. 5장은 다섯 가지 핵심 개념을 설명하고, 6장은 프레임워크를 여러분의 애셋에 연결합니다.
  • 체인지로그. Welcome 창의 퀵 링크(3장)에서 설치된 버전의 문서와 체인지로그를 열 수 있습니다.

다음: 5. 핵심 개념