From 961f5ab8d8e03ee658846bdfd0eaa2790a14ab57 Mon Sep 17 00:00:00 2001 From: heavycaffiner Date: Sat, 29 Nov 2025 06:09:34 +0900 Subject: [PATCH] feat: Add variable system, scene transition, and improve character layout - **Introduce Variable System** - Added singleton class for variable management - Implemented script commands `[var]` and `[add]` for variable control - Supported variable substitution (`{variable}`) in dialogue and choices - **Expand Script Features** - Added `[scene]` command for scene transition (load scene and link next script) - **Improve Character Presentation** - Refactored character object hierarchy for better animation control - Applied mask-based soft transition effect (Soft Wipe) for expression changes --- Assets/_MAIN/Scripts/Core/ScriptAction.cs | 2 +- Assets/_MAIN/Scripts/Core/ScriptManager.cs | 65 +++++++++++++++-- Assets/_MAIN/Scripts/Core/ScriptParser.cs | 2 - Assets/_MAIN/Scripts/Core/VariableManager.cs | 73 +++++++++++++++++++ .../Scripts/Core/VariableManager.cs.meta | 2 + .../Scripts/Core/VisualNovelLayoutDirector.cs | 3 - ProjectSettings/EditorBuildSettings.asset | 3 + 7 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 Assets/_MAIN/Scripts/Core/VariableManager.cs create mode 100644 Assets/_MAIN/Scripts/Core/VariableManager.cs.meta diff --git a/Assets/_MAIN/Scripts/Core/ScriptAction.cs b/Assets/_MAIN/Scripts/Core/ScriptAction.cs index 73caeea..c96375e 100644 --- a/Assets/_MAIN/Scripts/Core/ScriptAction.cs +++ b/Assets/_MAIN/Scripts/Core/ScriptAction.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; public class ScriptAction { public string Type { get; set; } - public Dictionary Params { get; set; } = new Dictionary(); + public Dictionary Params { get; set; } = new(); public List> Choices { get; set; } public string GetParam(string key, string defaultValue = "") diff --git a/Assets/_MAIN/Scripts/Core/ScriptManager.cs b/Assets/_MAIN/Scripts/Core/ScriptManager.cs index b009d02..dc25fd1 100644 --- a/Assets/_MAIN/Scripts/Core/ScriptManager.cs +++ b/Assets/_MAIN/Scripts/Core/ScriptManager.cs @@ -3,6 +3,7 @@ using PrimeTween; using TMPro; using UnityEngine; using UnityEngine.EventSystems; +using UnityEngine.SceneManagement; using UnityEngine.UI; public class ScriptManager : MonoBehaviour @@ -30,6 +31,8 @@ public class ScriptManager : MonoBehaviour private Tween dialogueTween; private Script _currentScript; + public static string NextScriptPath = ""; + void Start() { speakerText.SetText(" "); @@ -37,7 +40,25 @@ public class ScriptManager : MonoBehaviour dialogueText.SetText(" "); dialogueText.ForceMeshUpdate(true); - _currentScript = ScriptParser.Parse(scriptFile.text); + if (!string.IsNullOrEmpty(NextScriptPath)) + { + TextAsset loadedScript = Resources.Load($"NovelScripts/{NextScriptPath}"); + if (loadedScript != null) + { + _currentScript = ScriptParser.Parse(loadedScript.text); + NextScriptPath = ""; + } + else + { + Debug.LogError($"ScriptManager :: Cannot find script: {NextScriptPath}"); + _currentScript = ScriptParser.Parse(scriptFile.text); + } + } + else + { + _currentScript = ScriptParser.Parse(scriptFile.text); + } + NextStep(); } @@ -144,6 +165,7 @@ public class ScriptManager : MonoBehaviour if (speaker == "") speakerSprite.SetActive(false); + speaker = VariableManager.Instance.ReplaceVariables(speaker); speakerText.SetText(speaker); speakerText.ForceMeshUpdate(true); NextStep(); @@ -152,6 +174,7 @@ public class ScriptManager : MonoBehaviour if (action.Type == "msg") { string dialogue = action.GetParam("content"); + dialogue = VariableManager.Instance.ReplaceVariables(dialogue); DisplayDialogue(dialogue); return; } @@ -174,7 +197,7 @@ public class ScriptManager : MonoBehaviour foreach (var choice in action.Choices) { - string text = choice["content"]; + string text = VariableManager.Instance.ReplaceVariables(choice["content"]); string target = choice["goto"]; GameObject buttonObj = Instantiate(choiceButtonPrefab, choiceButtonContainer); buttonObj.GetComponentInChildren().text = text; @@ -196,6 +219,34 @@ public class ScriptManager : MonoBehaviour } return; } + if (action.Type == "var") + { + foreach (var entry in action.Params) + { + VariableManager.Instance.SetVariable(entry.Key, entry.Value.ToString()); + } + NextStep(); + return; + } + if (action.Type == "add") + { + foreach (var entry in action.Params) + { + VariableManager.Instance.AddVariable(entry.Key, entry.Value.ToString()); + } + NextStep(); + return; + } + if (action.Type == "scene") + { + string sceneName = action.GetParam("file"); + string nextScript = action.GetParam("script"); + Debug.Log($"ScriptManager :: Load Scene: {sceneName}, Next Script: {nextScript}"); + + NextScriptPath = nextScript; + SceneManager.LoadScene(sceneName); + return; + } } public void DebugReload() @@ -210,11 +261,11 @@ public class ScriptManager : MonoBehaviour private bool IsPointerOverInteractiveUI() { - PointerEventData eventData = new(EventSystem.current) - { - position = Input.mousePosition - }; - List results = new(); + PointerEventData eventData = new(EventSystem.current) + { + position = Input.mousePosition + }; + List results = new(); EventSystem.current.RaycastAll(eventData, results); foreach (RaycastResult result in results) diff --git a/Assets/_MAIN/Scripts/Core/ScriptParser.cs b/Assets/_MAIN/Scripts/Core/ScriptParser.cs index b28581d..0832a9e 100644 --- a/Assets/_MAIN/Scripts/Core/ScriptParser.cs +++ b/Assets/_MAIN/Scripts/Core/ScriptParser.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -using UnityEngine; public class ScriptParser { @@ -32,7 +31,6 @@ public class ScriptParser { string tagName = tagMatch.Groups[1].Value; string attrString = tagMatch.Groups[2].Value; - Debug.Log($"ScriptParser :: Tag: {tagName} {attrString}"); var scriptAction = new ScriptAction { Type = tagName }; diff --git a/Assets/_MAIN/Scripts/Core/VariableManager.cs b/Assets/_MAIN/Scripts/Core/VariableManager.cs new file mode 100644 index 0000000..e87cf87 --- /dev/null +++ b/Assets/_MAIN/Scripts/Core/VariableManager.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using UnityEngine; + +public class VariableManager +{ + private static VariableManager _instance; + public static VariableManager Instance => _instance ??= new VariableManager(); + + private Dictionary _variables = new(); + + public void SetVariable(string name, string value) + { + // Try to parse as int or float, otherwise string + if (int.TryParse(value, out int intVal)) + _variables[name] = intVal; + else if (float.TryParse(value, out float floatVal)) + _variables[name] = floatVal; + else + _variables[name] = value; + + + Debug.Log($"VariableManager :: Set {name} = {_variables[name]} ({_variables[name].GetType()})"); + } + + public object GetVariable(string name) + { + return _variables.ContainsKey(name) ? _variables[name] : null; + } + + public void AddVariable(string name, string valueStr) + { + if (!_variables.ContainsKey(name)) + { + SetVariable(name, valueStr); + return; + } + + object current = _variables[name]; + + + if (current is int currentInt && int.TryParse(valueStr, out int addInt)) + { + _variables[name] = currentInt + addInt; + } + else if (current is float currentFloat && float.TryParse(valueStr, out float addFloat)) + { + _variables[name] = currentFloat + addFloat; + } + else if (current is string currentStr) + { + _variables[name] = currentStr + valueStr; + } + else + { + Debug.LogWarning($"VariableManager :: Cannot add {valueStr} to {name} (Type: {current.GetType()})"); + } + + + Debug.Log($"VariableManager :: Add {name} += {valueStr} -> {_variables[name]}"); + } + + + public string ReplaceVariables(string text) + { + if (string.IsNullOrEmpty(text)) return text; + + foreach (var kvp in _variables) + { + text = text.Replace($"{{{kvp.Key}}}", kvp.Value.ToString()); + } + return text; + } +} diff --git a/Assets/_MAIN/Scripts/Core/VariableManager.cs.meta b/Assets/_MAIN/Scripts/Core/VariableManager.cs.meta new file mode 100644 index 0000000..0af1bad --- /dev/null +++ b/Assets/_MAIN/Scripts/Core/VariableManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 309802f724fb94846a7b453b40357e1d \ No newline at end of file diff --git a/Assets/_MAIN/Scripts/Core/VisualNovelLayoutDirector.cs b/Assets/_MAIN/Scripts/Core/VisualNovelLayoutDirector.cs index 5231b51..7d9a8a5 100644 --- a/Assets/_MAIN/Scripts/Core/VisualNovelLayoutDirector.cs +++ b/Assets/_MAIN/Scripts/Core/VisualNovelLayoutDirector.cs @@ -1,5 +1,4 @@ using System.Collections; -using System.Collections.Generic; using PrimeTween; using UnityEngine; using UnityEngine.UI; @@ -19,8 +18,6 @@ public class VisualNovelLayoutDirector : MonoBehaviour public float defaultDuration = 0.5f; public float moveDistance = 800f; - - // ========================= [1. 등장 (Entry)] ========================= public void AddCharacter(string fileName, EntranceType type) { diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index 5f72133..bc31da3 100644 --- a/ProjectSettings/EditorBuildSettings.asset +++ b/ProjectSettings/EditorBuildSettings.asset @@ -8,6 +8,9 @@ EditorBuildSettings: - enabled: 1 path: Assets/_MAIN/Scenes/VisualNovel.unity guid: 199e3baed267a4c4fb4665bdaf82e49c + - enabled: 1 + path: Assets/_MAIN/Scenes/Scene01.unity + guid: ab7661506d731e6428485450843b0c2c m_configObjects: com.unity.input.settings.actions: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3} m_UseUCBPForAssetBundles: 0