feat(cordis): 接入上下文组合与模组事务热替换
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
using System.Collections;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace ShrinkTutorial
|
||||
{
|
||||
public class ShrinkTutorialSampleSceneController : MonoBehaviour
|
||||
{
|
||||
public const string TutorialId = "sample.shrink_tutorial.basic";
|
||||
public const string RewardAnchorId = "sample.reward.item";
|
||||
public const string RewardClaimEventName = "sample.reward.claimed";
|
||||
|
||||
[SerializeField] private Button openInventoryButton;
|
||||
[SerializeField] private Button spawnRewardButton;
|
||||
[SerializeField] private GameObject inventoryPanel;
|
||||
[SerializeField] private RectTransform rewardContainer;
|
||||
[SerializeField] private TextMeshProUGUI statusText;
|
||||
|
||||
private Button _spawnedRewardButton;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
AutoWire();
|
||||
BindButtons();
|
||||
LogDebug($"Awake, openButton={DescribeObject(openInventoryButton)}, spawnButton={DescribeObject(spawnRewardButton)}, inventoryPanel={DescribeObject(inventoryPanel)}");
|
||||
|
||||
if (inventoryPanel)
|
||||
inventoryPanel.SetActive(false);
|
||||
|
||||
ClearRewardItems();
|
||||
SetStatus("Waiting for tutorial start.");
|
||||
}
|
||||
|
||||
private IEnumerator Start()
|
||||
{
|
||||
yield return null;
|
||||
var tutorialManager = ShrinkTutorialManager.EnsureInstance();
|
||||
tutorialManager.ClearProgress(TutorialId);
|
||||
tutorialManager.StartTutorial(TutorialId);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (openInventoryButton)
|
||||
openInventoryButton.onClick.RemoveListener(HandleOpenInventory);
|
||||
|
||||
if (spawnRewardButton)
|
||||
spawnRewardButton.onClick.RemoveListener(HandleSpawnReward);
|
||||
|
||||
if (_spawnedRewardButton)
|
||||
_spawnedRewardButton.onClick.RemoveListener(HandleClaimReward);
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
AutoWire();
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
AutoWire();
|
||||
}
|
||||
|
||||
public void HandleOpenInventory()
|
||||
{
|
||||
LogDebug($"HandleOpenInventory before, inventoryActive={inventoryPanel && inventoryPanel.activeSelf}");
|
||||
if (inventoryPanel)
|
||||
inventoryPanel.SetActive(true);
|
||||
|
||||
SetStatus("Inventory panel opened.");
|
||||
LogDebug($"HandleOpenInventory after, inventoryActive={inventoryPanel && inventoryPanel.activeSelf}");
|
||||
}
|
||||
|
||||
public void HandleSpawnReward()
|
||||
{
|
||||
LogDebug($"HandleSpawnReward start, hasReward={_spawnedRewardButton}");
|
||||
if (!rewardContainer)
|
||||
return;
|
||||
|
||||
if (_spawnedRewardButton)
|
||||
{
|
||||
SetStatus("Reward item has already been created.");
|
||||
return;
|
||||
}
|
||||
|
||||
var buttonObject = new GameObject("RuntimeRewardButton",
|
||||
typeof(RectTransform),
|
||||
typeof(Image),
|
||||
typeof(Button),
|
||||
typeof(LayoutElement),
|
||||
typeof(ShrinkTutorialAnchor));
|
||||
var rectTransform = buttonObject.GetComponent<RectTransform>();
|
||||
rectTransform.SetParent(rewardContainer, false);
|
||||
rectTransform.anchorMin = new Vector2(0f, 0.5f);
|
||||
rectTransform.anchorMax = new Vector2(1f, 0.5f);
|
||||
rectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
rectTransform.offsetMin = new Vector2(0f, 0f);
|
||||
rectTransform.offsetMax = new Vector2(0f, 0f);
|
||||
rectTransform.sizeDelta = new Vector2(0f, 58f);
|
||||
|
||||
var image = buttonObject.GetComponent<Image>();
|
||||
image.color = new Color(0.18f, 0.48f, 0.28f, 1f);
|
||||
|
||||
var button = buttonObject.GetComponent<Button>();
|
||||
button.targetGraphic = image;
|
||||
button.onClick.AddListener(HandleClaimReward);
|
||||
_spawnedRewardButton = button;
|
||||
|
||||
var layoutElement = buttonObject.GetComponent<LayoutElement>();
|
||||
layoutElement.minHeight = 58f;
|
||||
layoutElement.preferredHeight = 58f;
|
||||
layoutElement.preferredWidth = 420f;
|
||||
layoutElement.flexibleWidth = 1f;
|
||||
|
||||
var anchor = buttonObject.GetComponent<ShrinkTutorialAnchor>();
|
||||
anchor.SetAnchorId(RewardAnchorId);
|
||||
|
||||
var labelObject = new GameObject("Label", typeof(RectTransform), typeof(TextMeshProUGUI));
|
||||
var labelRect = labelObject.GetComponent<RectTransform>();
|
||||
labelRect.SetParent(rectTransform, false);
|
||||
labelRect.anchorMin = Vector2.zero;
|
||||
labelRect.anchorMax = Vector2.one;
|
||||
labelRect.offsetMin = Vector2.zero;
|
||||
labelRect.offsetMax = Vector2.zero;
|
||||
|
||||
var label = labelObject.GetComponent<TextMeshProUGUI>();
|
||||
label.text = "Claim Runtime Reward";
|
||||
label.fontSize = 24f;
|
||||
label.alignment = TextAlignmentOptions.Center;
|
||||
label.color = Color.white;
|
||||
label.enableWordWrapping = false;
|
||||
label.overflowMode = TextOverflowModes.Ellipsis;
|
||||
|
||||
if (spawnRewardButton)
|
||||
spawnRewardButton.interactable = false;
|
||||
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(rewardContainer);
|
||||
Canvas.ForceUpdateCanvases();
|
||||
|
||||
SetStatus("Reward button created. Waiting for dynamic anchor step.");
|
||||
LogDebug($"HandleSpawnReward created reward button, path={GetTransformPath(buttonObject.transform)}");
|
||||
}
|
||||
|
||||
public void HandleClaimReward()
|
||||
{
|
||||
LogDebug($"HandleClaimReward start, hasReward={_spawnedRewardButton}");
|
||||
if (_spawnedRewardButton)
|
||||
{
|
||||
_spawnedRewardButton.interactable = false;
|
||||
var image = _spawnedRewardButton.GetComponent<Image>();
|
||||
if (image)
|
||||
image.color = new Color(0.25f, 0.25f, 0.25f, 1f);
|
||||
|
||||
var label = _spawnedRewardButton.GetComponentInChildren<TextMeshProUGUI>();
|
||||
if (label)
|
||||
label.text = "Reward Claimed";
|
||||
}
|
||||
|
||||
SetStatus("Custom completion event sent.");
|
||||
ShrinkTutorialManager.Instance?.CompleteStep(RewardClaimEventName);
|
||||
LogDebug($"HandleClaimReward complete, event={RewardClaimEventName}");
|
||||
}
|
||||
|
||||
private void BindButtons()
|
||||
{
|
||||
if (openInventoryButton)
|
||||
{
|
||||
openInventoryButton.onClick.RemoveListener(HandleOpenInventory);
|
||||
openInventoryButton.onClick.AddListener(HandleOpenInventory);
|
||||
LogDebug($"Bound openInventoryButton -> {GetTransformPath(openInventoryButton.transform)}");
|
||||
}
|
||||
|
||||
if (spawnRewardButton)
|
||||
{
|
||||
spawnRewardButton.onClick.RemoveListener(HandleSpawnReward);
|
||||
spawnRewardButton.onClick.AddListener(HandleSpawnReward);
|
||||
LogDebug($"Bound spawnRewardButton -> {GetTransformPath(spawnRewardButton.transform)}");
|
||||
}
|
||||
}
|
||||
|
||||
private void AutoWire()
|
||||
{
|
||||
if (!openInventoryButton)
|
||||
openInventoryButton = FindButton("Tutorial Sample Canvas/OpenInventoryButton");
|
||||
|
||||
if (!spawnRewardButton)
|
||||
spawnRewardButton = FindButton("Tutorial Sample Canvas/InventoryPanel/SpawnRewardButton");
|
||||
|
||||
if (!inventoryPanel)
|
||||
{
|
||||
var inventoryTransform = transform.Find("Tutorial Sample Canvas/InventoryPanel");
|
||||
inventoryPanel = inventoryTransform ? inventoryTransform.gameObject : null;
|
||||
}
|
||||
|
||||
if (!rewardContainer)
|
||||
rewardContainer = FindRectTransform("Tutorial Sample Canvas/InventoryPanel/RewardContainer");
|
||||
|
||||
if (!statusText)
|
||||
statusText = FindText("Tutorial Sample Canvas/StatusText");
|
||||
}
|
||||
|
||||
private void ClearRewardItems()
|
||||
{
|
||||
if (!rewardContainer)
|
||||
return;
|
||||
|
||||
for (var i = rewardContainer.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
Destroy(rewardContainer.GetChild(i).gameObject);
|
||||
}
|
||||
|
||||
_spawnedRewardButton = null;
|
||||
|
||||
if (spawnRewardButton)
|
||||
spawnRewardButton.interactable = true;
|
||||
}
|
||||
|
||||
private void SetStatus(string text)
|
||||
{
|
||||
if (statusText)
|
||||
statusText.text = text;
|
||||
}
|
||||
|
||||
private Button FindButton(string path)
|
||||
{
|
||||
var target = transform.Find(path);
|
||||
return target ? target.GetComponent<Button>() : null;
|
||||
}
|
||||
|
||||
private RectTransform FindRectTransform(string path)
|
||||
{
|
||||
var target = transform.Find(path);
|
||||
return target ? target as RectTransform : null;
|
||||
}
|
||||
|
||||
private TextMeshProUGUI FindText(string path)
|
||||
{
|
||||
var target = transform.Find(path);
|
||||
return target ? target.GetComponent<TextMeshProUGUI>() : null;
|
||||
}
|
||||
|
||||
[System.Diagnostics.Conditional("UNITY_EDITOR")]
|
||||
private static void LogDebug(string message)
|
||||
{
|
||||
if (!IsDebugLoggingEnabled())
|
||||
return;
|
||||
|
||||
Debug.Log($"[ShrinkTutorialSample][Debug] {message}");
|
||||
}
|
||||
|
||||
private static bool IsDebugLoggingEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string DescribeObject(Object value)
|
||||
{
|
||||
return value ? value.name : "<null>";
|
||||
}
|
||||
|
||||
private static string GetTransformPath(Transform transform)
|
||||
{
|
||||
if (!transform)
|
||||
return "<null>";
|
||||
|
||||
var path = transform.name;
|
||||
while (transform.parent)
|
||||
{
|
||||
transform = transform.parent;
|
||||
path = $"{transform.name}/{path}";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user