M0 回合制战斗壳层:接口与单局状态、调试入口、暂停联动
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Battle;
|
||||
using SepCore.Definition;
|
||||
using SepCore.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.CustomComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// 单局战斗协调器(普通类,不挂场景)。
|
||||
/// 负责从单局状态构建请求、预留战斗占用、暂停/恢复探索更新与计时、打开/关闭战斗 UI;
|
||||
/// 后续里程碑在此创建并校验 BattleController,并消费 BattleResult 生成 BattleReturnPlan。
|
||||
/// 不负责回合排序、效果计算和 UI 控件状态。
|
||||
/// </summary>
|
||||
public sealed class RunBattleCoordinator
|
||||
{
|
||||
/// <summary>
|
||||
/// 尝试开始一场战斗。
|
||||
/// 战斗占用已激活时拒绝;请求构建失败时释放占用且不暂停地图。
|
||||
/// </summary>
|
||||
/// <param name="encounter">探索层创建的遭遇输入。</param>
|
||||
/// <returns>是否成功开始。</returns>
|
||||
public bool TryStartBattle(BattleEncounter encounter)
|
||||
{
|
||||
if (encounter == null)
|
||||
{
|
||||
Log.Error("Can not start battle with null encounter.");
|
||||
return false;
|
||||
}
|
||||
|
||||
TurnBattleComponent runBattle = GameEntry.TurnBattle;
|
||||
if (runBattle == null || runBattle.IsBattleActive)
|
||||
{
|
||||
Log.Warning("Can not start battle because battle occupancy is already active.");
|
||||
return false;
|
||||
}
|
||||
|
||||
BattleStartRequest request = BuildStartRequest(encounter);
|
||||
if (request == null)
|
||||
{
|
||||
Log.Warning("Can not start battle because start request is invalid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 预留战斗占用并暂停探索更新与单局计时;
|
||||
// 后续里程碑在此创建并校验 BattleController,失败则释放占用且不暂停地图
|
||||
runBattle.TryReserveBattle();
|
||||
runBattle.SetExplorationPaused(true);
|
||||
runBattle.SetTimerPaused(true);
|
||||
|
||||
GameEntry.UI.OpenUIForm(UIFormType.BattleForm);
|
||||
Log.Info("Battle started with encounter '{0}'.", encounter.EncounterId);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭调试壳层并恢复探索更新与单局计时。
|
||||
/// M0 调试入口专用;M7 起由 ApplyResult 按战斗结果统一回写与恢复。
|
||||
/// </summary>
|
||||
public void EndDebugBattle()
|
||||
{
|
||||
TurnBattleComponent runBattle = GameEntry.TurnBattle;
|
||||
if (runBattle == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UGuiForm form = GameEntry.UI.GetUIForm(UIFormType.BattleForm);
|
||||
if (form != null)
|
||||
{
|
||||
GameEntry.UI.CloseUIForm(form);
|
||||
}
|
||||
|
||||
runBattle.SetExplorationPaused(false);
|
||||
runBattle.SetTimerPaused(false);
|
||||
runBattle.ReleaseBattle();
|
||||
Log.Info("Debug battle closed.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从单局临时角色状态与共享随机源构建启动请求。
|
||||
/// 请求创建后视为只读;构建失败返回 null,不消耗随机数。
|
||||
/// </summary>
|
||||
private static BattleStartRequest BuildStartRequest(BattleEncounter encounter)
|
||||
{
|
||||
IRunRandomSource random = GameEntry.Random != null ? GameEntry.Random.Random : null;
|
||||
if (random == null)
|
||||
{
|
||||
Log.Warning("Can not start battle because run random source is not initialized.");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<BattlePlayerInput> players = new List<BattlePlayerInput>();
|
||||
foreach (RunPlayerState state in GameEntry.TurnBattle.Players)
|
||||
{
|
||||
players.Add(new BattlePlayerInput(state.CharacterId, state.PartyOrder,
|
||||
state.CurrentHp, state.CurrentMp, state.MaxHp, state.MaxMp,
|
||||
state.Atk, state.Mat, state.Speed,
|
||||
state.AttackActionId, state.SkillActionId));
|
||||
}
|
||||
|
||||
if (players.Count == 0)
|
||||
{
|
||||
Log.Warning("Can not start battle because no run player state exists.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new BattleStartRequest(encounter.EncounterId, players, encounter.EnemyPartyConfigId,
|
||||
encounter.IsPreemptive, random);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0146e261d98d40109183900a1d033fc9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
namespace SepCore.CustomComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// 单局临时角色状态。
|
||||
/// 数值由单局快照构建器在开战前从角色与装备结算得到;战斗期间只读,战斗结束回写当前 HP/MP。
|
||||
/// </summary>
|
||||
public sealed class RunPlayerState
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色配置标识。
|
||||
/// </summary>
|
||||
public int CharacterId;
|
||||
|
||||
/// <summary>
|
||||
/// 当前战备中的顺序,1 开始。
|
||||
/// </summary>
|
||||
public int PartyOrder;
|
||||
|
||||
/// <summary>
|
||||
/// 当前 HP。
|
||||
/// </summary>
|
||||
public int CurrentHp;
|
||||
|
||||
/// <summary>
|
||||
/// 当前 MP。
|
||||
/// </summary>
|
||||
public int CurrentMp;
|
||||
|
||||
/// <summary>
|
||||
/// 已结算装备加成的最终 HP 上限。
|
||||
/// </summary>
|
||||
public int MaxHp;
|
||||
|
||||
/// <summary>
|
||||
/// 已结算装备加成的最终 MP 上限。
|
||||
/// </summary>
|
||||
public int MaxMp;
|
||||
|
||||
/// <summary>
|
||||
/// 已结算装备加成的最终攻击。
|
||||
/// </summary>
|
||||
public int Atk;
|
||||
|
||||
/// <summary>
|
||||
/// 已结算装备加成的最终魔力。
|
||||
/// </summary>
|
||||
public int Mat;
|
||||
|
||||
/// <summary>
|
||||
/// 已结算装备加成的最终速度。
|
||||
/// </summary>
|
||||
public int Speed;
|
||||
|
||||
/// <summary>
|
||||
/// 普通攻击行动配置 ID。
|
||||
/// </summary>
|
||||
public int AttackActionId;
|
||||
|
||||
/// <summary>
|
||||
/// 该角色首版唯一技能行动配置 ID。
|
||||
/// </summary>
|
||||
public int SkillActionId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3caaef559cc641769b9ede0b4d033532
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,136 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.CustomComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// 单局战斗组件。
|
||||
/// 负责本局临时角色状态、计时、探索暂停标志和战斗占用的最小状态。
|
||||
/// 本局种子与共享随机源由独立的 RandomComponent 持有,战斗只沿用,不创建私有随机源。
|
||||
/// 战斗协调(构建请求、打开 UI、回写结果)由独立的 RunBattleCoordinator 负责。
|
||||
/// </summary>
|
||||
public class TurnBattleComponent : GameFrameworkComponent
|
||||
{
|
||||
private readonly List<RunPlayerState> _players = new List<RunPlayerState>();
|
||||
private float _elapsedMs;
|
||||
private bool _timerPaused;
|
||||
private bool _explorationPaused;
|
||||
private bool _battleActive;
|
||||
|
||||
/// <summary>
|
||||
/// 获取本局临时角色状态列表(只读)。
|
||||
/// </summary>
|
||||
public IReadOnlyList<RunPlayerState> Players => _players;
|
||||
|
||||
/// <summary>
|
||||
/// 获取本局已流逝时间(毫秒)。
|
||||
/// </summary>
|
||||
public long RunElapsedMs => (long)_elapsedMs;
|
||||
|
||||
/// <summary>
|
||||
/// 获取单局计时是否已暂停。
|
||||
/// </summary>
|
||||
public bool IsTimerPaused => _timerPaused;
|
||||
|
||||
/// <summary>
|
||||
/// 获取探索更新是否已暂停。
|
||||
/// 战斗期间为 true,地图更新统一以此作为门禁。
|
||||
/// </summary>
|
||||
public bool IsExplorationPaused => _explorationPaused;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前是否存在战斗占用。
|
||||
/// 战斗重复进入由此标志拒绝。
|
||||
/// </summary>
|
||||
public bool IsBattleActive => _battleActive;
|
||||
|
||||
/// <summary>
|
||||
/// 开始一局新的单局:重置全部临时状态。
|
||||
/// </summary>
|
||||
public void BeginRun()
|
||||
{
|
||||
_players.Clear();
|
||||
_elapsedMs = 0;
|
||||
_timerPaused = false;
|
||||
_explorationPaused = false;
|
||||
_battleActive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束当前单局,清空全部临时状态。
|
||||
/// </summary>
|
||||
public void EndRun()
|
||||
{
|
||||
_players.Clear();
|
||||
_elapsedMs = 0;
|
||||
_timerPaused = false;
|
||||
_explorationPaused = false;
|
||||
_battleActive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用指定状态替换本局临时角色列表,保持战备顺序。
|
||||
/// </summary>
|
||||
/// <param name="players">新的临时角色状态,可为空。</param>
|
||||
public void ReplacePlayers(IEnumerable<RunPlayerState> players)
|
||||
{
|
||||
_players.Clear();
|
||||
if (players != null)
|
||||
{
|
||||
_players.AddRange(players);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预留战斗占用,拒绝同一帧或未结束战斗的重复进入。
|
||||
/// </summary>
|
||||
/// <returns>预留成功返回 true;已存在战斗占用时返回 false。</returns>
|
||||
public bool TryReserveBattle()
|
||||
{
|
||||
if (_battleActive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_battleActive = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放战斗占用。
|
||||
/// </summary>
|
||||
public void ReleaseBattle()
|
||||
{
|
||||
_battleActive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置探索更新暂停状态。
|
||||
/// </summary>
|
||||
/// <param name="paused">是否暂停探索更新。</param>
|
||||
public void SetExplorationPaused(bool paused)
|
||||
{
|
||||
_explorationPaused = paused;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置单局计时暂停状态。
|
||||
/// </summary>
|
||||
/// <param name="paused">是否暂停单局计时。</param>
|
||||
public void SetTimerPaused(bool paused)
|
||||
{
|
||||
_timerPaused = paused;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_timerPaused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_elapsedMs += Time.deltaTime * 1000f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ceac378d38794bafb31a203753565121
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user