Unity TCG卡牌拖拽后无法返回原父物体问题求助
卡牌拖拽后无法返回原父物体问题排查与修复
问题描述
开发TCG集换式卡牌游戏时,卡牌拖拽功能其他逻辑正常,但释放卡牌后,卡牌未返回player1Hand区域,而是回到主屏幕根节点。C#代码无编译错误,但Unity控制台抛出NullReferenceException,提示在CardController.OnPointerUp方法中尝试访问空引用。
控制台错误信息
NullReferenceException: Object reference not set to an instance of an object
CardController.OnPointerUp(PointerEventData eventData) (at Assets/Scripts/CardController.cs:XX)
优化后的代码
CardController 卡牌交互控制器
using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; using TMPro; // 处理卡牌的拖拽、点击交互逻辑 public class CardController : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler { // 当前卡牌绑定的数据对象 public Card card; // 显示卡牌角色精灵的Image组件 public Image characterSprite; // 卡牌背景Image组件(控制射线检测) private Image _cardBackground; // 卡牌属性文本组件 public TextMeshProUGUI cardNameText, attackText, defenceText, levelText, descriptionText; // 存储卡牌初始父物体,用于拖拽结束后返回原位置 private Transform _originalParent; // 初始化组件引用 private void Awake() { _cardBackground = GetComponent<Image>(); } // 初始化卡牌数据与UI显示 public void Initialize(Card cardData) { card = cardData; // 赋值角色精灵 characterSprite.sprite = cardData.character; // 填充卡牌属性文本 cardNameText.text = cardData.cardName; attackText.text = cardData.attack.ToString(); defenceText.text = cardData.defence.ToString(); levelText.text = cardData.level.ToString(); descriptionText.text = cardData.description; // 记录当前父物体为初始父物体 _originalParent = transform.parent; } // 鼠标释放卡牌时触发的逻辑 public void OnPointerUp(PointerEventData eventData) { // 恢复射线检测,允许卡牌再次被交互 _cardBackground.raycastTarget = true; // 避免空引用错误:先检查初始父物体是否有效 if (_originalParent != null) { // 将卡牌放回初始父物体 transform.SetParent(_originalParent); // 重置卡牌在父物体内的位置为居中 transform.localPosition = Vector3.zero; } } // 鼠标按下卡牌时触发的逻辑 public void OnPointerDown(PointerEventData eventData) { // 将卡牌移至根节点,解决拖拽时的层级遮挡问题 transform.SetParent(transform.root); // 禁用射线检测,防止拖拽过程中重复触发点击事件 _cardBackground.raycastTarget = false; } // 拖拽过程中触发的逻辑 public void OnDrag(PointerEventData eventData) { // 让卡牌跟随鼠标位置移动 transform.position = eventData.position; } }
CardManager 卡牌管理器
using UnityEngine; using System.Collections.Generic; // 全局卡牌管理类,负责卡牌生成与实例管理 public class CardManager : MonoBehaviour { // 单例实例,供其他脚本全局调用 public static CardManager Instance; // 存储所有可生成的卡牌数据列表 public List<Card> cardDataList = new List<Card>(); // 玩家1手牌区的父物体Transform public Transform player1HandArea; // 玩家2手牌区的父物体Transform public Transform player2HandArea; // 卡牌预制体(带CardController组件) public CardController cardPrefab; // 初始化单例 private void Awake() { Instance = this; } // 游戏启动时生成初始手牌 private void Start() { GenerateInitialHandCards(); } // 遍历卡牌数据列表,生成卡牌并添加到玩家1手牌区 private void GenerateInitialHandCards() { foreach (Card cardData in cardDataList) { // 实例化卡牌预制体,设置父物体为玩家1手牌区 CardController newCard = Instantiate(cardPrefab, player1HandArea); // 重置卡牌在父物体内的位置为居中 newCard.transform.localPosition = Vector3.zero; // 初始化卡牌数据与UI显示 newCard.Initialize(cardData); } } }
问题原因与修复说明
- 空引用错误根源:原代码中未对
originalParent做空值检查,若该变量因意外情况(如预制体初始化顺序问题)未被正确赋值,会导致OnPointerUp时触发NullReferenceException,卡牌无法返回原父物体。 - 修复措施:
- 在
OnPointerUp中增加_originalParent != null的判断,确保只有当引用有效时才执行父物体设置。 - 优化变量命名,避免与Unity内置组件名冲突(如将
image改为_cardBackground),提升代码可读性与维护性。 - 规范注释,明确每个组件、方法的作用,降低后续开发的理解成本。
- 在
内容的提问来源于stack exchange,提问作者Ahmed Nasser
相关产品推荐
相关产品推荐

