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 validTargets = new List(); public List conditionNotMetTargets = new List(); public List invalidTargets = new List(); #region Multi-Target Selection State /// 是否正处于多目标逐次点击选择模式。 private bool isMultiTargetSelecting; /// 多目标模式下已选中的目标列表(可含重复)。 private readonly List multiTargetSelectedList = new List(); /// 多目标模式需要的总选择次数。 private int multiTargetRequired; /// 多目标模式下卡牌固定显示的位置(箭头起点)。 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 validTargetsExceptHovering = validTargets.FindAll(target => target != hoveringCharacter); List 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() { hoveringCharacter })) { card.eventSubmodule.onUntargeting(); card.contentSubmodule.dirtyMark = true; } } } else { RectTransform dropZone = CombatUIManager.Instance.combatMainPage.dropZone; bool isInDropZone = RectTransformUtility.RectangleContainsScreenPoint(dropZone, eventData.position, uiCamera); List targetList = new List(); 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 /// /// 检查卡牌是否可以被打出(Unplayable / Prerequisite 校验)。 /// 校验失败时会生成提示文本。 /// private bool CheckCanStartPlay() { if (card.HasKeyword("Unplayable")) { return false; } if (!card.HasKeyword("Prerequisite")) { CharacterBase currentCharacter = CombatMainManager.Instance.currentCharacter; List 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; } /// 重置选择状态(不触发 Untargeting 事件)。 private void ResetSelectionState() { isSelecting = false; isHovering = false; CombatUIManager.Instance.selectingCardView = null; canvas.overrideSorting = false; canvas.sortingOrder = 0; } #endregion #region Multi-Target Selection /// 进入多目标逐次选择模式。 private void EnterMultiTargetMode(int required) { isMultiTargetSelecting = true; multiTargetRequired = required; multiTargetSelectedList.Clear(); // 记录卡牌当前位置作为箭头起点锚点 multiTargetCardAnchor = cardTransform.position; UpdateMultiTargetHint(); } /// 多目标模式下的输入处理,在 Update 中调用。 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(); } } } /// 撤销多目标模式下的上一步选择。 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(); } } /// 选满后自动打出。 private void ConfirmMultiTargetPlay() { List targets = new List(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; } } /// 退出多目标选择模式(取消操作),清理所有状态,卡牌归位。 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; } /// 更新多目标选择的计数提示。 private void UpdateMultiTargetHint() { string hint = $"{multiTargetSelectedList.Count} / {multiTargetRequired}"; MainGameManager.Instance.basePrefabs.GenerateInfoText( hint, card.user.characterView, Color.cyan); } #endregion } }