feat: Add WorldStateFlagAttribute and custom property drawer for enhanced dialogue management
- Implemented WorldStateFlagAttribute to mark string fields as world state flags. - Created NarrativeNPCEditor for custom inspector to visualize dialogue version activation states. - Developed WorldStateFlagDrawer to provide dropdown menu for known flags in the inspector. - Introduced ActorModule for managing DialogueActorSO assets, including viewing, creating, and deleting actors. - Added DialogueModule for managing DialogueSequenceSO assets with detailed previews and action bars. - Established QuestModule for managing QuestSO assets, including objectives and branches. - Implemented QuestManagerPostprocessor to automatically refresh QuestManager's quest list on asset changes.
This commit is contained in:
@@ -26,6 +26,11 @@ namespace BaseGames.Dialogue
|
||||
private DialogueLine _currentLine;
|
||||
private const float DefaultTypewriterDelay = 0.03f;
|
||||
|
||||
// 缓存单个 WaitForSecondsRealtime,避免 TypeLine 每字符 new 分配。
|
||||
// 当 delay 值改变时才重新创建(不同行可能有不同打字速度)。
|
||||
private WaitForSecondsRealtime _cachedTypeDelay;
|
||||
private float _cachedTypeDelayValue = -1f;
|
||||
|
||||
/// <summary>当前是否仍在执行打字机效果。</summary>
|
||||
public bool IsTyping { get; private set; }
|
||||
|
||||
@@ -35,20 +40,22 @@ namespace BaseGames.Dialogue
|
||||
public void ShowLine(DialogueLine line)
|
||||
{
|
||||
_currentLine = line;
|
||||
_rootPanel.SetActive(true);
|
||||
_continuePrompt.SetActive(false);
|
||||
if (_rootPanel != null) _rootPanel.SetActive(true);
|
||||
if (_continuePrompt != null) _continuePrompt.SetActive(false);
|
||||
|
||||
// 说话人名称
|
||||
bool hasSpeaker = !string.IsNullOrEmpty(line.speakerNameKey);
|
||||
// 说话人名称(actor 优先,回退到直接字段)
|
||||
string resolvedNameKey = line.ResolvedNameKey;
|
||||
bool hasSpeaker = !string.IsNullOrEmpty(resolvedNameKey);
|
||||
if (_speakerNamePanel != null) _speakerNamePanel.SetActive(hasSpeaker);
|
||||
if (hasSpeaker && _speakerNameText != null)
|
||||
_speakerNameText.text = LocalizationManager.Get(line.speakerNameKey, "Dialogue");
|
||||
_speakerNameText.text = LocalizationManager.Get(resolvedNameKey, "Dialogue");
|
||||
|
||||
// 头像
|
||||
// 头像(actor 优先,回退到直接字段)
|
||||
var resolvedPortrait = line.ResolvedPortrait;
|
||||
if (_speakerPortrait != null)
|
||||
{
|
||||
_speakerPortrait.gameObject.SetActive(line.portraitSprite != null);
|
||||
if (line.portraitSprite != null) _speakerPortrait.sprite = line.portraitSprite;
|
||||
_speakerPortrait.gameObject.SetActive(resolvedPortrait != null);
|
||||
if (resolvedPortrait != null) _speakerPortrait.sprite = resolvedPortrait;
|
||||
}
|
||||
|
||||
// 语音播放
|
||||
@@ -95,6 +102,14 @@ namespace BaseGames.Dialogue
|
||||
{
|
||||
IsTyping = true;
|
||||
float delay = line.typewriterDelay > 0f ? line.typewriterDelay : DefaultTypewriterDelay;
|
||||
|
||||
// 复用缓存的 WaitForSecondsRealtime;仅当 delay 值变化时才重新 new
|
||||
if (_cachedTypeDelay == null || !Mathf.Approximately(_cachedTypeDelayValue, delay))
|
||||
{
|
||||
_cachedTypeDelay = new WaitForSecondsRealtime(delay);
|
||||
_cachedTypeDelayValue = delay;
|
||||
}
|
||||
|
||||
string text = LocalizationManager.Get(line.textKey ?? "", "Dialogue");
|
||||
|
||||
// 性能:StringBuilder 避免每帧字符串分配(O(n²) → O(n))
|
||||
@@ -105,7 +120,7 @@ namespace BaseGames.Dialogue
|
||||
{
|
||||
sb.Append(c);
|
||||
if (_dialogueText != null) _dialogueText.SetText(sb); // TMP SetText(StringBuilder) 零分配
|
||||
yield return new WaitForSecondsRealtime(delay);
|
||||
yield return _cachedTypeDelay;
|
||||
}
|
||||
|
||||
IsTyping = false;
|
||||
|
||||
Reference in New Issue
Block a user