using System.Collections.Generic; using SepCore.Battle; using SepCore.Definition; using UnityEngine; using UnityGameFramework.Runtime; namespace SepCore.UI { /// /// 战斗界面逻辑(手写 partial,与自动生成的 BattleForm.cs 合并)。 /// UI 只读取 BattleViewState / BattleStep / BattleResult,不持有 BattleRuntime 或 BattleUnit; /// 玩家指令经 GameEntry.TurnBattle.SubmitCommand 提交,推进结果统一回填界面。 /// 我方卡片按玩家单位数显示/隐藏;敌人槽和回合顺序槽按当前战局从模板动态实例化。 /// public partial class BattleForm : UGuiForm { private BattleResult _result; private int _displayedRound; private readonly List _turnSlots = new List(); private readonly List _turnSlotUnitIds = new List(); protected override void OnInit(object userData) { base.OnInit(userData); View.attackButton.onClick.AddListener(OnAttackButtonClick); View.skillButton.onClick.AddListener(OnSkillButtonClick); View.itemButton.onClick.AddListener(OnItemButtonClick); View.escapeButton.onClick.AddListener(OnEscapeButtonClick); // M1 只开放攻击;道具、技能、逃跑在后续里程碑接入 View.itemButton.interactable = false; View.skillButton.interactable = false; View.escapeButton.interactable = false; } protected override void OnOpen(object userData) { base.OnOpen(userData); if (GameEntry.TurnBattle != null) { GameEntry.TurnBattle.SetStepListener(ApplyStep); } _result = null; _displayedRound = 0; _turnSlots.Clear(); _turnSlotUnitIds.Clear(); Refresh(GameEntry.TurnBattle != null ? GameEntry.TurnBattle.GetViewState() : null); } protected override void OnClose(bool isShutdown, object userData) { if (GameEntry.TurnBattle != null) { GameEntry.TurnBattle.SetStepListener(null); } View.attackButton.onClick.RemoveListener(OnAttackButtonClick); View.skillButton.onClick.RemoveListener(OnSkillButtonClick); View.itemButton.onClick.RemoveListener(OnItemButtonClick); View.escapeButton.onClick.RemoveListener(OnEscapeButtonClick); base.OnClose(isShutdown, userData); } private void OnAttackButtonClick() { if (GameEntry.TurnBattle == null || !GameEntry.TurnBattle.IsBattleActive) { return; } BattleViewState view = GameEntry.TurnBattle.GetViewState(); if (view == null || view.CurrentActorUnitId == 0) { return; } BattleUnitView actor = FindUnit(view, view.CurrentActorUnitId); if (actor == null || actor.Faction != BattleFaction.Player) { return; } int attackActionId = FindAttackActionId(view); int targetUnitId = FindFirstActiveEnemy(view); if (attackActionId == 0 || targetUnitId == 0) { return; } BattleStep step = GameEntry.TurnBattle.SubmitCommand(new BattleCommand( actor.BattleUnitId, BattleActionType.Attack, attackActionId, new List { targetUnitId })); ApplyStep(step); } private void ApplyStep(BattleStep step) { if (step == null) { return; } if (step.Result != null) { _result = step.Result; } Refresh(step.View); } private void Refresh(BattleViewState view) { if (view == null) { return; } RefreshPlayerCards(view); RefreshEnemySlots(view); RefreshTurnSlots(view); RefreshActionPanel(view); } private void RefreshPlayerCards(BattleViewState view) { int index = 0; foreach (BattleUnitView unit in view.Units) { if (unit.Faction != BattleFaction.Player) { continue; } BattleActorCardItem card = GetPlayerCard(index); if (card != null) { card.gameObject.SetActive(true); card.SetUnit(unit, unit.BattleUnitId == view.CurrentActorUnitId); } index++; } for (int i = index; i < 4; i++) { BattleActorCardItem card = GetPlayerCard(i); if (card != null) { card.gameObject.SetActive(false); } } } private void RefreshEnemySlots(BattleViewState view) { BattleEnemySlotItem template = View.battleEnemySlotTemplate; if (template == null || View.enemySlotsRoot == null) { Log.Warning("BattleForm enemy slots are not configured."); return; } template.gameObject.SetActive(false); ClearSlots(View.enemySlotsRoot, template.transform); foreach (BattleUnitView unit in view.Units) { if (unit.Faction != BattleFaction.Enemy) { continue; } BattleEnemySlotItem slot = Instantiate(template, View.enemySlotsRoot); slot.gameObject.SetActive(true); slot.SetEnemy(unit, unit.BattleUnitId == view.CurrentActorUnitId); } } private void RefreshTurnSlots(BattleViewState view) { BattleTurnSlotItem template = View.battleTurnSlotTemplate; if (template == null || View.turnSlotsRoot == null) { Log.Warning("BattleForm turn slots are not configured."); return; } if (view.RoundNumber != _displayedRound) { RebuildTurnSlots(view, template); _displayedRound = view.RoundNumber; return; } // 同轮内只移动当前行动者高亮,不隐藏已行动单位 for (int i = 0; i < _turnSlots.Count; i++) { _turnSlots[i].SetCurrentActor(_turnSlotUnitIds[i] == view.CurrentActorUnitId); } } /// /// 新一轮开始时重建本轮完整顺序:全部活跃单位按显示顺序排列, /// 当前行动者高亮;本轮内已行动单位保持可见。 /// private void RebuildTurnSlots(BattleViewState view, BattleTurnSlotItem template) { template.gameObject.SetActive(false); ClearSlots(View.turnSlotsRoot, template.transform); _turnSlots.Clear(); _turnSlotUnitIds.Clear(); foreach (BattleUnitView unit in view.Units) { if (unit.IsDefeated || unit.IsEscaped) { continue; } BattleTurnSlotItem slot = Instantiate(template, View.turnSlotsRoot); slot.gameObject.SetActive(true); slot.SetTurnSlot(unit, unit.BattleUnitId == view.CurrentActorUnitId); _turnSlots.Add(slot); _turnSlotUnitIds.Add(unit.BattleUnitId); } } private void RefreshActionPanel(BattleViewState view) { if (_result != null) { View.currentActorText.text = GetOutcomeText(_result.Outcome); View.attackButton.interactable = false; return; } BattleUnitView actor = FindUnit(view, view.CurrentActorUnitId); bool playerTurn = actor != null && actor.Faction == BattleFaction.Player; View.currentActorText.text = string.Format("第 {0} 轮 {1} 行动", view.RoundNumber, actor != null ? BattleUnitViewHelper.GetDisplayName(actor) : string.Empty); View.attackButton.interactable = playerTurn; } private static string GetOutcomeText(BattleOutcome outcome) { switch (outcome) { case BattleOutcome.Victory: return "胜利!"; case BattleOutcome.AllEscaped: return "全员逃跑"; case BattleOutcome.PartialEscapeDefeat: return "部分逃跑,战斗失败"; case BattleOutcome.TotalDefeat: return "全员阵亡,单局失败"; default: return string.Empty; } } private static int FindAttackActionId(BattleViewState view) { foreach (int actionId in view.AvailableActionIds) { BattleActionConfig action = GameEntry.Luban.Get(actionId); if (action != null && action.ActionType == BattleActionType.Attack) { return actionId; } } return 0; } private static int FindFirstActiveEnemy(BattleViewState view) { foreach (BattleUnitView unit in view.Units) { if (unit.Faction == BattleFaction.Enemy && !unit.IsDefeated && !unit.IsEscaped) { return unit.BattleUnitId; } } return 0; } private static BattleUnitView FindUnit(BattleViewState view, int unitId) { foreach (BattleUnitView unit in view.Units) { if (unit.BattleUnitId == unitId) { return unit; } } return null; } private BattleActorCardItem GetPlayerCard(int index) { switch (index) { case 0: return View.playerCard1; case 1: return View.playerCard2; case 2: return View.playerCard3; case 3: return View.playerCard4; default: return null; } } private static void ClearSlots(RectTransform root, Transform template) { for (int i = root.childCount - 1; i >= 0; i--) { Transform child = root.GetChild(i); if (child == template) { continue; } Destroy(child.gameObject); } } private void OnSkillButtonClick() { // M3 接入 } private void OnItemButtonClick() { // 道具首版禁用,不产生指令 } private void OnEscapeButtonClick() { // M5 接入 } } }