177 lines
6.2 KiB
C#
177 lines
6.2 KiB
C#
using System;
|
||
using System.Collections;
|
||
using Core;
|
||
using Gameplay.Enemy;
|
||
using Gameplay.Player;
|
||
using Share;
|
||
using UnityEngine;
|
||
|
||
namespace Gameplay
|
||
{
|
||
/// <summary>
|
||
/// 战斗流程管理器(回合制、循环抽牌)
|
||
/// 使用方法:在场景中挂载一个空物体并配置 player 与 enemy 的 Combatant 引用。
|
||
/// 该管理器通过事件回调让 UI 或其它系统接入“双方牌都打空时”的选择(继续/逃跑)。
|
||
/// </summary>
|
||
public class CombatFlowManager : MonoSingleton<CombatFlowManager>
|
||
{
|
||
[Header("Participants")]
|
||
public PlayerController player;
|
||
public EnemyController enemy;
|
||
|
||
[Header("Flow Settings")]
|
||
[Tooltip("玩家是否先手(true=玩家先出一张)")]
|
||
public bool playerStarts = true;
|
||
[Tooltip("每出一张牌后的间隔(秒)")]
|
||
public float turnDelay = 0.8f;
|
||
|
||
// Events
|
||
public event Action OnCombatStarted;
|
||
public event Action<ICharacter, Card> OnCardPlayed;
|
||
public event Action<ICharacter> OnCombatEnded; // 参数为胜利方(null 表示平局或逃跑)
|
||
public event Action OnBothEmpty; // 当双方都没有卡可以出时触发,UI 需要通过 ContinueAfterBothEmpty 或 EscapeFromCombat 响应
|
||
|
||
// internal state
|
||
private Coroutine runningRoutine;
|
||
private bool waitingForDecision = false;
|
||
private bool decisionContinue = false;
|
||
private bool decisionEscape = false;
|
||
|
||
/// <summary>
|
||
/// 启动战斗流程(也可以在 Inspector 中提前绑定 player/enemy,然后只调用 StartCombat())
|
||
/// </summary>
|
||
public void StartCombat(PlayerController playerController = null, EnemyController enemyController = null)
|
||
{
|
||
if (playerController != null) player = playerController;
|
||
if (enemyController != null) enemy = enemyController;
|
||
|
||
if (player == null || enemy == null)
|
||
{
|
||
Debug.LogError("CombatFlowManager: player 或 enemy 未设置。");
|
||
return;
|
||
}
|
||
|
||
// 初始化双方状态
|
||
player.StartCombat();
|
||
enemy.StartCombat();
|
||
player.InitializeDeckCycle();
|
||
enemy.InitializeDeckCycle();
|
||
|
||
|
||
runningRoutine = StartCoroutine(CombatRoutine());
|
||
OnCombatStarted?.Invoke();
|
||
}
|
||
|
||
public void StopCombat()
|
||
{
|
||
if (runningRoutine != null) StopCoroutine(runningRoutine);
|
||
runningRoutine = null;
|
||
}
|
||
|
||
private IEnumerator CombatRoutine()
|
||
{
|
||
ICharacter current = playerStarts ? player : enemy;
|
||
|
||
while (true)
|
||
{
|
||
// 结束检查
|
||
if (player.IsDead || enemy.IsDead)
|
||
{
|
||
ICharacter winner = player.IsDead ? enemy : player;
|
||
OnCombatEnded?.Invoke(winner);
|
||
runningRoutine = null;
|
||
yield break;
|
||
}
|
||
|
||
bool playerHas = player.HasCardsLeft();
|
||
bool enemyHas = enemy.HasCardsLeft();
|
||
|
||
if (!playerHas && !enemyHas)
|
||
{
|
||
// 双方都打空,等待玩家选择(由 UI 调用 ContinueAfterBothEmpty 或 EscapeFromCombat)
|
||
waitingForDecision = true;
|
||
decisionContinue = false;
|
||
decisionEscape = false;
|
||
OnBothEmpty?.Invoke();
|
||
|
||
// 等待选择
|
||
while (waitingForDecision)
|
||
yield return null;
|
||
|
||
if (decisionEscape)
|
||
{
|
||
// 玩家选择逃跑 -> 结束战斗,胜者设为 null(或按需要设成敌人/玩家)
|
||
OnCombatEnded?.Invoke(null);
|
||
runningRoutine = null;
|
||
yield break;
|
||
}
|
||
|
||
if (decisionContinue)
|
||
{
|
||
// 重新从卡册读取(重置抽牌队列),保持生命与其它状态不变
|
||
player.InitializeDeckCycle();
|
||
enemy.InitializeDeckCycle();
|
||
// 继续循环(当前先手不变)
|
||
yield return null;
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// 当前回合:如果当前方没有牌则跳过(空过)
|
||
if (current.HasCardsLeft())
|
||
{
|
||
var card = current.GetNextCard();
|
||
ICharacter target;
|
||
if (current is PlayerController)
|
||
{
|
||
target = enemy;
|
||
}
|
||
else
|
||
{
|
||
target = player;
|
||
}
|
||
|
||
|
||
// 触发卡牌效果(当前仅支持直接伤害)
|
||
if (card != null)
|
||
{
|
||
card.PlayCard(new CardContext(current, target));
|
||
OnCardPlayed?.Invoke(current, card);
|
||
}
|
||
|
||
// 检查死亡(将在下一循环顶部处理)
|
||
yield return new WaitForSeconds(turnDelay);
|
||
}
|
||
else
|
||
{
|
||
// 跳过一轮,不延迟太久
|
||
yield return new WaitForSeconds(0.1f);
|
||
}
|
||
|
||
// 切换行动方
|
||
current = (current == player) ? enemy : player;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当双方都打空时,UI 调用此方法选择继续下一轮(重新从卡册读取卡牌)
|
||
/// </summary>
|
||
public void ContinueAfterBothEmpty()
|
||
{
|
||
if (!waitingForDecision) return;
|
||
decisionContinue = true;
|
||
waitingForDecision = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当双方都打空时,UI 调用此方法选择逃跑
|
||
/// </summary>
|
||
public void EscapeFromCombat()
|
||
{
|
||
if (!waitingForDecision) return;
|
||
decisionEscape = true;
|
||
waitingForDecision = false;
|
||
}
|
||
}
|
||
}
|