StorySystem
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace Ichni.Story.YarnFunctions
|
||||
{
|
||||
public static class GeneralFunctions
|
||||
{
|
||||
[YarnCommand("log")]
|
||||
public static void Log(string message, string logType)
|
||||
{
|
||||
logType = logType.ToLower();
|
||||
|
||||
switch (logType)
|
||||
{
|
||||
case "info":
|
||||
Debug.Log(message);
|
||||
break;
|
||||
case "warning":
|
||||
Debug.LogWarning(message);
|
||||
break;
|
||||
case "error":
|
||||
Debug.LogError(message);
|
||||
break;
|
||||
default:
|
||||
Debug.Log(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1af4095ad0bedbe41b834a162253a0e8
|
||||
@@ -0,0 +1,69 @@
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace Ichni.Story.YarnFunctions
|
||||
{
|
||||
/// <summary>
|
||||
/// 立绘动画控制相关的 Yarn 自定义命令静态注册器。
|
||||
/// 包含平移、跳跃、震动等 DOTween 动画表现。
|
||||
/// </summary>
|
||||
public static class PortraitAnimationCommands
|
||||
{
|
||||
// ── Yarn Commands ────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// 平滑移动角色立绘到目标位置。
|
||||
/// 格式: <<move_portrait characterId x y duration>>
|
||||
/// </summary>
|
||||
/// <param name="characterId">角色标识 ID</param>
|
||||
/// <param name="x">目标 X 坐标 [-100, 100]</param>
|
||||
/// <param name="y">目标 Y 坐标 [-100, 100]</param>
|
||||
/// <param name="duration">动画持续时间(秒)</param>
|
||||
[YarnCommand("move_portrait")]
|
||||
public static void MovePortrait(string characterId, float x, float y, float duration)
|
||||
{
|
||||
if (!EnsureStage()) return;
|
||||
Dialogue.VNPortraitStage.Instance.MovePortrait(characterId, new Vector2(x, y), duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 让角色立绘原地跳跃。
|
||||
/// 格式: <<jump_portrait characterId power numJumps duration>>
|
||||
/// </summary>
|
||||
/// <param name="characterId">角色标识 ID</param>
|
||||
/// <param name="power">跳跃高度(使用与坐标域相同的归一化尺度,如 10 表示 10% 高度)</param>
|
||||
/// <param name="numJumps">跳跃次数</param>
|
||||
/// <param name="duration">动画总持续时间(秒)</param>
|
||||
[YarnCommand("jump_portrait")]
|
||||
public static void JumpPortrait(string characterId, float power, int numJumps, float duration)
|
||||
{
|
||||
if (!EnsureStage()) return;
|
||||
Dialogue.VNPortraitStage.Instance.JumpPortrait(characterId, power, numJumps, duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 让角色立绘产生左右震动效果。
|
||||
/// 格式: <<shake_portrait characterId duration strength vibrato>>
|
||||
/// </summary>
|
||||
/// <param name="characterId">角色标识 ID</param>
|
||||
/// <param name="duration">震动持续时间(秒)</param>
|
||||
/// <param name="strength">震动幅度(使用与坐标域相同的归一化尺度)</param>
|
||||
/// <param name="vibrato">震动频率</param>
|
||||
[YarnCommand("shake_portrait")]
|
||||
public static void ShakePortrait(string characterId, float duration, float strength, int vibrato)
|
||||
{
|
||||
if (!EnsureStage()) return;
|
||||
Dialogue.VNPortraitStage.Instance.ShakePortrait(characterId, duration, strength, vibrato);
|
||||
}
|
||||
|
||||
// ── 内部辅助 ─────────────────────────────────────────────────────────────
|
||||
|
||||
private static bool EnsureStage()
|
||||
{
|
||||
if (Dialogue.VNPortraitStage.Instance != null) return true;
|
||||
|
||||
Debug.LogError("[PortraitAnimationCommands] 未找到 VNPortraitStage 实例!请确保在当前场景中存在挂载了 VNPortraitStage 的游戏物体。");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50b4898984f9bfc4da527dcd444f87b3
|
||||
112
Assets/Scripts/NewStorySystem/YarnFunctions/PortraitCommands.cs
Normal file
112
Assets/Scripts/NewStorySystem/YarnFunctions/PortraitCommands.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace Ichni.Story.YarnFunctions
|
||||
{
|
||||
/// <summary>
|
||||
/// 立绘控制相关的 Yarn 自定义命令静态注册器。
|
||||
/// <para>
|
||||
/// 全局静态命令,不依赖于 GameObject 的挂载。所有方法都使用强类型的参数,
|
||||
/// 以更明确、简洁的指令名称区分不同应用场景,从而抛弃复杂的内部字符串解析判断。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static class PortraitCommands
|
||||
{
|
||||
// ── Yarn Commands ────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// 最基础、最全面的立绘指令:设置指定角色的坐标和表情。
|
||||
/// 若角色不在台上,会自动以指定的表情和位置实例化。
|
||||
/// 格式: <<set_portrait characterId x y [emotion]>>
|
||||
/// </summary>
|
||||
/// <param name="characterId">角色标识 ID。</param>
|
||||
/// <param name="x">归一化 X 坐标 [-100, 100]</param>
|
||||
/// <param name="y">归一化 Y 坐标 [-100, 100]</param>
|
||||
/// <param name="emotion">表情名称。如果不填,默认保持不变或初始化为 "normal"</param>
|
||||
[YarnCommand("set_portrait")]
|
||||
public static void SetPortrait(string characterId, float x, float y, string emotion = null)
|
||||
{
|
||||
if (!EnsureStage()) return;
|
||||
|
||||
// 传入归一化坐标,由 VNPortraitStage 内部自动应用 positionOffset 并转换为像素坐标
|
||||
Vector2 normalizedPos = new Vector2(x, y);
|
||||
Dialogue.VNPortraitStage.Instance.SetPortraitPosition(characterId, normalizedPos, emotion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前说话角色的坐标和表情。
|
||||
/// 格式: <<set_portrait_current x y [emotion]>>
|
||||
/// </summary>
|
||||
[YarnCommand("set_portrait_current")]
|
||||
public static void SetPortraitCurrent(float x, float y, string emotion = null)
|
||||
{
|
||||
if (!EnsureStage()) return;
|
||||
|
||||
string characterId = Dialogue.VNPortraitStage.Instance.CurrentSpeakerId;
|
||||
if (string.IsNullOrEmpty(characterId))
|
||||
{
|
||||
Debug.LogWarning("[PortraitCommands] set_portrait_current: 当前没有活动的说话者,无法执行此命令!");
|
||||
return;
|
||||
}
|
||||
|
||||
SetPortrait(characterId, x, y, emotion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅设置或移动指定角色的坐标(不改变当前表情)。
|
||||
/// 格式: <<set_portrait_position characterId x y>>
|
||||
/// </summary>
|
||||
[YarnCommand("set_portrait_position")]
|
||||
public static void SetPortraitPosition(string characterId, float x, float y)
|
||||
{
|
||||
// 通过传入 emotion = null,VNPortraitStage 在更新时将保持角色原有表情
|
||||
SetPortrait(characterId, x, y, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅改变指定角色的表情(角色必须已经上台)。
|
||||
/// 格式: <<set_portrait_emotion characterId emotion>>
|
||||
/// </summary>
|
||||
[YarnCommand("set_portrait_emotion")]
|
||||
public static void SetPortraitEmotion(string characterId, string emotion)
|
||||
{
|
||||
if (!EnsureStage()) return;
|
||||
|
||||
Dialogue.VNPortraitStage.Instance.SetPortraitEmotion(characterId, emotion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏指定角色的立绘。
|
||||
/// 格式: <<hide_portrait characterId>>
|
||||
/// </summary>
|
||||
[YarnCommand("hide_portrait")]
|
||||
public static void HidePortrait(string characterId)
|
||||
{
|
||||
if (!EnsureStage()) return;
|
||||
|
||||
Dialogue.VNPortraitStage.Instance.HidePortrait(characterId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏当前所有在台上的立绘。
|
||||
/// 格式: <<hide_all_portraits>>
|
||||
/// </summary>
|
||||
[YarnCommand("hide_all_portraits")]
|
||||
public static void HideAllPortraits()
|
||||
{
|
||||
if (!EnsureStage()) return;
|
||||
|
||||
Dialogue.VNPortraitStage.Instance.HideAll();
|
||||
}
|
||||
|
||||
// ── 内部辅助 ─────────────────────────────────────────────────────────────
|
||||
|
||||
private static bool EnsureStage()
|
||||
{
|
||||
if (Dialogue.VNPortraitStage.Instance != null) return true;
|
||||
|
||||
Debug.LogError("[PortraitCommands] 未找到 VNPortraitStage 实例!请确保在当前场景中存在挂载了 VNPortraitStage 的游戏物体。");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d56251fa130b1334eab42a8d3069932f
|
||||
103
Assets/Scripts/NewStorySystem/YarnFunctions/StoryTreeCommands.cs
Normal file
103
Assets/Scripts/NewStorySystem/YarnFunctions/StoryTreeCommands.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using Ichni.Story.Dialogue;
|
||||
using Ichni.Story.UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Settings;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace Ichni.Story.YarnFunctions
|
||||
{
|
||||
/// <summary>
|
||||
/// 包含与故事树节点控制、全局进程、存档交互相关的 Yarn 自定义命令注册器。
|
||||
/// </summary>
|
||||
public static class StoryTreeCommands
|
||||
{
|
||||
// ── Yarn Commands ────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// 解锁一首新歌曲,并在当前这段对话结束(对话 UI 淡出)后,弹出 MessageBox 提示。
|
||||
/// 格式: <<unlock_song songUnlockKey>>
|
||||
/// </summary>
|
||||
/// <param name="songUnlockKey">要解锁的歌曲密钥/ID</param>
|
||||
[YarnCommand("unlock_song")]
|
||||
public static void UnlockSong(string songUnlockKey)
|
||||
{
|
||||
if (GameSaveManager.instance == null || GameSaveManager.instance.SongSaveModule == null)
|
||||
{
|
||||
Debug.LogError("[StoryTreeCommands] 无法解锁歌曲:GameSaveManager 或其 SongSaveModule 未初始化!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 检查是否已经解锁
|
||||
if (GameSaveManager.instance.SongSaveModule.CheckStoryKey(songUnlockKey))
|
||||
{
|
||||
Debug.Log($"[StoryTreeCommands] 歌曲 {songUnlockKey} 已处于解锁状态。");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 写入解锁状态并保存存档
|
||||
GameSaveManager.instance.SongSaveModule.storyUnlockKeys.Add(songUnlockKey);
|
||||
GameSaveManager.instance.SongSaveModule.SaveStoryUnlockKeys();
|
||||
Debug.Log($"[StoryTreeCommands] 已成功写入并保存歌曲解锁密钥:{songUnlockKey}");
|
||||
|
||||
// 3. 将 UI 弹窗提示加入到对话结束队列中
|
||||
if (StoryDialogueController.instance != null)
|
||||
{
|
||||
StoryDialogueController.instance.dialogueEndActions.Add(() =>
|
||||
{
|
||||
if (StoryMessageBoxUIPage.instance != null)
|
||||
{
|
||||
StoryMessageBoxUIPage.instance.ShowUnlockMessage(songUnlockKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[StoryTreeCommands] 弹窗失败:场景中未找到 StoryMessageBoxUIPage 实例!");
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("[StoryTreeCommands] 弹窗队列注册失败:未找到 StoryDialogueController 实例!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在对话结束后,弹出一个自定义 MessageBox 提示。
|
||||
/// 会尝试使用 Unity Localization 进行翻译,如果找不到对应条目则回退显示原文本(Key)。
|
||||
/// 格式: <<show_message titleKey contentKey [tableName]>>
|
||||
/// </summary>
|
||||
/// <param name="titleKey">标题文本或本地化键</param>
|
||||
/// <param name="contentKey">正文文本或本地化键</param>
|
||||
/// <param name="tableName">Unity Localization 中的 String Table 名称</param>
|
||||
[YarnCommand("show_message")]
|
||||
public static void ShowMessage(string titleKey, string contentKey, string tableName = "Message")
|
||||
{
|
||||
string translatedTitle = GetTranslatedText(tableName, titleKey);
|
||||
string translatedContent = GetTranslatedText(tableName, contentKey);
|
||||
Debug.Log($"[StoryTreeCommands] 准备在对话结束后显示自定义弹窗:标题='{translatedTitle}',内容='{translatedContent}'");
|
||||
StoryDialogueController.instance.dialogueEndActions.Add(() =>
|
||||
{
|
||||
StoryMessageBoxUIPage.instance.ShowCustomMessage(translatedTitle, translatedContent);
|
||||
});
|
||||
}
|
||||
|
||||
// ── 内部辅助 ─────────────────────────────────────────────────────────────
|
||||
|
||||
private static string GetTranslatedText(string tableName, string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key)) return string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
// 尝试从 Unity Localization 中获取翻译文本
|
||||
string translated = LocalizationSettings.StringDatabase.GetLocalizedString(tableName, key);
|
||||
// 若获取失败或为空,则直接原样返回 key 作为兜底文本
|
||||
return string.IsNullOrEmpty(translated) ? key : translated;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果表不存在或其他异常,返回原 key
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a048ef81fee2164b8c7ae9748690cfd
|
||||
@@ -0,0 +1,76 @@
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
using Ichni.Story;
|
||||
|
||||
namespace Ichni.Story.YarnFunctions
|
||||
{
|
||||
/// <summary>
|
||||
/// 提供可以直接在 Yarn 脚本中调用的全局变量读写指令。
|
||||
/// 完全兼容旧系统中的自定义函数(避免旧的 .yarn 报错),
|
||||
/// 底层统一指向全新的 StoryVariables 枢纽。
|
||||
/// </summary>
|
||||
public static class VariableCommands
|
||||
{
|
||||
[YarnCommand("set_bool")]
|
||||
public static void SetBool(string key, bool value)
|
||||
{
|
||||
StoryVariables.SetBool(key, value);
|
||||
}
|
||||
|
||||
[YarnFunction("get_bool")]
|
||||
public static bool GetBool(string key)
|
||||
{
|
||||
return StoryVariables.GetBool(key);
|
||||
}
|
||||
|
||||
[YarnCommand("set_int")]
|
||||
public static void SetInt(string key, int value)
|
||||
{
|
||||
StoryVariables.SetInt(key, value);
|
||||
}
|
||||
|
||||
[YarnCommand("modify_int")]
|
||||
public static void ModifyInt(string key, int modification)
|
||||
{
|
||||
int currentValue = StoryVariables.GetInt(key);
|
||||
StoryVariables.SetInt(key, currentValue + modification);
|
||||
}
|
||||
|
||||
[YarnFunction("get_int")]
|
||||
public static int GetInt(string key)
|
||||
{
|
||||
return StoryVariables.GetInt(key);
|
||||
}
|
||||
|
||||
[YarnCommand("set_float")]
|
||||
public static void SetFloat(string key, float value)
|
||||
{
|
||||
StoryVariables.SetFloat(key, value);
|
||||
}
|
||||
|
||||
[YarnCommand("modify_float")]
|
||||
public static void ModifyFloat(string key, float modification)
|
||||
{
|
||||
float currentValue = StoryVariables.GetFloat(key);
|
||||
StoryVariables.SetFloat(key, currentValue + modification);
|
||||
}
|
||||
|
||||
[YarnFunction("get_float")]
|
||||
public static float GetFloat(string key)
|
||||
{
|
||||
return StoryVariables.GetFloat(key);
|
||||
}
|
||||
|
||||
[YarnCommand("set_string")]
|
||||
public static void SetString(string key, string value)
|
||||
{
|
||||
StoryVariables.SetString(key, value);
|
||||
}
|
||||
|
||||
[YarnFunction("get_string")]
|
||||
public static string GetString(string key)
|
||||
{
|
||||
return StoryVariables.GetString(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9094628fd04644439b4afd553c7a6aa
|
||||
Reference in New Issue
Block a user