Files
bansonic_beta_main/Assets/_galgame_inGame/ingame_galgame_so.cs
T

327 lines
9.1 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "NewGalSO", menuName = "Galgame/galSO")]
public class ingame_galgame_so : ScriptableObject
{
[Serializable]
public class DialogueText
{
public enum ImagePosition
{
Left,
Right
}
public enum StepMethod
{
ClickToNext,
WaitForDuration
}
public enum TimeAction
{
None,
SlowMotion,
Pause
}
public enum EndAction
{
NextText,
PauseQueue,
EndPerformance
}
[TextArea(3, 10)]
[Tooltip("当前对话实际显示的文本内容。")]
public string content;
[Tooltip("文本编号,仅用于人工整理,不作为运行时唯一依据。")]
public int textNumber;
[Tooltip("发言人索引,来自 speakersDataSO 的 speakers 列表。-1 表示系统或旁白。")]
public int senderIndex = -1;
[Tooltip("角色图片显示在左侧还是右侧。")]
public ImagePosition imagePos = ImagePosition.Left;
[Tooltip("角色图片是否水平翻转。")]
public bool flipX;
[Tooltip("该条文本在所选时间轴上的出现时间。")]
public float appearTime;
[Tooltip("自动播放时的停留时间,仅在 WaitForDuration 下生效。")]
public float duration = 1f;
[Tooltip("当前文本如何推进到下一条。")]
public StepMethod stepMethod = StepMethod.ClickToNext;
[Tooltip("文本播放期间对游戏时间流做的动作。")]
public TimeAction timeAction = TimeAction.None;
[Tooltip("当 timeAction 为 SlowMotion 时使用的 Time.timeScale。")]
[Range(0f, 1f)]
public float slowMotionScale = 0.5f;
[Tooltip("当前文本结束后的队列行为。")]
public EndAction endAction = EndAction.NextText;
public DialogueText Clone()
{
return new DialogueText
{
content = content,
textNumber = textNumber,
senderIndex = senderIndex,
imagePos = imagePos,
flipX = flipX,
appearTime = appearTime,
duration = duration,
stepMethod = stepMethod,
timeAction = timeAction,
slowMotionScale = slowMotionScale,
endAction = endAction
};
}
}
[Serializable]
public class DialogueElement
{
public enum PositionTag
{
RoleHost,
RoleHint,
Narration,
HintOrLyrics
}
[Header("显示模式")]
[Tooltip("决定本段文本使用哪种对话框样式。")]
public PositionTag positionTag = PositionTag.RoleHost;
[HideInInspector]
public List<Vector2> customPositions = new List<Vector2>();
[Header("文本列表")]
[Tooltip("该段落下的实际文本播放列表。")]
public List<DialogueText> textList = new List<DialogueText>();
public DialogueElement Clone()
{
var clone = new DialogueElement
{
positionTag = positionTag,
customPositions = customPositions != null ? new List<Vector2>(customPositions) : new List<Vector2>(),
textList = new List<DialogueText>()
};
if (textList != null)
{
for (int i = 0; i < textList.Count; i++)
{
if (textList[i] != null)
{
clone.textList.Add(textList[i].Clone());
}
}
}
return clone;
}
}
public enum TimelineBase
{
MusicTime,
SceneStartTime,
CustomTimer
}
public enum TriggerMethod
{
CodeTrigger,
TimerTrigger,
MixedTrigger
}
public enum DialogueType
{
Galgame,
Lyrics
}
[Serializable]
public class JsonDefinition
{
public int version = 1;
public DialogueType dialogueType = DialogueType.Galgame;
public TriggerMethod triggerMethod = TriggerMethod.TimerTrigger;
public TimelineBase timelineStandard = TimelineBase.SceneStartTime;
public List<DialogueElement> dialogueList = new List<DialogueElement>();
public JsonDefinition Clone()
{
var clone = new JsonDefinition
{
version = version,
dialogueType = dialogueType,
triggerMethod = triggerMethod,
timelineStandard = timelineStandard,
dialogueList = new List<DialogueElement>()
};
if (dialogueList != null)
{
for (int i = 0; i < dialogueList.Count; i++)
{
if (dialogueList[i] != null)
{
clone.dialogueList.Add(dialogueList[i].Clone());
}
}
}
return clone;
}
}
[Header("全局配置")]
[Tooltip("当前脚本化演出是普通对话还是歌词模式。")]
public DialogueType dialogueType = DialogueType.Galgame;
[Tooltip("运行时由代码触发、按时间轴触发,还是两者混合。")]
public TriggerMethod triggerMethod = TriggerMethod.TimerTrigger;
[Tooltip("appearTime 使用哪一种时间基准。")]
public TimelineBase timelineStandard = TimelineBase.SceneStartTime;
[Header("角色数据")]
[Tooltip("发言人配置来源。")]
public galgame_speakers_so speakersDataSO;
[Header("JSON 覆盖")]
[Tooltip("如果拖入 JSON 文本资源,运行时会优先使用 JSON 内容,而不是当前 Inspector 里的对话配置。")]
public TextAsset jsonDefinitionAsset;
[Header("对话内容")]
public List<DialogueElement> dialogueList = new List<DialogueElement>();
public bool HasJsonOverride => jsonDefinitionAsset != null && !string.IsNullOrWhiteSpace(jsonDefinitionAsset.text);
public JsonDefinition BuildDefinitionFromInspector()
{
var definition = new JsonDefinition
{
dialogueType = dialogueType,
triggerMethod = triggerMethod,
timelineStandard = timelineStandard,
dialogueList = new List<DialogueElement>()
};
if (dialogueList != null)
{
for (int i = 0; i < dialogueList.Count; i++)
{
if (dialogueList[i] != null)
{
definition.dialogueList.Add(dialogueList[i].Clone());
}
}
}
return definition;
}
public bool TryParseJsonOverride(out JsonDefinition definition)
{
definition = null;
if (!HasJsonOverride)
{
return false;
}
try
{
definition = JsonUtility.FromJson<JsonDefinition>(jsonDefinitionAsset.text);
if (definition == null)
{
return false;
}
if (definition.dialogueList == null)
{
definition.dialogueList = new List<DialogueElement>();
}
return true;
}
catch (Exception ex)
{
Debug.LogWarning($"[ingame_galgame_so] JSON 解析失败: {ex.Message}", this);
definition = null;
return false;
}
}
public JsonDefinition GetResolvedDefinition()
{
if (TryParseJsonOverride(out JsonDefinition fromJson))
{
return fromJson;
}
return BuildDefinitionFromInspector();
}
public string ExportCurrentDefinitionToJson(bool prettyPrint = true)
{
return JsonUtility.ToJson(BuildDefinitionFromInspector(), prettyPrint);
}
public void ApplyDefinitionToInspector(JsonDefinition definition)
{
if (definition == null)
{
return;
}
dialogueType = definition.dialogueType;
triggerMethod = definition.triggerMethod;
timelineStandard = definition.timelineStandard;
dialogueList ??= new List<DialogueElement>();
dialogueList.Clear();
if (definition.dialogueList == null)
{
return;
}
for (int i = 0; i < definition.dialogueList.Count; i++)
{
DialogueElement element = definition.dialogueList[i];
if (element != null)
{
dialogueList.Add(element.Clone());
}
}
}
public bool TryApplyJsonOverrideToInspector(out string errorMessage)
{
errorMessage = string.Empty;
if (!TryParseJsonOverride(out JsonDefinition definition))
{
errorMessage = HasJsonOverride ? "JSON 解析失败" : "未配置 JSON 覆盖源";
return false;
}
ApplyDefinitionToInspector(definition);
return true;
}
}