到IronWall

This commit is contained in:
SoulliesOfficial
2025-10-30 23:31:29 -04:00
parent 8b72c75128
commit 5d09ef7b53
39 changed files with 688 additions and 41 deletions

View File

@@ -232,15 +232,21 @@ namespace Continentis.MainGame.Card
protected virtual void AfterPlayEffect(List<CharacterBase> targetList)
{
if (contentSubmodule.cardType == CardType.Power)
{
CommandQueueManager.Instance.AddCommand(user.deckSubmodule.UsePowerCard(cardInstance));
return;
}
if (user is PlayerHero playerHero)
{
if (HasKeyword("Exhaust"))
{
playerHero.deckSubmodule.ExhaustCard(cardInstance);
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.ExhaustCard(cardInstance));
}
else if(!HasKeyword("Reuse"))
{
playerHero.deckSubmodule.DiscardCard(cardInstance);
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.DiscardCard(cardInstance));
CommandQueueManager.Instance.AddCommand(new Cmd_Function(() =>
{
if (handCardView != null)
@@ -254,7 +260,7 @@ namespace Continentis.MainGame.Card
{
if (HasKeyword("Exhaust"))
{
npc.deckSubmodule.ExhaustCard(cardInstance);
CommandQueueManager.Instance.AddCommand(npc.deckSubmodule.ExhaustCard(cardInstance));
}
}
}

View File

@@ -22,6 +22,7 @@ namespace Continentis.MainGame.Character
piles.Add("Draw", new List<CardInstance>());
piles.Add("Discard", new List<CardInstance>());
piles.Add("Exhaust", new List<CardInstance>());
piles.Add("Grave", new List<CardInstance>());
piles.Add("Pool", new List<CardInstance>());
piles.Add("Intention", new List<CardInstance>());
}
@@ -84,35 +85,98 @@ namespace Continentis.MainGame.Character
{
card.cardLogic.Play(targetList, owner);
}
public void DiscardCard(CardInstance card, float interval = 0.1f)
{
CommandQueueManager.Instance.AddCommand(new Cmd_DiscardCards(card.deck, new List<CardInstance> { card }, interval));
}
public void DiscardCards(List<CardInstance> cards, float interval = 0.1f)
public CommandGroup DiscardCard(CardInstance card, float interval = 0.1f)
{
CommandContext context = new CommandContext();
CommandGroup discardCardGroup = new CommandGroup(ExecutionMode.Sequential, context,
new Cmd_DiscardCards(card.deck, new List<CardInstance>() { card }, interval),
new Cmd_Function(0, () =>
{
//Debug.Log((context.sharedInfo["DrawnCards"] as List<CardInstance>).Count); //TODO: 弃牌后的处理
}));
return discardCardGroup;
}
public CommandGroup DiscardCards(List<CardInstance> cards, float interval = 0.1f)
{
Dictionary<DeckSubmodule, List<CardInstance>> groupedCards = cards.GroupBy(card => card.deck)
.ToDictionary(group => group.Key, group => group.ToList());
CommandContext context = new CommandContext();
CommandGroup discardCardGroup = new CommandGroup(ExecutionMode.Sequential, context);
foreach (var kvp in groupedCards)
{
CommandQueueManager.Instance.AddCommand(new Cmd_DiscardCards(kvp.Key, kvp.Value, interval));
discardCardGroup.AddCommand(new Cmd_DiscardCards(kvp.Key, kvp.Value, interval));
}
discardCardGroup.AddCommand(new Cmd_Function(0, () =>
{
//Debug.Log((context.sharedInfo["DrawnCards"] as List<CardInstance>).Count); //TODO: 弃牌后的处理
}));
return discardCardGroup;
}
public void ExhaustCard(CardInstance card, float interval = 0.1f)
public CommandGroup ExhaustCard(CardInstance card, float interval = 0.1f)
{
CommandQueueManager.Instance.AddCommand(new Cmd_ExhaustCards(owner is PlayerHero, card.deck, new List<CardInstance> { card }, interval));
CommandContext context = new CommandContext();
CommandGroup discardCardGroup = new CommandGroup(ExecutionMode.Sequential, context,
new Cmd_ExhaustCards(owner is PlayerHero, card.deck, new List<CardInstance>() { card }, interval),
new Cmd_Function(0, () =>
{
//Debug.Log((context.sharedInfo["DrawnCards"] as List<CardInstance>).Count); //TODO: 消耗牌后的处理
}));
return discardCardGroup;
}
public void ExhaustCards(List<CardInstance> cards, float interval = 0.1f)
public CommandGroup ExhaustCards(List<CardInstance> cards, float interval = 0.1f)
{
Dictionary<DeckSubmodule, List<CardInstance>> groupedCards = cards.GroupBy(card => card.deck)
.ToDictionary(group => group.Key, group => group.ToList());
CommandContext context = new CommandContext();
CommandGroup discardCardGroup = new CommandGroup(ExecutionMode.Sequential, context);
foreach (var kvp in groupedCards)
{
CommandQueueManager.Instance.AddCommand(new Cmd_ExhaustCards(owner is PlayerHero, kvp.Key, kvp.Value, interval));
discardCardGroup.AddCommand(new Cmd_ExhaustCards(owner is PlayerHero, kvp.Key, kvp.Value, interval));
}
discardCardGroup.AddCommand(new Cmd_Function(0, () =>
{
//Debug.Log((context.sharedInfo["DrawnCards"] as List<CardInstance>).Count); //TODO: 弃牌后的处理
}));
return discardCardGroup;
}
public CommandGroup UsePowerCard(CardInstance card, float interval = 0.1f)
{
CommandContext context = new CommandContext();
CommandGroup discardCardGroup = new CommandGroup(ExecutionMode.Sequential, context,
new Cmd_UsePowerCards(owner is PlayerHero, card.deck, new List<CardInstance>() { card }, interval),
new Cmd_Function(0, () =>
{
//Debug.Log((context.sharedInfo["DrawnCards"] as List<CardInstance>).Count); //TODO: 消耗牌后的处理
}));
return discardCardGroup;
}
public CommandGroup UsePowerCards(List<CardInstance> cards, float interval = 0.1f)
{
Dictionary<DeckSubmodule, List<CardInstance>> groupedCards = cards.GroupBy(card => card.deck)
.ToDictionary(group => group.Key, group => group.ToList());
CommandContext context = new CommandContext();
CommandGroup discardCardGroup = new CommandGroup(ExecutionMode.Sequential, context);
foreach (var kvp in groupedCards)
{
discardCardGroup.AddCommand(new Cmd_UsePowerCards(owner is PlayerHero, kvp.Key, kvp.Value, interval));
}
discardCardGroup.AddCommand(new Cmd_Function(0, () =>
{
//Debug.Log((context.sharedInfo["DrawnCards"] as List<CardInstance>).Count); //TODO: 弃牌后的处理
}));
return discardCardGroup;
}
public void ReshuffleDeck(float interval = 0.1f)
@@ -189,6 +253,7 @@ namespace Continentis.MainGame.Character
public List<CardInstance> DrawPile => Pile("Draw");
public List<CardInstance> DiscardPile => Pile("Discard");
public List<CardInstance> ExhaustPile => Pile("Exhaust");
public List<CardInstance> GravePile => Pile("Grave");
public List<CardInstance> PoolPile => Pile("Pool");
public List<CardInstance> IntentionPile => Pile("Intention");
}

View File

@@ -219,8 +219,8 @@ namespace Continentis.MainGame.Combat
List<CardInstance> cardToRetain = handPile.Where(card => card.cardLogic.HasKeyword("Retain")).ToList(); //含有“保留”关键词的卡牌
List<CardInstance> cardToExhaust = handPile.Where(card => card.cardLogic.HasKeyword("Ethereal")).ToList(); //含有“虚无”关键词的卡牌
List<CardInstance> cardsToDiscard = handPile.Except(cardToRetain).Except(cardToExhaust).ToList(); //其他卡牌,默认丢弃
playerHero.deckSubmodule.ExhaustCards(cardToExhaust);
playerHero.deckSubmodule.DiscardCards(cardsToDiscard);
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.ExhaustCards(cardToExhaust));
CommandQueueManager.Instance.AddCommand(playerHero.deckSubmodule.DiscardCards(cardsToDiscard));
}
characterController.actionOrderList.Remove(currentCharacter);

View File

@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Continentis.MainGame.Card;
using Continentis.MainGame.Character;
using DG.Tweening;
using SLSFramework.General;
using UniRx;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Continentis.MainGame.Commands
{
public class Cmd_UsePowerCards : CommandBase
{
private bool isPlayer;
private readonly DeckSubmodule deck;
private readonly List<CardInstance> cardsToUse;
private readonly float interval;
private readonly float singleCardAnimationDuration = 0.5f; // 单张卡牌的动画时长
public Cmd_UsePowerCards(bool isPlayer, DeckSubmodule deck, List<CardInstance> cards, float interval)
{
this.isPlayer = isPlayer;
this.deck = deck;
this.cardsToUse = cards;
this.interval = interval;
}
protected override IObservable<Unit> OnExecute(CommandContext outerContext)
{
if (cardsToUse == null || cardsToUse.Count == 0)
{
return Observable.Return(Unit.Default);
}
Func<CardInstance, IObservable<Unit>> exhaustAction = isPlayer ? PlayerUsePowers : NpcUsePowers;
// --- 情况1并行丢弃 (所有卡牌动画同时开始) ---
if (interval <= 0f)
{
// 为每张卡牌创建一个“懒加载”的丢弃动画流。
var allDiscardAnimations = cardsToUse.Select(card =>
Observable.Defer(() => exhaustAction(card))
);
// 使用 WhenAll 等待所有的并行任务都完成。
// 只有当最后一个动画结束时WhenAll 才会发出完成信号。
return Observable.WhenAll(allDiscardAnimations).AsUnitObservable();
}
// --- 情况2交错丢弃 (按固定间隔开始动画) ---
else
{
var cardStream = cardsToUse.ToObservable();
var timerStream = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(interval));
return timerStream
.Zip(cardStream, (_, card) => card)
// 核心:不再使用 .Do(..).Subscribe(),而是使用 Select 将每个 card 转换为
// 其对应的动画流。这样主流程就“知道”了每个动画的存在。
.Select(card => exhaustAction(card))
// 使用 Merge 将所有交错开始的动画流合并为一个流。
// Merge 会同时运行所有这些动画,并在最后一个动画也完成时,它才会完成。
.Merge()
// 使用 Last 来确保我们只在整个 Merge 流全部结束后,才发出最终的完成信号。
.Last()
.AsUnitObservable();
}
}
private IObservable<Unit> PlayerUsePowers(CardInstance card)
{
deck.TransferCard(deck.Pile(card.cardLocation.pileName), deck.GravePile, card);
card.handCardView.TransferCardView(CombatUIManager.Instance.combatMainPage.gravePile);
RectTransform cardTransform = card.handCardView.cardTransform;
Vector2 userViewPosition = card.cardLogic.user.characterView.hudContainer.GetComponent<RectTransform>().position;
cardTransform.DOMove(userViewPosition, singleCardAnimationDuration).SetEase(Ease.Linear).Play();
cardTransform.DOScale(Vector3.zero, singleCardAnimationDuration).SetEase(Ease.Linear).OnComplete(() =>
{
cardTransform.anchoredPosition = Vector2.zero;
}).Play();
return Observable.Timer(TimeSpan.FromSeconds(singleCardAnimationDuration)).AsUnitObservable();
}
private IObservable<Unit> NpcUsePowers(CardInstance card)
{
deck.TransferCard(deck.Pile(card.cardLocation.pileName), deck.GravePile, card);
return Observable.Timer(TimeSpan.FromSeconds(singleCardAnimationDuration)).AsUnitObservable();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 11580fee6c93e4445b768eb40c5780bb

View File

@@ -13,6 +13,7 @@ namespace Continentis.MainGame.UI
public HandPile handPile;
public DiscardPile discardPile;
public ExhaustPile exhaustPile;
public GravePile gravePile;
public TeamSwitchButton teamSwitchButton;
public HandCardSelectionInterface handCardSelector;
public CustomCardSelectionInterface customCardSelector;
@@ -32,11 +33,13 @@ namespace Continentis.MainGame.UI
handPile.cardViews.ForEach(c => LeanPool.Despawn(c.gameObject));
discardPile.cardViews.ForEach(c => LeanPool.Despawn(c.gameObject));
exhaustPile.cardViews.ForEach(c => LeanPool.Despawn(c.gameObject));
gravePile.cardViews.ForEach(c => LeanPool.Despawn(c.gameObject));
drawPile.cardViews.Clear();
handPile.cardViews.Clear();
discardPile.cardViews.Clear();
exhaustPile.cardViews.Clear();
gravePile.cardViews.Clear();
}
public PileBase Pile(string pileName)
@@ -51,6 +54,8 @@ namespace Continentis.MainGame.UI
return discardPile;
case "Exhaust":
return exhaustPile;
case "Grave":
return gravePile;
case "Intention":
throw new NotImplementedException("Intention pile UI is in HUD, not in DeckPage.");
default:

View File

@@ -4,16 +4,6 @@ namespace Continentis.MainGame.UI
{
public class ExhaustPile : PileBase
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
}

View File

@@ -0,0 +1,9 @@
using UnityEngine;
namespace Continentis.MainGame.UI
{
public class GravePile : PileBase
{
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f997d4e8f500b944eb3cbb0f5c4ac7c5