refactor & fix
- 将 `CombatScheduler` 的职责分散到 3 个类中
- `PhaseLoopRuntime`:负责关卡各波次的调度
- `CombatLoadSession`:负责地图与 UI 等资源的加载
- `CombatEventBridge`:负责相关事件的处理
- 统一了战斗的命名为 `Combat`
- 调整了各个地图的坐标,使其位于摄像头中心
- 新增了 CombatInfoForm 展示战斗内的信息
- 补充了循环执行 LevelPhase,手动结束战斗的逻辑
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 638583d0231ea31459f5c3dd4e934ce5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f613b24c1e065e542b7bb847939acba3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class CombatInfoFormContext : UIContext
|
||||
{
|
||||
public string LevelMetaText;
|
||||
public string LevelPhaseText;
|
||||
public string CoinText;
|
||||
public bool CanPause;
|
||||
public bool CanEnd;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f486ea7237d4edb9e56147cf540ae69
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a49c1dd9119c8d34c95ea2a22dcd7d2c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,151 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.Definition;
|
||||
using GameFramework.Event;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class CombatInfoFormController : UIFormControllerCommonBase<CombatInfoFormContext, CombatInfoForm>
|
||||
{
|
||||
private CombatInfoFormUseCase _useCase;
|
||||
|
||||
protected override UIFormType UIFormTypeId => UIFormType.CombatInfoForm;
|
||||
|
||||
protected override void RefreshUI(CombatInfoForm form, CombatInfoFormContext context)
|
||||
{
|
||||
form.RefreshUI(context);
|
||||
}
|
||||
|
||||
protected override void SubscribeCustomEvents()
|
||||
{
|
||||
GameEntry.Event.Subscribe(CombatPauseEventArgs.EventId, OnCombatPauseButtonClicked);
|
||||
GameEntry.Event.Subscribe(CombatEndEventArgs.EventId, OnCombatEndButtonClicked);
|
||||
}
|
||||
|
||||
protected override void UnsubscribeCustomEvents()
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(CombatPauseEventArgs.EventId, OnCombatPauseButtonClicked);
|
||||
GameEntry.Event.Unsubscribe(CombatEndEventArgs.EventId, OnCombatEndButtonClicked);
|
||||
}
|
||||
|
||||
public int? OpenUI(CombatInfoFormRawData rawData)
|
||||
{
|
||||
CombatInfoFormContext context = BuildContext(rawData);
|
||||
return OpenUIInternal(context);
|
||||
}
|
||||
|
||||
public override int? OpenUI(object userData = null)
|
||||
{
|
||||
if (userData is CombatInfoFormContext context)
|
||||
{
|
||||
return OpenUIInternal(context);
|
||||
}
|
||||
|
||||
if (userData is CombatInfoFormRawData rawDataFromUserData)
|
||||
{
|
||||
return OpenUI(rawDataFromUserData);
|
||||
}
|
||||
|
||||
if (userData != null)
|
||||
{
|
||||
Log.Warning("CombatInfoFormController.OpenUI() userData type is invalid.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_useCase == null)
|
||||
{
|
||||
Log.Error("CombatInfoFormController.OpenUI() useCase is null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
CombatInfoFormRawData rawData = _useCase.CreateInitialModel();
|
||||
return OpenUI(rawData);
|
||||
}
|
||||
|
||||
public override void BindUseCase(IUIUseCase useCase)
|
||||
{
|
||||
if (!(useCase is CombatInfoFormUseCase combatInfoFormUseCase))
|
||||
{
|
||||
Log.Error("CombatInfoFormController.BindUseCase() useCase is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
_useCase = combatInfoFormUseCase;
|
||||
}
|
||||
|
||||
private static CombatInfoFormContext BuildContext(CombatInfoFormRawData rawData)
|
||||
{
|
||||
if (rawData == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new CombatInfoFormContext
|
||||
{
|
||||
LevelMetaText = BuildLevelMetaText(rawData.LevelThemeType, rawData.LevelId),
|
||||
LevelPhaseText = BuildPhaseText(rawData.CurrentPhaseIndex, rawData.TotalPhaseCount),
|
||||
CoinText = BuildCoinText(rawData.Coin),
|
||||
CanPause = rawData.CanPause,
|
||||
CanEnd = rawData.CanEnd
|
||||
};
|
||||
}
|
||||
|
||||
private static string BuildLevelMetaText(LevelThemeType themeType, int levelId)
|
||||
{
|
||||
if (levelId <= 0)
|
||||
{
|
||||
return "Map -";
|
||||
}
|
||||
|
||||
return $"{themeType} Map.{levelId}";
|
||||
}
|
||||
|
||||
private static string BuildPhaseText(int currentPhaseIndex, int totalPhaseCount)
|
||||
{
|
||||
int phaseIndex = currentPhaseIndex < 0 ? 0 : currentPhaseIndex;
|
||||
if (totalPhaseCount <= 0)
|
||||
{
|
||||
return $"{phaseIndex}/?";
|
||||
}
|
||||
|
||||
return $"Wave: {phaseIndex}/{totalPhaseCount}";
|
||||
}
|
||||
|
||||
private static string BuildCoinText(int coin)
|
||||
{
|
||||
if (coin < 0)
|
||||
{
|
||||
return "Coin: -";
|
||||
}
|
||||
|
||||
return $"Coin: {coin}";
|
||||
}
|
||||
|
||||
private void OnCombatPauseButtonClicked(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!(sender is CombatInfoForm) || !(e is CombatPauseEventArgs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.DialogForm, new DialogFormRawData
|
||||
{
|
||||
Mode = 1,
|
||||
Title = "Pause",
|
||||
Message = "Game paused.",
|
||||
PauseGame = true,
|
||||
ConfirmText = "Continue"
|
||||
});
|
||||
}
|
||||
|
||||
private void OnCombatEndButtonClicked(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!(sender is CombatInfoForm) || !(e is CombatEndEventArgs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_useCase?.TryEndCombat();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb66e5d005d549938b7b4bb68c6d66e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca167152dba83864bbcd398e6d984d89
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class CombatInfoFormRawData
|
||||
{
|
||||
public LevelThemeType LevelThemeType;
|
||||
public int LevelId;
|
||||
public int CurrentPhaseIndex;
|
||||
public int TotalPhaseCount;
|
||||
public int Coin;
|
||||
public bool CanPause;
|
||||
public bool CanEnd;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf24b0e63c6b4863a90d4a3261378106
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 28613671adff3fc44b3c6ace7957869d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class CombatInfoFormUseCase : IUIUseCase
|
||||
{
|
||||
public CombatInfoFormRawData CreateInitialModel()
|
||||
{
|
||||
return BuildModel();
|
||||
}
|
||||
|
||||
public CombatInfoFormRawData TryRefresh()
|
||||
{
|
||||
return BuildModel();
|
||||
}
|
||||
|
||||
public bool TryEndCombat()
|
||||
{
|
||||
if (GameEntry.CombatNode == null || !GameEntry.CombatNode.CanEndCombat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GameEntry.CombatNode.TryEndCombatByPlayer();
|
||||
}
|
||||
|
||||
private static CombatInfoFormRawData BuildModel()
|
||||
{
|
||||
if (GameEntry.CombatNode == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var level = GameEntry.CombatNode.CurrentLevel;
|
||||
LevelThemeType themeType = level != null ? level.LevelThemeType : GameEntry.CombatNode.CurrentThemeType;
|
||||
int levelId = level != null ? level.Id : 0;
|
||||
|
||||
return new CombatInfoFormRawData
|
||||
{
|
||||
LevelThemeType = themeType,
|
||||
LevelId = levelId,
|
||||
CurrentPhaseIndex = GameEntry.CombatNode.CurrentPhaseIndex,
|
||||
TotalPhaseCount = GameEntry.CombatNode.CurrentLevelPhaseCount,
|
||||
Coin = GameEntry.CombatNode.CurrentCoin,
|
||||
CanPause = true,
|
||||
CanEnd = GameEntry.CombatNode.CanEndCombat
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7bc6a5500e554439bf8c760a779ae87c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1d770766799a63488692f296e0d42f7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,107 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class CombatInfoForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private TMP_Text _levelMetaText;
|
||||
|
||||
[SerializeField] private TMP_Text _levelPhaseText;
|
||||
|
||||
[SerializeField] private TMP_Text _coinText;
|
||||
|
||||
[SerializeField] private CommonButton _pauseButton;
|
||||
|
||||
[SerializeField] private CommonButton _endButton;
|
||||
|
||||
private CombatInfoFormContext _context;
|
||||
|
||||
public void RefreshUI(CombatInfoFormContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
||||
if (_levelMetaText != null)
|
||||
{
|
||||
_levelMetaText.text = context?.LevelMetaText ?? string.Empty;
|
||||
}
|
||||
|
||||
if (_levelPhaseText != null)
|
||||
{
|
||||
_levelPhaseText.text = context?.LevelPhaseText ?? string.Empty;
|
||||
}
|
||||
|
||||
if (_coinText != null)
|
||||
{
|
||||
_coinText.text = context?.CoinText ?? "0";
|
||||
}
|
||||
|
||||
if (_pauseButton != null)
|
||||
{
|
||||
_pauseButton.Interactive = context?.CanPause ?? false;
|
||||
}
|
||||
|
||||
if (_endButton != null)
|
||||
{
|
||||
_endButton.gameObject.SetActive(context?.CanEnd ?? false);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPauseButtonClick()
|
||||
{
|
||||
if (_context != null && !_context.CanPause)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, CombatPauseEventArgs.Create());
|
||||
}
|
||||
|
||||
public void OnEndButtonClick()
|
||||
{
|
||||
if (_context != null && !_context.CanEnd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, CombatEndEventArgs.Create());
|
||||
}
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
|
||||
if (userData is CombatInfoFormContext context)
|
||||
{
|
||||
RefreshUI(context);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Warning("CombatInfoForm requires CombatInfoFormContext as userData.");
|
||||
}
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
_context = null;
|
||||
|
||||
if (_levelMetaText != null)
|
||||
{
|
||||
_levelMetaText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (_levelPhaseText != null)
|
||||
{
|
||||
_levelPhaseText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (_coinText != null)
|
||||
{
|
||||
_coinText.text = string.Empty;
|
||||
}
|
||||
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3971fa7b9e17b04a97d7f10d1472a80
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user