327 lines
9.1 KiB
C#
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;
|
|
}
|
|
}
|