调整对话,将 Combine 接入对话

This commit is contained in:
2026-04-22 22:21:09 +08:00
parent 68d8db79c5
commit 113358330c
26 changed files with 455 additions and 329 deletions
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using Event;
using UI;
using UnityEngine;
@@ -14,12 +13,9 @@ namespace CustomComponent
[DisallowMultipleComponent]
public class CombineComponent : GameFrameworkComponent
{
#region Inspector Config
private const int MaxCombineRoundCount = 2;
/// <summary>
/// 是否自动收集子节点中的槽位和部件。
/// </summary>
[SerializeField] private bool _autoCollectChildren = true;
#region Inspector Config
/// <summary>
/// 组件启用时是否自动开始拼装。
@@ -41,22 +37,17 @@ namespace CustomComponent
/// </summary>
[SerializeField] private Transform _puzzleRoot = null;
/// <summary>
/// Combine 展示关卡序列(当前固定两次,按顺序消费)。
/// </summary>
[SerializeField] private List<GameObject> _levelStructurePrefabs = new List<GameObject>();
[SerializeField] [TextArea(1, 3)] private string _successHint = "拼接成功";
[SerializeField] [TextArea(1, 3)] private string _orderErrorHint = "顺序错误";
[SerializeField] [TextArea(1, 3)] private string _positionErrorHint = "位置错误";
/// <summary>
/// 当前参与拼装的槽位列表。
/// </summary>
[SerializeField] private List<CombineSlot> _slots = new List<CombineSlot>();
/// <summary>
/// 当前参与拼装的可拖拽部件列表。
/// </summary>
[SerializeField] private List<CombineDraggablePart> _parts = new List<CombineDraggablePart>();
/// <summary>
/// 拼装完成事件。
/// </summary>
@@ -69,6 +60,16 @@ namespace CustomComponent
private CombineFormContext _formContext;
private CombineFormController _formController;
/// <summary>
/// 当前拼装场景中收集到的槽位(运行态)。
/// </summary>
private readonly List<CombineSlot> _runtimeSlots = new List<CombineSlot>();
/// <summary>
/// 当前拼装场景中收集到的拖拽部件(运行态)。
/// </summary>
private readonly List<CombineDraggablePart> _runtimeParts = new List<CombineDraggablePart>();
/// <summary>
/// 按顺序排序后的槽位缓存。
/// </summary>
@@ -99,6 +100,11 @@ namespace CustomComponent
/// </summary>
private bool _isPaused = false;
/// <summary>
/// 下一次启动要使用的展示关卡索引。
/// </summary>
private int _nextLevelStructureIndex = 0;
#endregion
#region Public Query
@@ -142,26 +148,26 @@ namespace CustomComponent
/// </summary>
public int? StartLevel(CombineFormContext context)
{
if (context == null)
if (!TryBuildRuntimeFormContext(context, out CombineFormContext runtimeContext))
{
Log.Warning("CoreGameplayA start failed. context is null.");
return null;
}
ClearRuntimeContext();
SetFormContext(context);
SetFormContext(runtimeContext);
EnsureFormController();
// 先关闭上一次UI,避免重复打开。
_formController.CloseUI();
int? serialId = _formController.OpenUI(context);
int? serialId = _formController.OpenUI(runtimeContext);
if (!serialId.HasValue)
{
Log.Warning("CoreGameplayA start failed. OpenUI returned null.");
return null;
}
_nextLevelStructureIndex++;
return serialId;
}
@@ -183,10 +189,7 @@ namespace CustomComponent
/// </summary>
public void StartPuzzle()
{
if (_autoCollectChildren)
{
CollectChildren();
}
CollectChildren();
BuildOrderedSlotList();
PrepareSlots();
@@ -410,8 +413,8 @@ namespace CustomComponent
_formContext = null;
_puzzleRoot = null;
_dragRoot = null;
_slots.Clear();
_parts.Clear();
_runtimeSlots.Clear();
_runtimeParts.Clear();
_orderedSlots.Clear();
_nextOrderSlotIndex = 0;
_placedCount = 0;
@@ -439,6 +442,47 @@ namespace CustomComponent
}
}
private bool TryBuildRuntimeFormContext(CombineFormContext context, out CombineFormContext runtimeContext)
{
runtimeContext = context ?? new CombineFormContext();
if (!TryGetNextLevelStructurePrefab(out GameObject structurePrefab))
{
return false;
}
runtimeContext.StructurePrefab = structurePrefab;
return true;
}
private bool TryGetNextLevelStructurePrefab(out GameObject prefab)
{
prefab = null;
if (_levelStructurePrefabs == null || _levelStructurePrefabs.Count == 0)
{
Log.Warning("CoreGameplayA start failed. level structure list is empty.");
return false;
}
int maxPlayableCount = Mathf.Min(MaxCombineRoundCount, _levelStructurePrefabs.Count);
if (_nextLevelStructureIndex < 0 || _nextLevelStructureIndex >= maxPlayableCount)
{
Log.Warning("CoreGameplayA start skipped. No remaining level structure prefab. used={0}, total={1}.",
_nextLevelStructureIndex.ToString(), maxPlayableCount.ToString());
return false;
}
prefab = _levelStructurePrefabs[_nextLevelStructureIndex];
if (prefab != null)
{
return true;
}
Log.Warning("CoreGameplayA start failed. level structure prefab at index {0} is null.",
_nextLevelStructureIndex.ToString());
return false;
}
#endregion
#region Collection And Preparation
@@ -448,11 +492,19 @@ namespace CustomComponent
/// </summary>
private void CollectChildren()
{
_slots.Clear();
_parts.Clear();
_runtimeSlots.Clear();
_runtimeParts.Clear();
Transform collectRoot = _puzzleRoot != null ? _puzzleRoot : transform;
_slots = collectRoot.GetComponentsInChildren<CombineSlot>(true).ToList();
CombineSlot[] foundSlots = collectRoot.GetComponentsInChildren<CombineSlot>(true);
for (int i = 0; i < foundSlots.Length; i++)
{
CombineSlot slot = foundSlots[i];
if (slot != null)
{
_runtimeSlots.Add(slot);
}
}
CollectUniqueParts(collectRoot);
if (_dragRoot != null && !ReferenceEquals(_dragRoot, collectRoot))
@@ -460,10 +512,10 @@ namespace CustomComponent
CollectUniqueParts(_dragRoot);
}
if (_slots.Count == 0 || _parts.Count == 0)
if (_runtimeSlots.Count == 0 || _runtimeParts.Count == 0)
{
Log.Warning("CoreGameplayA collect failed. slots={0}, parts={1}.", _slots.Count.ToString(),
_parts.Count.ToString());
Log.Warning("CoreGameplayA collect failed. slots={0}, parts={1}.", _runtimeSlots.Count.ToString(),
_runtimeParts.Count.ToString());
}
}
@@ -481,12 +533,12 @@ namespace CustomComponent
for (int i = 0; i < parts.Length; i++)
{
CombineDraggablePart part = parts[i];
if (part == null || _parts.Contains(part))
if (part == null || _runtimeParts.Contains(part))
{
continue;
}
_parts.Add(part);
_runtimeParts.Add(part);
}
}
@@ -497,9 +549,9 @@ namespace CustomComponent
{
_orderedSlots.Clear();
for (int i = 0; i < _slots.Count; i++)
for (int i = 0; i < _runtimeSlots.Count; i++)
{
CombineSlot slot = _slots[i];
CombineSlot slot = _runtimeSlots[i];
if (slot != null)
{
_orderedSlots.Add(slot);
@@ -527,9 +579,9 @@ namespace CustomComponent
/// </summary>
private void PrepareParts()
{
for (int i = 0; i < _parts.Count; i++)
for (int i = 0; i < _runtimeParts.Count; i++)
{
CombineDraggablePart part = _parts[i];
CombineDraggablePart part = _runtimeParts[i];
if (part == null)
{
continue;
@@ -9,7 +9,6 @@ namespace CustomComponent
public sealed class StoryCombineConfig
{
public bool AutoStart = true;
public GameObject StructurePrefab;
[FormerlySerializedAs("PartPrefabs")] public List<Sprite> PartSprites = new List<Sprite>();
}
}
@@ -299,7 +299,6 @@ namespace CustomComponent
return new CombineFormContext
{
StructurePrefab = config.StructurePrefab,
PartSprites = ClonePartSprites(config.PartSprites),
AutoStart = config.AutoStart
};