功能批量实现 优化 服务端 新浮动小游戏框架 新界面UI

This commit is contained in:
2026-04-24 13:20:16 +08:00
parent e0bc0bbf08
commit 5eec879582
257 changed files with 38481 additions and 1288 deletions
+291 -44
View File
@@ -1,79 +1,326 @@
using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "NewGalSO", menuName = "Galgame/galSO")]
public class ingame_galgame_so : ScriptableObject
{
[System.Serializable]
[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 string content;
[Tooltip("队列中第几个文本")]
public int textNumber; // 队列中第几个文本
[Tooltip("文本编号,仅用于人工整理,不作为运行时唯一依据。")]
public int textNumber;
[Tooltip(" speakersDataSO 中选择发言者")]
public int senderIndex = -1; // 改为索引,通过下拉选择
[Tooltip("发言人索引,来自 speakersDataSO 的 speakers 列表。-1 表示系统或旁白。")]
public int senderIndex = -1;
public enum ImagePosition { Left, Right }
[Tooltip("对象图片左右位置")]
public ImagePosition imagePos; // 对象图片左右位置
[Tooltip("对象图片是否水平翻转")]
[Tooltip("角色图片显示在左侧还是右侧。")]
public ImagePosition imagePos = ImagePosition.Left;
[Tooltip("角色图片是否水平翻转")]
public bool flipX;
[Tooltip("文本出现时间")]
public float appearTime; // 文本出现时间
[Tooltip("文本持续时间")]
public float duration; // 文本持续时间
[Tooltip("该条文本在所选时间轴上的出现时间")]
public float appearTime;
public enum StepMethod { ClickToNext, WaitForDuration }
[Tooltip("文本步进方法:点击后下一步 / 等待时长结束")]
public StepMethod stepMethod; // 文本步进方法
[Tooltip("自动播放时的停留时间,仅在 WaitForDuration 下生效。")]
public float duration = 1f;
public enum TimeAction { None, SlowMotion, Pause }
[Tooltip("文本出现时动作:无/慢动作/暂停")]
public TimeAction timeAction; // 文本出现时动作
[Tooltip("当前文本如何推进到下一条。")]
public StepMethod stepMethod = StepMethod.ClickToNext;
[Tooltip("文本播放期间时间流速,0为暂停")]
[Tooltip("文本播放期间对游戏时间流做的动作。")]
public TimeAction timeAction = TimeAction.None;
[Tooltip("当 timeAction 为 SlowMotion 时使用的 Time.timeScale。")]
[Range(0f, 1f)]
public float slowMotionScale = 0.5f; // 慢动作允许TimeScale设置值
public float slowMotionScale = 0.5f;
public enum EndAction { NextText, PauseQueue, EndPerformance }
[Tooltip("文本结束动作")]
public EndAction endAction; // 文本结束动作
[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
};
}
}
[System.Serializable]
[Serializable]
public class DialogueElement
{
public enum PositionTag { RoleHost, RoleHint, Narration, HintOrLyrics }
public enum PositionTag
{
RoleHost,
RoleHint,
Narration,
HintOrLyrics
}
[Header("显示模式")]
[Tooltip("决定本段文本使用哪种对话框样式。")]
public PositionTag positionTag = PositionTag.RoleHost;
[Header("位置配置")]
public PositionTag positionTag;
[HideInInspector]
public List<Vector2> customPositions;
public List<Vector2> customPositions = new List<Vector2>();
[Header("文本内容配置")]
public List<DialogueText> textList; // 文字列表
[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 }
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;
[Tooltip("触发方式")]
public TriggerMethod triggerMethod;
[Tooltip("时间线基准")]
public TimelineBase timelineStandard;
[Tooltip("当前脚本化演出是普通对话还是歌词模式。")]
public DialogueType dialogueType = DialogueType.Galgame;
[Tooltip("运行时由代码触发、按时间轴触发,还是两者混合。")]
public TriggerMethod triggerMethod = TriggerMethod.TimerTrigger;
[Tooltip("appearTime 使用哪一种时间基准。")]
public TimelineBase timelineStandard = TimelineBase.SceneStartTime;
[Header("角色数据")]
[Tooltip("引用 Speaker 配置 ScriptableObject")]
[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;
}
}