Add prototype gameplay loop with character/battlefield assets and server game APIs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
udx
2026-10-20 18:50:00 +08:00
co-authored by Cursor
parent 79369e4473
commit 6c64210331
833 changed files with 998079 additions and 1042 deletions
@@ -6,7 +6,7 @@ using UnityEngine.UI;
namespace HotUpdate.UI
{
/// <summary>
/// UI_MainHUD 运行时绑定。
/// 营地主界面:绑定 JSON Prefab 入口、网络状态和断线重连。
/// </summary>
public sealed class MainHudView : MonoBehaviour
{
@@ -19,6 +19,7 @@ namespace HotUpdate.UI
Button _reconnectBtn;
public event Action OnReconnectClicked;
public event Action<string> OnHomeActionClicked;
public void Bind()
{
@@ -35,6 +36,16 @@ namespace HotUpdate.UI
_reconnectBtn.onClick.AddListener(() => OnReconnectClicked?.Invoke());
}
ShowReconnect(false);
foreach (var button in GetComponentsInChildren<Button>(true))
{
if (button == _reconnectBtn) continue;
var key = button.name.StartsWith("Btn_Nav", StringComparison.Ordinal)
? button.name.Substring(7)
: button.name.StartsWith("Btn_", StringComparison.Ordinal) ? button.name.Substring(4) : null;
if (key == null) continue;
button.onClick.RemoveAllListeners();
button.onClick.AddListener(() => OnHomeActionClicked?.Invoke(key));
}
}
public void SetStatus(string text)
@@ -47,6 +58,54 @@ namespace HotUpdate.UI
if (_pid != null) _pid.text = pid > 0 ? $"pid={pid}" : "pid=-";
}
public void SetPrototypeState(Gameplay.PrototypeSave state, Gameplay.PrototypeConfig config = null, long serverNow = 0)
{
SetText("Txt_Level", "Lv. " + state.level);
SetText("Txt_Coin", state.coins.ToString("N0"));
SetText("Txt_Diamond", "0");
SetText("Txt_Pinballs", state.balls.ToString());
SetText("Txt_TaskCaption", "教学目标");
SetText("Txt_Task", state.goalClaimed ? "教学目标已完成" : state.cleared ? "领取首通目标奖励" : state.shots == 0 ? "发射第一枚弹珠" : state.level < 2 ? "共享训练至 Lv.2" : "完成教学关卡 1-1");
SetText("Txt_AdventureHint", state.cleared ? "首通已完成 · 可重复挑战" : "首通另获糖果 40 · 不消耗体力");
if (config != null && state.schema >= 2)
{
var stage = config.Stage(state.UnlockedStage); bool complete = state.clearedStages[stage.id - 1] == 1;
SetText("Txt_Chapter", config.chapter);
SetText("Txt_Stage", stage.code + " · " + stage.name);
SetText("Txt_Reward_coin", complete ? "已领取" : stage.reward.coins.ToString());
SetText("Txt_Reward_pinball", complete ? "已领取" : stage.reward.balls.ToString());
SetText("Txt_AdventureHint", complete ? "本轮五关已完成 · 可免费重试" : "首通另获糖果 " + stage.reward.candy + " · 不消耗体力");
}
foreach (var child in GetComponentsInChildren<Transform>(true))
if (child.name.StartsWith("Dot_", StringComparison.Ordinal)) child.gameObject.SetActive(false);
if (state.mails != null)
foreach (var child in GetComponentsInChildren<Transform>(true))
if (child.name == "Dot_Mail") child.gameObject.SetActive(Array.Exists(state.mails, m => !m.expired && serverNow < m.expiresAt && (!m.read || !m.claimed && m.HasAttachment)));
if (config?.rewards?.chests != null && state.chests != null)
foreach (var child in GetComponentsInChildren<Transform>(true))
if (child.name == "Dot_Rewards") child.gameObject.SetActive(state.chestDailyClaimed == 0 || Array.Exists(state.chests, n => n > 0));
if (state.schema >= 5 && config?.daily != null)
{
int ready = 0; bool signin = false;
for (int i = 0; i < 3; i++) if (state.dailyClaimed[i] == 0 && state.dailyProgress[i] >= config.daily.tasks[i].target) ready++;
for (int i = 0; i < state.signinDays; i++) if (state.signinClaimed[i] == 0) signin = true;
foreach (var child in GetComponentsInChildren<Transform>(true))
if (child.name == "Dot_Tasks") child.gameObject.SetActive(ready > 0 || state.cleared && !state.goalClaimed);
else if (child.name == "Dot_Daily") child.gameObject.SetActive(signin);
if (state.goalClaimed)
{
SetText("Txt_TaskCaption", "每日目标");
SetText("Txt_Task", ready > 0 ? ready + "项奖励可领取" : "查看今日任务进度");
}
}
}
void SetText(string name, string value)
{
var label = FindTmp(name);
if (label != null) label.text = value;
}
public void ShowReconnect(bool visible, string message = null)
{
if (_reconnectPanel != null) _reconnectPanel.SetActive(visible);