Unity3D RPG 入门项目(四)背包拖拽、物品悬浮提示、项目开发思维

核心知识点:背包拖拽三大需求、IDragHandler 系列拖拽接口、拖拽层级遮挡解决方案、格子交换 / 空格存放 / 丢弃逻辑、射线穿透接口、物品悬浮信息面板、跟随鼠标悬浮 UI、项目开发前置需求分析、AI 工具合理使用规范

一、背包拖拽功能三大核心需求

1 概念

实现物品鼠标拖拽交互,拆解三类场景逻辑,提前梳理需求再编码,避免写一半返工修改。

2 特性 / 规则

  1. 层级问题:拖拽物品不能被格子遮挡,需要提升渲染层级放在画布顶层;

  2. 跟随问题:拖拽全程跟随鼠标坐标移动;

  3. 落点分支逻辑:

    ① 拖到空格子:物品移入空格,原格子清空;

    ② 拖到已有物品格子:两件物品交换位置、数据互换;

    ③ 拖到背包空白区域:销毁物品(丢弃道具)。

3 相关知识点对比

写完代码再改需求 VS 先梳理需求再编码

直接编码:中途新增交换逻辑,大量代码重构、产生 Bug; 需求前置:分场景设计逻辑,代码一次性写完,结构清晰易维护。

5 模块拓展

拓展拖拽拆分、批量丢弃、拖拽到快捷栏功能。

二、Unity 拖拽标准接口体系

1 概念

UGUI 内置拖拽四组接口,挂载在物品 Image 组件,分别对应拖拽开始、拖拽中、拖拽结束、射线穿透控制。

2 特性 / 规则

  1. IBeginDragHandler:鼠标按下刚拖拽触发;

  2. IDragHandler:拖拽过程每帧持续执行;

  3. IEndDragHandler:松开鼠标拖拽结束;

  4. ICanvasRaycastFilter:控制拖拽时射线穿透下方格子,解决遮挡检测失效 Bug。

3 语法 & 代码片段

复制代码
using UnityEngine.EventSystems;
public class BagDragItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, ICanvasRaycastFilter{
    private Transform originParent; // 记录原始格子父物体
    public bool isRayPass = false;
    // 拖拽开始
    public void OnBeginDrag(PointerEventData eventData){
        originParent = transform.parent;
        transform.SetParent(transform.root); // 提升到画布顶层
        isRayPass = true; // 开启射线穿透
    }
    // 拖拽跟随鼠标
    public void OnDrag(PointerEventData eventData){
        transform.position = eventData.position;
    }
    // 拖拽结束处理落点
    public void OnEndDrag(PointerEventData eventData){
        isRayPass = false;
        GameObject hitObj = eventData.pointerCurrentRaycast.gameObject;
        DealDropResult(hitObj);
    }
    // 射线穿透接口实现
    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera){
        return !isRayPass;
    }
    // 落点分支逻辑
    void DealDropResult(GameObject hit){
        if(hit == null){
            Destroy(gameObject); // 丢弃物品
            return;
        }
        if(hit.CompareTag("BagSlot")){
            ExchangeItem(this, hit.GetComponent<BagSlot>());
        }
        else if(hit.CompareTag("BagItem")){
            SwapTwoItem(this, hit.GetComponent<BagDragItem>());
        }
        else{
            // 无有效落点,放回原格子
            transform.SetParent(originParent);
            transform.localPosition = Vector3.zero;
        }
    }
}

4 相关知识点对比

手动监听鼠标拖拽 VS 官方拖拽接口

手动 Input 判断:坐标计算复杂,多 UI 拖拽冲突; 官方接口:EventSystem 统一管理,自动处理射线、坐标,兼容性更强。

5 模块拓展

拖拽时缩放半透明渐变视觉效果。

三、拖拽层级遮挡解决方案

1 概念

拖拽物品默认在格子下层,无法检测下方格子碰撞,拖拽开始将物品父物体切换为画布根节点,渲染层级置顶。

2 特性 / 规则

  1. transform.root 直接获取顶层 Canvas,无需手动赋值画布引用;

  2. 拖拽结束切回对应格子父物体,恢复正常层级;

  3. 搭配 ICanvasRaycastFilter 拖拽时开启射线穿透,不阻挡下方格子射线检测。

4 相关知识点对比

修改 SortingLayer 层级 VS 切换父物体置顶

改层级:多界面叠加容易层级错乱; 切换父物体:画布永远最高层级,稳定无冲突。

5 模块拓展

弹窗内拖拽单独设置弹窗容器为父物体,不干扰全局界面。

四、三类落点完整逻辑(空格 / 交换 / 丢弃)

1 概念

拖拽结束通过射线命中物体 Tag 区分三类落点,分别处理 UI 显示与底层 Model 数据同步。

2 特性 / 规则

  1. 拖至空格子 BagSlot:

    UI:当前物品移入空格,原格子 itemId 置 0;

    数据:Model 中原格子物品数量清除,空格写入物品 ID 与数量;

  2. 拖至已有 BagItem:两件物品 UI 互换父物体,双向交换格子 itemId;

  3. 无命中物体:销毁物品预制,同步删除 Model 内物品数据。

3 语法 & 代码片段

复制代码
// 拖入空格子
void ExchangeItem(BagDragItem item, BagSlot emptySlot){
    BagSlot oldSlot = item.originParent.GetComponent<BagSlot>();
    // UI层级交换
    transform.SetParent(empty.transform);
    transform.localPosition = Vector3.zero;
    // 同步底层数据
    int tempId = oldSlot.itemId;
    oldSlot.itemId = 0;
    emptySlot.itemId = tempId;
}
// 两件物品互相交换
void SwapTwoItem(BagDragItem self, BagDragItem targetItem){
    BagSlot slotA = self.originParent.GetComponent<BagSlot>();
    BagSlot slotB = targetItem.originParent.GetComponent<Transform>().GetComponent<BagSlot>();
    // UI互换父物体
    self.transform.SetParent(slotB);
    targetItem.transform.SetParent(slotA);
    self.originParent = slotB.transform;
    targetItem.originParent = slotA.transform;
    // 交换ID数据
    int temp = slotA.itemId;
    slotA.itemId = slotB.itemId;
    slotB.itemId = temp;
}

4 相关知识点对比

只改 UI 视觉不同步数据 VS UI+Model 同步修改

只改图片:后台数据不变,刷新背包位置复原; 双向同步:视图、数据完全统一,切换场景数据不错乱。

5 模块拓展

增加物品数量交换逻辑,支持可堆叠道具拆分拖拽。

五、ICanvasRaycastFilter 射线穿透接口

1 概念

拖拽时物品 Image 会拦截鼠标射线,无法拾取下方格子,通过接口控制拖拽阶段射线失效,松开后恢复检测。

2 特性 / 规则

  1. 接口返回 false 代表当前 UI 不阻挡射线,鼠标可穿透拾取下层物体;

  2. 拖拽 Begin 置 isRayPass=true,IsRaycastLocationValid 返回 false;

  3. 拖拽 End 恢复 isRayPass=false,正常点击交互。

4 相关知识点对比

关闭 Image 射线勾选 VS 动态接口控制

永久关闭:平时无法点击选中物品; 动态控制:仅拖拽阶段穿透,日常点击正常。

5 模块拓展

弹窗遮罩、全屏面板通用射线过滤逻辑复用。

六、物品悬浮信息提示面板

1 概念

鼠标移入物品弹出描述 UI,显示名称、回血、售价等配置信息,鼠标移出自动隐藏。

2 特性 / 规则

  1. 两种布局方案:固定侧边面板 / 跟随鼠标悬浮面板;

  2. 面板使用九宫图片做背景,文本拼接 XML 配置读取的物品属性;

  3. 跟随鼠标时增加坐标偏移,避免提示框遮挡当前物品导致移出触发隐藏。

3 语法 & 代码片段

复制代码
public class ItemTipPanel : BasePanel{
    public Text nameTxt;
    public Text descTxt;
    public void ShowTip(int itemId, Vector2 mousePos){
        ItemInfo data = ItemConfig.Instance.GetItem(itemId);
        nameTxt.text = data.ItemName;
        // 拼接描述文字
        string desc = $"效果:回复{data.Hp}血量\n售价:{data.SellPrice}";
        descTxt.text = desc;
        // 鼠标偏移,防止遮挡
        rect.anchoredPosition = mousePos + new Vector2(-320, 200);
        Show();
    }
    public void HideTip(){
        Close();
    }
}
// 物品鼠标移入移出
public class BagDragItem : IPointerEnterHandler, IPointerExitHandler{
    public int itemId;
    public void OnPointerEnter(PointerEventData eventData){
        ItemTipPanel.Instance.ShowTip(itemId, Input.mousePosition);
    }
    public void OnPointerExit(PointerEventData eventData){
        ItemTipPanel.Instance.HideTip();
    }
}

4 相关知识点对比

固定侧边提示 VS 鼠标跟随提示

固定面板:界面布局稳定,不会遮挡交互; 跟随悬浮:查看任意物品无需移动视线,RPG 主流设计。

5 模块拓展

提示面板增加道具图标、品质颜色区分。

七、项目标准开发思维:先需求再编码

1 概念

写功能前完整梳理所有交互场景、边界异常,再编写代码,减少后期大量重构修改。

2 特性 / 规则

  1. 拖拽提前梳理:置顶、跟随、空格交换丢弃三类落点;

  2. 界面功能区分核心逻辑与辅助展示;

  3. 数据与视图分层(MVC),不能只改 UI 忽略 Model 存储;

  4. 边界 Case 处理:背包满、道具堆叠、拖拽出界全部提前规划。

4 相关知识点对比

边写边想 VS 需求前置梳理

边写边改:代码冗余、分支遗漏,Bug 极多; 先梳理需求:逻辑闭环,代码简洁易维护,面试加分。

5 模块拓展

任务、商城、角色界面全部遵循需求前置开发流程。

八、AI 工具使用规范

1 概念

AI 可辅助查语法、生成片段,但禁止直接复制完整项目代码,底层逻辑必须手写吃透,面试可完整口述实现流程。

2 特性 / 规则

  1. 只会复制代码无法讲清原理,面试极易暴露基础薄弱;

  2. 复杂功能(背包、Socket、MVC)独立手写,锻炼排错能力;

  3. AI 仅用来查 API、优化冗余代码,不作为项目主体代码来源。

4 相关知识点对比

依赖 AI 复制 VS 自主手写

AI 复制:底层原理模糊,遇到报错无法自主排查; 自主手写:掌握每段代码作用,面试口述、线上排错无压力。

5 模块拓展

后期进阶可学习 AI 对接游戏工具、批量生成配置脚本。

综合拓展

1 背包拖拽整套开发流程

1)梳理拖拽三大落点需求;

2)实现 IBeginDrag/IDrag/IEndDrag 拖拽接口,切换父物体置顶;

3)射线过滤接口解决遮挡检测;

4)编写空格存放、物品交换、丢弃三套数据 + UI 同步逻辑;

5)实现鼠标悬浮物品信息提示面板;

2 高频 Bug 排查清单

拖拽物品挡住格子:未开启 ICanvasRaycastFilter 射线穿透;

交换后数据错乱:只改 UI 未同步 BagSlot itemId;

提示框闪烁遮挡:鼠标跟随无坐标偏移;

拖拽后物品层级错乱:结束未切回原父物体;

3 考点

UGUI 拖拽全套接口、射线过滤原理、背包物品交换逻辑、MVC 视图数据分离、功能前置需求分析;

4 进阶拓展学习方向

道具堆叠拆分、拖拽至快捷技能栏、背包批量出售、装备穿戴拖拽、存档持久化;

5 实战落地要求

整合拖拽、悬浮提示、XML 配表、MVC 数据层完整背包模块写入 RPG 项目。

相关推荐
xcLeigh6 小时前
Unity基础:Start与Update方法——Unity脚本生命周期初探
java·unity·游戏引擎·教程
郝学胜-神的一滴7 小时前
[简化版 GAMES 104] 现代游戏引擎 05:游戏引擎世界构建核心机制深度解析
c++·程序人生·unity·游戏引擎·计算机图形学·opengl
cyadyx1 天前
【Three.js】Three.js 中加载 3D 模型
前端·javascript·3d
松树戈1 天前
godot项目【宝石捕手】04~添加音效、记分
游戏引擎·godot
chaoyuanl1 天前
悬空玻璃剧场源头厂家选型全解析|270°裸眼3D悬空玻璃剧场投资避坑指南
大数据·人工智能·3d·xr·娱乐·mr
LONGZETECH1 天前
无人机实训高成本痛点解法:虚拟仿真实现 70% 耗材损耗下降
大数据·算法·unity·架构·无人机
在下胡三汉1 天前
GLTF vs OBJ vs FBX vs GLB:选择合适的 3D 文件格式,怎么获取下载
3d
fanfan_hongyun1 天前
Cesium for unity (可加载3dTileset)
3d
鲲穹AI种草1 天前
家装设计工具记录:多款室内 3D 设计工具能力边界整理
3d·家装设计工具