Files
bansonic_beta_main/Assets/_galgame_inGame/gameplayGalgame.cs
T

534 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
public class gameplayGalgame : MonoBehaviour
{
private ingame_galgame_so.JsonDefinition resolvedDefinition;
private sealed class RuntimeDialogueEntry
{
public int sequence;
public ingame_galgame_so.DialogueElement.PositionTag positionTag;
public ingame_galgame_so.DialogueText dialogue;
public Speaker speaker;
}
[Header("启用开关")]
public bool enableGalgame = false;
public bool enableLyricsSO = true;
[Header("对话数据")]
public ingame_galgame_so golSO;
[Header("预制体")]
public GameObject galgamePrefab;
public GameObject where_to_put;
[Header("时间轴")]
public AudioSource musicTimelineSource;
[Header("输入")]
public bool allowGlobalClickToAdvance = true;
public KeyCode keyboardAdvanceKey = KeyCode.Space;
public KeyCode keyboardAdvanceKeyAlt = KeyCode.Return;
private readonly List<RuntimeDialogueEntry> runtimeEntries = new List<RuntimeDialogueEntry>();
private galPrefab galController;
private GameObject galInstance;
private int currentEntryIndex = -1;
private bool isRunning;
private bool waitingForClick;
private bool pauseQueueRequested;
private bool entryVisible;
private bool advanceRequested;
private float sceneStartRealtime;
private float entryShownRealtime;
private float customTimelineTime;
private float cachedTimeScale = 1f;
private bool timeActionApplied;
public bool IsRunning => isRunning;
public bool IsPausedQueue => pauseQueueRequested;
public bool HasActiveEntry => isRunning && currentEntryIndex >= 0 && currentEntryIndex < runtimeEntries.Count;
private void Awake()
{
sceneStartRealtime = Time.unscaledTime;
}
private void Start()
{
TryPrepareRuntime();
if (ShouldAutoStart())
{
StartSequence();
}
}
private void Update()
{
if (!isRunning || golSO == null || runtimeEntries.Count == 0)
{
return;
}
if (golSO.timelineStandard == ingame_galgame_so.TimelineBase.CustomTimer)
{
customTimelineTime += Time.unscaledDeltaTime;
}
if (pauseQueueRequested)
{
if (advanceRequested || DetectAdvanceInput())
{
advanceRequested = false;
ResumeSequence();
}
return;
}
RuntimeDialogueEntry entry = GetCurrentEntry();
if (entry == null)
{
FinishSequence();
return;
}
if (!entryVisible)
{
if (GetTimelineTime() >= Mathf.Max(0f, entry.dialogue.appearTime))
{
ShowCurrentEntry(entry);
}
return;
}
if (waitingForClick)
{
if (advanceRequested || DetectAdvanceInput())
{
advanceRequested = false;
ResolveCurrentEntry(entry);
}
return;
}
float requiredDuration = Mathf.Max(0f, entry.dialogue.duration);
if (Time.unscaledTime - entryShownRealtime >= requiredDuration)
{
ResolveCurrentEntry(entry);
}
}
public void read_gol_so()
{
if (golSO == null)
{
Debug.LogWarning("[gameplayGalgame] 没有配置 galgame SO。");
return;
}
ResolveDefinition();
if (resolvedDefinition == null)
{
Debug.LogWarning("[gameplayGalgame] 无法解析 galgame 配置。");
return;
}
Debug.Log($"[gameplayGalgame] dialogueType={resolvedDefinition.dialogueType}, triggerMethod={resolvedDefinition.triggerMethod}, timeline={resolvedDefinition.timelineStandard}");
}
public void StartSequence()
{
if (!ShouldPlayConfiguredSo())
{
return;
}
TryPrepareRuntime();
if (golSO == null || runtimeEntries.Count == 0)
{
return;
}
StopSequenceInternal(false);
sceneStartRealtime = Time.unscaledTime;
customTimelineTime = 0f;
currentEntryIndex = 0;
isRunning = true;
waitingForClick = false;
pauseQueueRequested = false;
entryVisible = false;
advanceRequested = false;
EnsureGalInstance();
if (galController != null)
{
galController.HideAllModes();
}
}
public void RestartSequence()
{
StartSequence();
}
public void ResumeSequence()
{
if (!pauseQueueRequested)
{
return;
}
pauseQueueRequested = false;
AdvanceToNextEntry();
}
public void StopSequence()
{
StopSequenceInternal(true);
}
public void RequestAdvance()
{
advanceRequested = true;
}
public void SetCustomTimelineTime(float value)
{
customTimelineTime = Mathf.Max(0f, value);
}
public void AdvanceCustomTimeline(float delta)
{
customTimelineTime = Mathf.Max(0f, customTimelineTime + delta);
}
private bool ShouldAutoStart()
{
if (!ShouldPlayConfiguredSo() || golSO == null)
{
return false;
}
ResolveDefinition();
if (resolvedDefinition == null)
{
return false;
}
return resolvedDefinition.triggerMethod == ingame_galgame_so.TriggerMethod.TimerTrigger
|| resolvedDefinition.triggerMethod == ingame_galgame_so.TriggerMethod.MixedTrigger;
}
private bool ShouldPlayConfiguredSo()
{
if (golSO == null)
{
return false;
}
ResolveDefinition();
if (resolvedDefinition == null)
{
return false;
}
if (resolvedDefinition.dialogueType == ingame_galgame_so.DialogueType.Galgame)
{
return enableGalgame;
}
if (resolvedDefinition.dialogueType == ingame_galgame_so.DialogueType.Lyrics)
{
return enableLyricsSO;
}
return false;
}
private void TryPrepareRuntime()
{
ResolveDefinition();
BuildRuntimeEntries();
EnsureGalInstance();
}
private void BuildRuntimeEntries()
{
runtimeEntries.Clear();
if (golSO == null || resolvedDefinition == null || resolvedDefinition.dialogueList == null)
{
return;
}
int sequence = 0;
for (int i = 0; i < resolvedDefinition.dialogueList.Count; i++)
{
ingame_galgame_so.DialogueElement element = resolvedDefinition.dialogueList[i];
if (element == null || element.textList == null)
{
continue;
}
for (int j = 0; j < element.textList.Count; j++)
{
ingame_galgame_so.DialogueText text = element.textList[j];
if (text == null)
{
continue;
}
runtimeEntries.Add(new RuntimeDialogueEntry
{
sequence = sequence++,
positionTag = element.positionTag,
dialogue = text,
speaker = ResolveSpeaker(text.senderIndex)
});
}
}
}
private Speaker ResolveSpeaker(int senderIndex)
{
if (golSO == null || golSO.speakersDataSO == null || golSO.speakersDataSO.speakers == null)
{
return null;
}
if (senderIndex < 0 || senderIndex >= golSO.speakersDataSO.speakers.Count)
{
return null;
}
return golSO.speakersDataSO.speakers[senderIndex];
}
private void EnsureGalInstance()
{
if (galController != null)
{
galController.Initialize(RequestAdvance);
return;
}
if (galgamePrefab == null)
{
return;
}
Transform parent = where_to_put != null ? where_to_put.transform : transform;
if (galInstance == null)
{
galInstance = Instantiate(galgamePrefab, parent, false);
}
galController = galInstance != null ? galInstance.GetComponent<galPrefab>() : null;
if (galController != null)
{
galController.Initialize(RequestAdvance);
}
}
private RuntimeDialogueEntry GetCurrentEntry()
{
if (currentEntryIndex < 0 || currentEntryIndex >= runtimeEntries.Count)
{
return null;
}
return runtimeEntries[currentEntryIndex];
}
private void ShowCurrentEntry(RuntimeDialogueEntry entry)
{
if (entry == null)
{
return;
}
EnsureGalInstance();
RestoreTimeAction();
if (galController != null)
{
galController.Present(entry.positionTag, entry.dialogue, entry.speaker);
bool clickToNext = entry.dialogue.stepMethod == ingame_galgame_so.DialogueText.StepMethod.ClickToNext;
galController.SetAdvanceEnabled(clickToNext);
}
ApplyTimeAction(entry.dialogue);
entryVisible = true;
entryShownRealtime = Time.unscaledTime;
waitingForClick = entry.dialogue.stepMethod == ingame_galgame_so.DialogueText.StepMethod.ClickToNext;
}
private void ResolveCurrentEntry(RuntimeDialogueEntry entry)
{
if (entry == null)
{
FinishSequence();
return;
}
RestoreTimeAction();
waitingForClick = false;
entryVisible = false;
switch (entry.dialogue.endAction)
{
case ingame_galgame_so.DialogueText.EndAction.NextText:
AdvanceToNextEntry();
break;
case ingame_galgame_so.DialogueText.EndAction.PauseQueue:
pauseQueueRequested = true;
if (galController != null)
{
galController.SetAdvanceEnabled(true);
}
break;
case ingame_galgame_so.DialogueText.EndAction.EndPerformance:
FinishSequence();
break;
default:
AdvanceToNextEntry();
break;
}
}
private void AdvanceToNextEntry()
{
currentEntryIndex++;
if (currentEntryIndex >= runtimeEntries.Count)
{
FinishSequence();
return;
}
advanceRequested = false;
waitingForClick = false;
entryVisible = false;
}
private void FinishSequence()
{
StopSequenceInternal(true);
}
private void StopSequenceInternal(bool hideUi)
{
RestoreTimeAction();
isRunning = false;
waitingForClick = false;
pauseQueueRequested = false;
entryVisible = false;
advanceRequested = false;
currentEntryIndex = -1;
if (hideUi && galController != null)
{
galController.HideAllModes();
galController.SetAdvanceEnabled(false);
}
}
private void ApplyTimeAction(ingame_galgame_so.DialogueText dialogue)
{
if (dialogue == null || dialogue.timeAction == ingame_galgame_so.DialogueText.TimeAction.None)
{
return;
}
cachedTimeScale = Time.timeScale;
timeActionApplied = true;
switch (dialogue.timeAction)
{
case ingame_galgame_so.DialogueText.TimeAction.SlowMotion:
Time.timeScale = Mathf.Clamp(dialogue.slowMotionScale, 0f, 1f);
break;
case ingame_galgame_so.DialogueText.TimeAction.Pause:
Time.timeScale = 0f;
break;
}
}
private void RestoreTimeAction()
{
if (!timeActionApplied)
{
return;
}
Time.timeScale = cachedTimeScale;
timeActionApplied = false;
}
private float GetTimelineTime()
{
if (golSO == null)
{
return 0f;
}
ResolveDefinition();
if (resolvedDefinition == null)
{
return 0f;
}
switch (resolvedDefinition.timelineStandard)
{
case ingame_galgame_so.TimelineBase.SceneStartTime:
return Mathf.Max(0f, Time.unscaledTime - sceneStartRealtime);
case ingame_galgame_so.TimelineBase.CustomTimer:
return customTimelineTime;
case ingame_galgame_so.TimelineBase.MusicTime:
if (musicTimelineSource != null)
{
return Mathf.Max(0f, musicTimelineSource.time);
}
return Mathf.Max(0f, Time.unscaledTime - sceneStartRealtime);
default:
return Mathf.Max(0f, Time.unscaledTime - sceneStartRealtime);
}
}
private void ResolveDefinition()
{
resolvedDefinition = golSO != null ? golSO.GetResolvedDefinition() : null;
}
private bool DetectAdvanceInput()
{
if (!allowGlobalClickToAdvance)
{
return false;
}
if (Input.GetMouseButtonDown(0))
{
return true;
}
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
return true;
}
}
return Input.GetKeyDown(keyboardAdvanceKey) || Input.GetKeyDown(keyboardAdvanceKeyAlt);
}
}