Files
Continentis/Assets/Scripts/MainGame/Card/CardView/HandCardView/HandCardView_Operations.cs
SoulliesOfficial c3b1561375 更新
2026-04-01 12:23:27 -04:00

541 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using System.Linq;
using Continentis.MainGame.Character;
using Continentis.MainGame.Combat;
using Continentis.MainGame.UI;
using SLSFramework.General;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
namespace Continentis.MainGame.Card
{
public partial class HandCardView : IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerClickHandler
{
public CombatCharacterViewBase currentTargetingCharacterView;
public List<CharacterBase> validTargets = new List<CharacterBase>();
public List<CharacterBase> conditionNotMetTargets = new List<CharacterBase>();
public List<CharacterBase> invalidTargets = new List<CharacterBase>();
#region Multi-Target Selection State
/// <summary>是否正处于多目标逐次点击选择模式。</summary>
private bool isMultiTargetSelecting;
/// <summary>多目标模式下已选中的目标列表(可含重复)。</summary>
private readonly List<CharacterBase> multiTargetSelectedList = new List<CharacterBase>();
/// <summary>多目标模式需要的总选择次数。</summary>
private int multiTargetRequired;
/// <summary>多目标模式下卡牌固定显示的位置(箭头起点)。</summary>
private Vector3 multiTargetCardAnchor;
#endregion
protected override void Update()
{
base.Update();
if (isMultiTargetSelecting)
{
HandleMultiTargetInput();
}
}
public override void OnPointerEnter(PointerEventData eventData)
{
base.OnPointerEnter(eventData);
card.contentSubmodule.dirtyMark = true;
if (CombatUIManager.Instance.selectingCardView == null)
{
canvas.overrideSorting = true;
canvas.sortingLayerName = "UI";
canvas.sortingOrder = 10;
}
}
public override void OnPointerExit(PointerEventData eventData)
{
base.OnPointerExit(eventData);
if (!isSelecting)
{
canvas.overrideSorting = false;
canvas.sortingOrder = 0;
}
}
public void OnPointerClick(PointerEventData eventData)
{
if (CombatUIManager.Instance.combatMainPage.handCardSelector.gameObject.activeInHierarchy)
{
if(isOccupied) return;
if (CombatUIManager.Instance.combatMainPage.handCardSelector.selectedCards.Contains(card))
{
CombatUIManager.Instance.combatMainPage.handCardSelector.Deselect(this);
}
else
{
CombatUIManager.Instance.combatMainPage.handCardSelector.Select(this);
}
}
else if (CombatUIManager.Instance.combatMainPage.customCardSelector.gameObject.activeInHierarchy)
{
if(isOccupied) return;
if (CombatUIManager.Instance.combatMainPage.customCardSelector.selectedCards.Contains(card))
{
CombatUIManager.Instance.combatMainPage.customCardSelector.Deselect(this);
}
else
{
CombatUIManager.Instance.combatMainPage.customCardSelector.Select(this);
}
}
}
public void OnBeginDrag(PointerEventData eventData)
{
isSelecting = true;
CombatUIManager.Instance.selectingCardView = this;
card.user = CombatMainManager.Instance.currentCharacter;
card.DetectTargetsValidity(out validTargets, out conditionNotMetTargets, out invalidTargets);
int targetCount = card.attributeSubmodule.targetCount;
if (targetCount > 1)
{
// 多目标模式:先执行通用的可打出校验
if (!CheckCanStartPlay())
{
ResetSelectionState();
return;
}
EnterMultiTargetMode(targetCount);
}
else if (targetCount == 1)
{
CombatUIManager.Instance.arrowsPage.GeneratePointerArrow(cardTransform.position, cardTransform.position, true);
}
else if (targetCount == -1)
{
CombatUIManager.Instance.arrowsPage.GeneratePointerArrow(cardTransform.position, cardTransform.position, true);
for (int i = 0; i < validTargets.Count + conditionNotMetTargets.Count - 1; i++)
{
CombatUIManager.Instance.arrowsPage.GeneratePointerArrow(cardTransform.position, cardTransform.position, false);
}
}
}
public void OnDrag(PointerEventData eventData)
{
// 多目标模式下拖拽无效,交互由 Update 中的点击处理
if (isMultiTargetSelecting) return;
RectTransform arrowCanvasRect = CombatUIManager.Instance.arrowsPage.rectTransform;
Camera uiCamera = CombatUIManager.Instance.uiCamera;
Camera worldCamera = CombatUIManager.Instance.combatCamera;
// 先检查悬停的视图是否和当前记录的目标视图发生了变化
if (CombatUIManager.Instance.hoveringCharacterView != currentTargetingCharacterView)
{
// 如果悬停视图不是空的,说明鼠标移动到了一个新的目标上
if (CombatUIManager.Instance.hoveringCharacterView != null)
{
card.Targeting(CombatUIManager.Instance.hoveringCharacterView.character);
currentTargetingCharacterView = CombatUIManager.Instance.hoveringCharacterView;
}
else // 悬停视图是空的,说明鼠标离开了之前的目标
{
card.Untargeting();
currentTargetingCharacterView = null;
}
card.contentSubmodule.dirtyMark = true;
}
Vector3 startPosition = cardTransform.position;
Vector3 endPosition = SpaceConverter.ScreenPointToUIPoint(arrowCanvasRect, eventData.position, uiCamera);
PointerArrow mainPointerArrow = CombatUIManager.Instance.arrowsPage.mainPointerArrow;
CombatCharacterViewBase hoveringCharacterView = CombatUIManager.Instance.hoveringCharacterView;
CharacterBase hoveringCharacter = hoveringCharacterView != null ? hoveringCharacterView.character : null;
if (card.attributeSubmodule.targetCount == 1)
{
mainPointerArrow.SetArrow(startPosition, endPosition);
if (hoveringCharacter != null)
{
if (validTargets.Contains(hoveringCharacter))
{
mainPointerArrow.SetColor(Color.white);
}
else if (conditionNotMetTargets.Contains(hoveringCharacter))
{
mainPointerArrow.SetColor(Color.yellow);
}
else if (invalidTargets.Contains(hoveringCharacter))
{
mainPointerArrow.SetColor(Color.red);
}
}
else
{
mainPointerArrow.SetColor(Color.clear);
}
}
else if (card.attributeSubmodule.targetCount == -1)
{
mainPointerArrow.SetArrow(startPosition, endPosition);
if (validTargets.Count > 0)
{
if (hoveringCharacter != null)
{
mainPointerArrow.SetColor(Color.clear);
}
if (validTargets.Contains(hoveringCharacter))
{
mainPointerArrow.SetColor(Color.white);
}
else if (conditionNotMetTargets.Contains(hoveringCharacter))
{
mainPointerArrow.SetColor(Color.yellow);
}
else if (invalidTargets.Contains(hoveringCharacter))
{
mainPointerArrow.SetColor(Color.red);
}
}
else
{
mainPointerArrow.SetColor(Color.red);
return;
}
if (hoveringCharacter != null && (validTargets.Contains(hoveringCharacter) || conditionNotMetTargets.Contains(hoveringCharacter)))
{
List<CharacterBase> validTargetsExceptHovering =
validTargets.FindAll(target => target != hoveringCharacter);
List<CharacterBase> notMetTargetsExceptHovering =
conditionNotMetTargets.FindAll(target => target != hoveringCharacter);
for (int i = 0; i < validTargetsExceptHovering.Count; i++)
{
PointerArrow arrow = CombatUIManager.Instance.arrowsPage.otherPointerArrows[i];
CharacterBase target = validTargetsExceptHovering[i];
Vector3 targetViewPosition = target.characterView.transform.position;
arrow.gameObject.SetActive(true);
Vector3 otherEndPosition = SpaceConverter.WorldPointToUIPoint(arrowCanvasRect, targetViewPosition, worldCamera, uiCamera);
arrow.SetArrow(startPosition, otherEndPosition);
arrow.SetColor(Color.white);
}
for (int i = validTargetsExceptHovering.Count; i < validTargetsExceptHovering.Count + notMetTargetsExceptHovering.Count; i++)
{
PointerArrow arrow = CombatUIManager.Instance.arrowsPage.otherPointerArrows[i];
CharacterBase target = notMetTargetsExceptHovering[i];
Vector3 targetViewPosition = target.characterView.transform.position;
arrow.gameObject.SetActive(true);
Vector3 otherEndPosition = SpaceConverter.WorldPointToUIPoint(arrowCanvasRect, targetViewPosition, worldCamera, uiCamera);
arrow.SetArrow(startPosition, otherEndPosition);
arrow.SetColor(Color.yellow);
}
}
else
{
CombatUIManager.Instance.arrowsPage.otherPointerArrows.ForEach(arrow => { arrow.gameObject.SetActive(false); });
}
}
else if (card.attributeSubmodule.targetCount == 0)
{
Vector3 cardPosition = SpaceConverter.ScreenPointToUIPoint(arrowCanvasRect, eventData.position, uiCamera);
cardTransform.position = cardPosition;
}
}
public void OnEndDrag(PointerEventData eventData)
{
// 多目标模式下,拖拽结束只是从拖拽过渡到点击模式,不做打出判定
if (isMultiTargetSelecting) return;
CombatCharacterViewBase hoveringCharacterView = CombatUIManager.Instance.hoveringCharacterView;
CharacterBase hoveringCharacter = hoveringCharacterView != null ? hoveringCharacterView.character : null;
Camera uiCamera = CombatUIManager.Instance.uiCamera;
CombatUIManager.Instance.arrowsPage.ClearPointerArrows();
if (isSelecting)
{
isSelecting = false;
isHovering = false;
CombatUIManager.Instance.selectingCardView = null;
canvas.overrideSorting = false;
canvas.sortingOrder = 0;
card.eventSubmodule.onUntargeting();
card.contentSubmodule.dirtyMark = true;
}
else
{
return;
}
if (!CheckCanStartPlay()) return;
if (!card.HasKeyword("TargetSelf"))
{
if (!validTargets.Contains(hoveringCharacter))
{
// 当前鼠标悬停的目标不在有效目标列表中
return;
}
}
// 根据目标类型,打出卡牌
if (card.attributeSubmodule.targetCount == 1)
{
if (hoveringCharacter != null && validTargets.Contains(hoveringCharacter))
{
if (!card.Play(new List<CharacterBase>() { hoveringCharacter }))
{
card.eventSubmodule.onUntargeting();
card.contentSubmodule.dirtyMark = true;
}
}
}
else
{
RectTransform dropZone = CombatUIManager.Instance.combatMainPage.dropZone;
bool isInDropZone = RectTransformUtility.RectangleContainsScreenPoint(dropZone, eventData.position, uiCamera);
List<CharacterBase> targetList = new List<CharacterBase>();
if (card.attributeSubmodule.targetCount == -1)
{
targetList.AddRange(validTargets);
}
else if (card.HasKeyword("TargetSelf") && card.attributeSubmodule.targetCount == 0)
{
targetList.Add(card.user);
}
if (!isInDropZone)
{
card.Play(targetList);
}
}
}
#region Play Validation
/// <summary>
/// 检查卡牌是否可以被打出Unplayable / Prerequisite 校验)。
/// 校验失败时会生成提示文本。
/// </summary>
private bool CheckCanStartPlay()
{
if (card.HasKeyword("Unplayable"))
{
return false;
}
if (!card.HasKeyword("Prerequisite"))
{
CharacterBase currentCharacter = CombatMainManager.Instance.currentCharacter;
List<CardInstance> handPile = currentCharacter.deckSubmodule.HandPile;
for (int i = 0; i < handPile.Count; i++)
{
if (handPile[i].HasKeyword("Prerequisite"))
{
MainGameManager.Instance.basePrefabs.GenerateInfoText(
"Keyword_Prerequisite_Warning".Localize(), currentCharacter.characterView);
return false;
}
}
}
return true;
}
/// <summary>重置选择状态(不触发 Untargeting 事件)。</summary>
private void ResetSelectionState()
{
isSelecting = false;
isHovering = false;
CombatUIManager.Instance.selectingCardView = null;
canvas.overrideSorting = false;
canvas.sortingOrder = 0;
}
#endregion
#region Multi-Target Selection
/// <summary>进入多目标逐次选择模式。</summary>
private void EnterMultiTargetMode(int required)
{
isMultiTargetSelecting = true;
multiTargetRequired = required;
multiTargetSelectedList.Clear();
// 记录卡牌当前位置作为箭头起点锚点
multiTargetCardAnchor = cardTransform.position;
UpdateMultiTargetHint();
}
/// <summary>多目标模式下的输入处理,在 Update 中调用。</summary>
private void HandleMultiTargetInput()
{
// Escape 取消全部
if (Keyboard.current.escapeKey.wasPressedThisFrame)
{
ExitMultiTargetMode();
return;
}
// 右键撤销上一步
if (Mouse.current.rightButton.wasPressedThisFrame)
{
UndoLastMultiTarget();
return;
}
// 左键选择目标
if (Mouse.current.leftButton.wasPressedThisFrame)
{
CombatCharacterViewBase hoveringView = CombatUIManager.Instance.hoveringCharacterView;
if (hoveringView == null) return;
CharacterBase hoveringCharacter = hoveringView.character;
// 判断是否为有效目标
if (!validTargets.Contains(hoveringCharacter)) return;
// 判断是否允许重复选择
if (!card.HasKeyword(CardKeywords.AllowDuplicateTargets)
&& multiTargetSelectedList.Contains(hoveringCharacter))
{
return;
}
// 选中目标
multiTargetSelectedList.Add(hoveringCharacter);
// 生成固定箭头指向该目标
RectTransform arrowCanvasRect = CombatUIManager.Instance.arrowsPage.rectTransform;
Camera worldCamera = CombatUIManager.Instance.combatCamera;
Camera uiCamera = CombatUIManager.Instance.uiCamera;
Vector3 targetWorldPos = hoveringView.transform.position;
Vector3 targetUIPos = SpaceConverter.WorldPointToUIPoint(
arrowCanvasRect, targetWorldPos, worldCamera, uiCamera);
// 第一支箭头为 main后续为 other
bool isMain = multiTargetSelectedList.Count == 1;
CombatUIManager.Instance.arrowsPage.GeneratePointerArrow(
multiTargetCardAnchor, targetUIPos, isMain);
// 触发 TargetingEffect 更新伤害预览
card.Targeting(hoveringCharacter);
card.contentSubmodule.dirtyMark = true;
UpdateMultiTargetHint();
// 检查是否选满
if (multiTargetSelectedList.Count >= multiTargetRequired)
{
ConfirmMultiTargetPlay();
}
}
}
/// <summary>撤销多目标模式下的上一步选择。</summary>
private void UndoLastMultiTarget()
{
if (multiTargetSelectedList.Count > 0)
{
multiTargetSelectedList.RemoveAt(multiTargetSelectedList.Count - 1);
CombatUIManager.Instance.arrowsPage.RemoveLastPointerArrow();
// 如果还有已选目标,触发最后一个目标的 TargetingEffect
if (multiTargetSelectedList.Count > 0)
{
card.Targeting(multiTargetSelectedList[^1]);
}
else
{
card.Untargeting();
}
card.contentSubmodule.dirtyMark = true;
UpdateMultiTargetHint();
}
// 已选归零 → 取消选择,卡牌归位
if (multiTargetSelectedList.Count == 0)
{
ExitMultiTargetMode();
}
}
/// <summary>选满后自动打出。</summary>
private void ConfirmMultiTargetPlay()
{
List<CharacterBase> targets = new List<CharacterBase>(multiTargetSelectedList);
// 清理多目标状态
isMultiTargetSelecting = false;
multiTargetSelectedList.Clear();
multiTargetRequired = 0;
CombatUIManager.Instance.arrowsPage.ClearPointerArrows();
isSelecting = false;
isHovering = false;
CombatUIManager.Instance.selectingCardView = null;
canvas.overrideSorting = false;
canvas.sortingOrder = 0;
// 打出卡牌
if (!card.Play(targets))
{
card.eventSubmodule.onUntargeting();
card.contentSubmodule.dirtyMark = true;
}
}
/// <summary>退出多目标选择模式(取消操作),清理所有状态,卡牌归位。</summary>
private void ExitMultiTargetMode()
{
isMultiTargetSelecting = false;
multiTargetSelectedList.Clear();
multiTargetRequired = 0;
CombatUIManager.Instance.arrowsPage.ClearPointerArrows();
isSelecting = false;
isHovering = false;
CombatUIManager.Instance.selectingCardView = null;
canvas.overrideSorting = false;
canvas.sortingOrder = 0;
card.eventSubmodule.onUntargeting();
card.contentSubmodule.dirtyMark = true;
}
/// <summary>更新多目标选择的计数提示。</summary>
private void UpdateMultiTargetHint()
{
string hint = $"{multiTargetSelectedList.Count} / {multiTargetRequired}";
MainGameManager.Instance.basePrefabs.GenerateInfoText(
hint, card.user.characterView, Color.cyan);
}
#endregion
}
}