on
ai 주식투자
- Get link
- X
- Other Apps
목표: 본 장에서는 게임 아키텍처 설계, 디자인 패턴 적용, 에셋 관리(Addressables), 세이브/로드 시스템 구축을 통해 유니티 프로젝트를 유지보수 가능한 구조로 성장시키는 방법을 학습합니다. 즉, ‘작동하는 코드’에서 ‘확장 가능한 시스템’으로 발전하는 단계입니다.
대부분의 유니티 초보자는 ‘씬과 스크립트의 결합’으로 게임을 구성하지만, 프로젝트가 커질수록 명확한 아키텍처 없이는 유지보수가 거의 불가능해집니다. 유니티에서는 컴포넌트 기반 아키텍처(Component-Based Architecture)가 기본 구조이며, 이를 중심으로 모듈화와 데이터 분리를 진행해야 합니다.
Game/ ├─ Managers/ │ ├─ GameManager.cs │ ├─ AudioManager.cs │ └─ SaveManager.cs ├─ Systems/ │ ├─ InputSystem.cs │ ├─ InventorySystem.cs │ └─ DialogueSystem.cs ├─ Data/ │ ├─ PlayerData.asset │ └─ ItemDatabase.asset └─ UI/ ├─ HUD/ └─ Menus/ 패턴은 복잡한 시스템을 단순화하기 위한 설계의 언어입니다. 유니티는 “객체 간의 관계”가 빈번하므로, 아래 패턴들이 특히 자주 사용됩니다.
전역에서 접근 가능한 인스턴스를 유지합니다. 다만, 남용은 유지보수를 어렵게 만듭니다.
public class AudioManager : MonoBehaviour { public static AudioManager Instance { get; private set; } void Awake() { if (Instance != null && Instance != this) Destroy(gameObject); else { Instance = this; DontDestroyOnLoad(gameObject); } } } 싱글톤은 매니저 객체에만 제한적으로 사용하는 것이 좋습니다. 예를 들어 AudioManager, InputManager, SceneLoader 등.
객체 간 이벤트 기반 통신에 적합합니다. 예를 들어, 플레이어의 체력이 감소하면 UI가 자동으로 업데이트되도록 구성합니다.
public class PlayerHealth : MonoBehaviour { public event Action OnHealthChanged; private int health = 100;
public void TakeDamage(int amount) {
health -= amount;
OnHealthChanged?.Invoke(health);
}
}
게임의 행동 모드를 명확히 구분하는 구조입니다. 예: Idle → Move → Attack → Die
public abstract class PlayerState { public abstract void Enter(); public abstract void Update(); public abstract void Exit(); }
public class PlayerMoveState : PlayerState {
public override void Enter() => Debug.Log("Move 시작");
public override void Update() => Debug.Log("이동 중...");
public override void Exit() => Debug.Log("Move 종료");
}
이 구조를 통해 if문 기반 제어 대신 확장 가능한 상태 머신을 구축할 수 있습니다.
플레이어 입력을 명령 객체로 저장하여, 실행/취소(Undo) 기능을 구현할 수 있습니다.
유니티의 Addressables은 대규모 프로젝트에서 리소스를 효율적으로 로드, 관리, 배포하기 위한 시스템입니다. 이는 기존 Resources.Load()의 비효율성을 개선한 현대적 솔루션입니다.
using UnityEngine; using UnityEngine.AddressableAssets;
public class AssetLoader : MonoBehaviour {
public string assetKey;
void Start() {
Addressables.LoadAssetAsync(assetKey).Completed += handle => {
Instantiate(handle.Result);
};
}
}
이 구조는 로컬뿐 아니라 클라우드에서도 동일하게 작동하므로, 패치 시스템 구현에도 유용합니다.
세이브 시스템은 플레이어의 진행 상태를 파일로 저장하고 불러오는 구조입니다. 유니티에서는 직렬화(Serialization)를 활용하여 데이터 객체를 JSON 또는 바이너리 형태로 저장합니다.
[System.Serializable] public class PlayerData { public int level; public float health; public Vector3 position; } using System.IO; using UnityEngine;
public class SaveManager : MonoBehaviour {
private string path => Application.persistentDataPath + "/save.json";
public void Save(PlayerData data) {
string json = JsonUtility.ToJson(data, true);
File.WriteAllText(path, json);
Debug.Log("저장 완료: " + path);
}
public PlayerData Load() {
if (!File.Exists(path)) return null;
string json = File.ReadAllText(path);
return JsonUtility.FromJson(json);
}
}
이 방식은 간단하지만 강력하며, JSON 형식이기 때문에 디버깅이 용이합니다.
{ "version": 2, "player": { "level": 5, "health": 73.5, "position": { "x": 10, "y": 0, "z": -5 } } } 좋은 아키텍처는 실행 속도를 높이기보다, 프로젝트의 생명 주기를 연장합니다. 패턴은 문제를 단순화하고, Addressables은 자원을 관리하며, 세이브 시스템은 경험을 지속시킵니다.
결국, 좋은 게임은 기술이 아니라 ‘구조적 일관성’에서 태어납니다.
Comments
Post a Comment