2026-07-05 대화시스템 수정
This commit is contained in:
135
Assets/02_Scripts/Managers/StoryState.cs
Normal file
135
Assets/02_Scripts/Managers/StoryState.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
// 이야기 진행 상태의 중앙 저장소 (메인 진행도 / 호감도 / 대화 이력 / 선택 이력).
|
||||
// DialogCondition이 대화 활성화 판정의 근거로 조회하고, DialogPlayer가 기록한다.
|
||||
//
|
||||
// 저장: Save()가 JSON 파일로 기록한다. DialogPlayer가 대화 완료 시마다 호출한다.
|
||||
// 로드: 플레이 시작 시 항상 빈 상태로 시작한다 (테스트 반복이 꼬이지 않게).
|
||||
// 이어하기를 만들 때 타이틀 화면 등에서 Load()를 호출하면 된다.
|
||||
public static class StoryState
|
||||
{
|
||||
private static int _mainProgress;
|
||||
private static readonly Dictionary<string, int> _affection = new();
|
||||
private static readonly HashSet<string> _completedDialogs = new();
|
||||
private static readonly HashSet<string> _chosenCodes = new();
|
||||
|
||||
// 상태가 바뀔 때마다 발행 (호감도 게이지 등 UI 갱신용)
|
||||
public static event Action Changed;
|
||||
|
||||
// ── 메인 진행도 ──────────────────────────────────────────────
|
||||
public static int MainProgress
|
||||
{
|
||||
get => _mainProgress;
|
||||
set
|
||||
{
|
||||
if (_mainProgress == value) return;
|
||||
_mainProgress = value;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
// ── 호감도 ──────────────────────────────────────────────────
|
||||
public static int GetAffection(CharacterData character)
|
||||
=> character != null && _affection.TryGetValue(IdOf(character), out var v) ? v : 0;
|
||||
|
||||
public static void AddAffection(CharacterData character, int delta)
|
||||
{
|
||||
if (character == null || delta == 0) return;
|
||||
_affection[IdOf(character)] = GetAffection(character) + delta;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
// CharacterData의 Id를 키로 사용 (비어있으면 에셋 이름)
|
||||
private static string IdOf(CharacterData c) => string.IsNullOrEmpty(c.Id) ? c.name : c.Id;
|
||||
|
||||
// ── 대화 이력 ────────────────────────────────────────────────
|
||||
public static bool IsDialogCompleted(string groupName) => _completedDialogs.Contains(groupName);
|
||||
|
||||
// 완료 기록. 처음 완료한 경우에만 true (진행도 보상 중복 방지용)
|
||||
public static bool MarkDialogCompleted(string groupName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(groupName) || !_completedDialogs.Add(groupName))
|
||||
return false;
|
||||
Changed?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ── 선택 이력 ────────────────────────────────────────────────
|
||||
public static bool HasChosen(string code) => _chosenCodes.Contains(code);
|
||||
|
||||
public static void RecordChoice(string code)
|
||||
{
|
||||
if (string.IsNullOrEmpty(code) || !_chosenCodes.Add(code)) return;
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
// ── 저장 / 로드 ──────────────────────────────────────────────
|
||||
[Serializable]
|
||||
private class SaveData
|
||||
{
|
||||
public int MainProgress;
|
||||
public List<string> AffectionIds = new();
|
||||
public List<int> AffectionValues = new();
|
||||
public List<string> CompletedDialogs = new();
|
||||
public List<string> ChosenCodes = new();
|
||||
}
|
||||
|
||||
private static string SavePath => Path.Combine(Application.persistentDataPath, "story_state.json");
|
||||
|
||||
public static void Save()
|
||||
{
|
||||
var data = new SaveData { MainProgress = _mainProgress };
|
||||
foreach (var kvp in _affection)
|
||||
{
|
||||
data.AffectionIds.Add(kvp.Key);
|
||||
data.AffectionValues.Add(kvp.Value);
|
||||
}
|
||||
data.CompletedDialogs.AddRange(_completedDialogs);
|
||||
data.ChosenCodes.AddRange(_chosenCodes);
|
||||
File.WriteAllText(SavePath, JsonUtility.ToJson(data, prettyPrint: true));
|
||||
}
|
||||
|
||||
// 저장 파일이 있으면 불러온다. 성공 여부 반환.
|
||||
public static bool Load()
|
||||
{
|
||||
if (!File.Exists(SavePath)) return false;
|
||||
|
||||
var data = JsonUtility.FromJson<SaveData>(File.ReadAllText(SavePath));
|
||||
if (data == null) return false;
|
||||
|
||||
_mainProgress = data.MainProgress;
|
||||
_affection.Clear();
|
||||
for (int i = 0; i < data.AffectionIds.Count && i < data.AffectionValues.Count; i++)
|
||||
_affection[data.AffectionIds[i]] = data.AffectionValues[i];
|
||||
_completedDialogs.Clear();
|
||||
_completedDialogs.UnionWith(data.CompletedDialogs);
|
||||
_chosenCodes.Clear();
|
||||
_chosenCodes.UnionWith(data.ChosenCodes);
|
||||
Changed?.Invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
// 새 게임용 초기화 (저장 파일은 다음 Save 때 덮어써짐)
|
||||
public static void ResetAll()
|
||||
{
|
||||
_mainProgress = 0;
|
||||
_affection.Clear();
|
||||
_completedDialogs.Clear();
|
||||
_chosenCodes.Clear();
|
||||
Changed?.Invoke();
|
||||
}
|
||||
|
||||
// 플레이 시작마다 초기화 (Enter Play Mode에서 도메인 리로드를 꺼도 이전 값이 안 남게)
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void ResetOnPlay()
|
||||
{
|
||||
_mainProgress = 0;
|
||||
_affection.Clear();
|
||||
_completedDialogs.Clear();
|
||||
_chosenCodes.Clear();
|
||||
Changed = null;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/Managers/StoryState.cs.meta
Normal file
2
Assets/02_Scripts/Managers/StoryState.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d47259c7403ae7e42b37a411170bc21c
|
||||
Reference in New Issue
Block a user