【UGUI】Unity 背包系统实现02:道具信息提示与显示

在游戏开发中,背包系统是一个常见的功能模块,用于管理玩家拾取的物品。本文将详细介绍如何在 Unity 中实现一个简单的背包系统,包括道具信息的提示和显示功能。我们将通过代码和场景搭建来逐步实现这一功能。

1. 功能需求清单

在实现背包系统时,我们需要满足以下功能需求:

  1. 初始化物品栏:在游戏启动时,初始化背包界面,并添加一些启动物资。

  2. 拾取物体到背包:玩家可以拾取场景中的物体,并将其添加到背包中。

  3. 鼠标滑入显示道具信息:当鼠标滑入背包中的道具时,显示该道具的名称和图标。

  4. 鼠标点击显示道具信息:当鼠标点击背包中的道具时,显示该道具的详细信息。

2. 程序逻辑过程

2.1 初始化物品栏

在游戏启动时,我们需要动态生成背包格子,并为每个格子设置图标和名称。这些格子将作为道具的容器。

2.2 拾取物体到背包

玩家可以通过某种方式(如点击、碰撞等)拾取场景中的物体,并将其添加到背包中。这个功能可以通过扩展代码来实现,本文暂不详细讨论。

2.3 鼠标滑入显示道具信息

当鼠标滑入某个道具格子时,我们需要显示一个提示框,提示框中包含该道具的名称和图标。提示框的位置需要跟随鼠标移动。

2.4 鼠标点击显示道具信息

当鼠标点击某个道具格子时,我们需要显示一个详细信息面板,面板中包含该道具的名称和图标。

3. 必要的场景搭建

在 Unity 中,我们需要搭建一个简单的场景来测试背包系统。场景中需要包含以下元素:

  • Canvas:用于显示 UI 元素。

  • Grid Layout Group:用于排列背包格子。

  • 提示框和信息面板:用于显示道具信息。

  • 道具格子模板:用于动态生成背包格子。

4.代码步骤解释

## 1. 初始化物品栏

### 代码片段

```csharp
private void Awake()
{
    // 通过标签找到提示框和信息面板
    OneTip = GameObject.FindGameObjectWithTag("OneTip");
    InfoRect = GameObject.FindGameObjectWithTag("InfoRect");

    // 初始化系统数据
    for (int i = 0; i < 10; i++)
    {
        GameObject TempCloneGrid = GameObject.Instantiate(GridMuban, GridParentTrans);
        // 修改道具的图标
        TempCloneGrid.transform.GetChild(0).GetChild(0).GetComponent<Image>().sprite = oneIamge[i];
        // 修改道具的名字
        TempCloneGrid.transform.GetChild(1).GetChild(0).GetComponent<TextMeshProUGUI>().text = Name[i];
        // 为每个道具添加侦听功能
        TempCloneGrid.AddComponent<UInterMaager232>();
    }
}
```

### 解释

1. **查找提示框和信息面板**:
   ```csharp
   OneTip = GameObject.FindGameObjectWithTag("OneTip");
   InfoRect = GameObject.FindGameObjectWithTag("InfoRect");
   ```
   通过 `GameObject.FindGameObjectWithTag` 方法查找场景中带有特定标签的对象,分别赋值给 `OneTip` 和 `InfoRect`。

2. **动态生成背包格子**:
   ```csharp
   for (int i = 0; i < 10; i++)
   {
       GameObject TempCloneGrid = GameObject.Instantiate(GridMuban, GridParentTrans);
   ```
   循环生成 10 个背包格子,使用 `GameObject.Instantiate` 方法克隆 `GridMuban` 模板,并将其父物体设置为 `GridParentTrans`。

3. **修改道具的图标**:
   ```csharp
   TempCloneGrid.transform.GetChild(0).GetChild(0).GetComponent<Image>().sprite = oneIamge[i];
   ```
   获取克隆的格子的子物体的子物体的 `Image` 组件,并设置其 `sprite` 属性为 `oneIamge` 数组中的对应图标。

4. **修改道具的名字**:
   ```csharp
   TempCloneGrid.transform.GetChild(1).GetChild(0).GetComponent<TextMeshProUGUI>().text = Name[i];
   ```
   获取克隆的格子的子物体的子物体的 `TextMeshProUGUI` 组件,并设置其 `text` 属性为 `Name` 数组中的对应名称。

5. 添加交互管理脚本**:
 
   TempCloneGrid.AddComponent<UInterMaager232>();
   
   为每个克隆的格子添加 `UInterMaager232` 脚本,以便处理交互事件。

2. 鼠标滑入显示道具信息

代码片段


public void OnPointerEnter(PointerEventData eventData)
{
    Debug.Log("鼠标滑入了");
    MoveTip();
    // 显示提示框并设置内容
    if (!InventoryManager.OneTip.activeSelf)
    {
        InventoryManager.OneTip.SetActive(true);
        InventoryManager.OneTip.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = this.transform.GetChild(1).GetChild(0).GetComponent<TextMeshProUGUI>().text;
        InventoryManager.OneTip.transform.GetChild(1).GetComponent<Image>().sprite = this.transform.GetChild(0).GetChild(0).GetComponent<Image>().sprite;
    }
}
```

解释

1. **显示提示框**:

   if (!InventoryManager.OneTip.activeSelf)
   {
       InventoryManager.OneTip.SetActive(true);
   ```
   检查提示框是否处于激活状态,如果未激活则激活提示框。

2. **设置提示框内容**:
   ```csharp
   InventoryManager.OneTip.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = this.transform.GetChild(1).GetChild(0).GetComponent<TextMeshProUGUI>().text;
   InventoryManager.OneTip.transform.GetChild(1).GetComponent<Image>().sprite = this.transform.GetChild(0).GetChild(0).GetComponent<Image>().sprite;
   ```
   设置提示框中的文本和图标,使其与鼠标滑入的道具格子内容一致。

3. **跟随鼠标移动**:
   ```csharp
   MoveTip();
   ```
   调用 `MoveTip` 方法,使提示框跟随鼠标移动。

## 3. 鼠标点击显示道具信息

### 代码片段

```csharp
public void OnPointerClick(PointerEventData eventData)
{
    // 关闭提示框
    InventoryManager.OneTip.SetActive(false);
    Debug.Log("鼠标点击了");

    // 切换信息面板的显示状态
    if (InventoryManager.InfoRect.activeSelf)
    {
        InventoryManager.InfoRect.SetActive(false);
    }
    else
    {
        InventoryManager.InfoRect.SetActive(true);
        // 设置信息面板的内容
        InventoryManager.InfoRect.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = this.transform.GetChild(1).GetChild(0).GetComponent<TextMeshProUGUI>().text;
        InventoryManager.InfoRect.transform.GetChild(1).GetComponent<Image>().sprite = this.transform.GetChild(0).GetChild(0).GetComponent<Image>().sprite;
    }
}
 

 解释

1. **关闭提示框**:
   ```csharp
   InventoryManager.OneTip.SetActive(false);
   ```
   关闭提示框,避免与信息面板重叠。

2. **切换信息面板的显示状态**:
   ```csharp
   if (InventoryManager.InfoRect.activeSelf)
   {
       InventoryManager.InfoRect.SetActive(false);
   }
   else
   {
       InventoryManager.InfoRect.SetActive(true);
   ```
   检查信息面板是否处于激活状态,如果已激活则隐藏,否则显示信息面板。

3. **设置信息面板内容**:
   ```csharp
   InventoryManager.InfoRect.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = this.transform.GetChild(1).GetChild(0).GetComponent<TextMeshProUGUI>().text;
   InventoryManager.InfoRect.transform.GetChild(1).GetComponent<Image>().sprite = this.transform.GetChild(0).GetChild(0).GetComponent<Image>().sprite;
   ```
   设置信息面板中的文本和图标,使其与鼠标点击的道具格子内容一致。

## 4. 提示框跟随鼠标移动

### 代码片段

```csharp
void MoveTip()
{
    RectTransform TipObject = InventoryManager.OneTip.GetComponent<RectTransform>();

    // 获取鼠标在屏幕上的位置
    Vector3 mousePosition = Input.mousePosition;

    // 将屏幕坐标转换为画布坐标
    Vector2 canvasPosition;
    RectTransformUtility.ScreenPointToLocalPointInRectangle(
        TipObject.parent as RectTransform, // 使用父对象的RectTransform
        mousePosition,
        null, // 如果Canvas是Overlay模式,可以传null
        out canvasPosition);

    // 计算对象在鼠标右下角的位置
    Vector2 offset = new Vector2(TipObject.rect.width / 2, -TipObject.rect.height / 2f); // 右下角偏移

    // 设置对象的位置
    TipObject.localPosition = canvasPosition + offset;
}
```

### 解释

1. **获取鼠标位置**:
   ```csharp
   Vector3 mousePosition = Input.mousePosition;
   ```
   获取鼠标在屏幕上的位置。

2. **转换坐标**:
   ```csharp
   RectTransformUtility.ScreenPointToLocalPointInRectangle(
       TipObject.parent as RectTransform, // 使用父对象的RectTransform
       mousePosition,
       null, // 如果Canvas是Overlay模式,可以传null
       out canvasPosition);
   ```
   将屏幕坐标转换为画布坐标。

3. **计算偏移**:
   ```csharp
   Vector2 offset = new Vector2(TipObject.rect.width / 2, -TipObject.rect.height / 2f); // 右下角偏移
   ```
   计算提示框在鼠标右下角的位置偏移。

4. **设置位置**:
   ```csharp
   TipObject.localPosition = canvasPosition + offset;
   ```
   设置提示框的位置,使其跟随鼠标移动。

## 总结

通过以上步骤和代码解释,我们实现了一个简单的背包系统,包括道具信息的提示和显示功能。通过动态生成背包格子、处理鼠标事件,我们可以在 Unity 中轻松实现这一功能。希望本文对你在 Unity 中开发背包系统有所帮助。

5. 完整代码 + 注释

5.1 InventoryManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;public class InventoryManager : MonoBehaviour
{public GameObject GridMuban; // 背包格子模板public Transform GridParentTrans; // 背包格子的父物体public Sprite[] oneIamge = new Sprite[10]; // 道具图标数组public string[] Name = new string[10]; // 道具名称数组public static GameObject OneTip; // 提示框public static GameObject InfoRect; // 信息面板private void Awake(){// 通过标签找到提示框和信息面板OneTip = GameObject.FindGameObjectWithTag("OneTip");InfoRect = GameObject.FindGameObjectWithTag("InfoRect");// 初始化系统数据for (int i = 0; i < 10; i++){GameObject TempCloneGrid = GameObject.Instantiate(GridMuban, GridParentTrans);// 修改道具的图标TempCloneGrid.transform.GetChild(0).GetChild(0).GetComponent<Image>().sprite = oneIamge[i];// 修改道具的名字TempCloneGrid.transform.GetChild(1).GetChild(0).GetComponent<TextMeshProUGUI>().text = Name[i];// 为每个道具添加侦听功能TempCloneGrid.AddComponent<UInterMaager232>();}}private void Start(){// 初始状态下隐藏提示框和信息面板if (OneTip.activeSelf){OneTip.SetActive(false);}if (InfoRect.activeSelf){InfoRect.SetActive(false);}}
}

5.2 UInterMaager232.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using TMPro;
using UnityEngine.UI;public class UInterMaager232 : MonoBehaviour, IPointerEnterHandler, IPointerClickHandler, IPointerExitHandler
{public void OnPointerClick(PointerEventData eventData){// 关闭提示框InventoryManager.OneTip.SetActive(false);Debug.Log("鼠标点击了");// 切换信息面板的显示状态if (InventoryManager.InfoRect.activeSelf){InventoryManager.InfoRect.SetActive(false);}else{InventoryManager.InfoRect.SetActive(true);// 设置信息面板的内容InventoryManager.InfoRect.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = this.transform.GetChild(1).GetChild(0).GetComponent<TextMeshProUGUI>().text;InventoryManager.InfoRect.transform.GetChild(1).GetComponent<Image>().sprite = this.transform.GetChild(0).GetChild(0).GetComponent<Image>().sprite;}}public void OnPointerEnter(PointerEventData eventData){Debug.Log("鼠标滑入了");MoveTip();// 显示提示框并设置内容if (!InventoryManager.OneTip.activeSelf){InventoryManager.OneTip.SetActive(true);InventoryManager.OneTip.transform.GetChild(0).GetComponent<TextMeshProUGUI>().text = this.transform.GetChild(1).GetChild(0).GetComponent<TextMeshProUGUI>().text;InventoryManager.OneTip.transform.GetChild(1).GetComponent<Image>().sprite = this.transform.GetChild(0).GetChild(0).GetComponent<Image>().sprite;}}public void OnPointerExit(PointerEventData eventData){// 关闭提示框if (InventoryManager.OneTip.activeSelf){InventoryManager.OneTip.SetActive(false);}}void MoveTip(){RectTransform TipObject = InventoryManager.OneTip.GetComponent<RectTransform>();// 获取鼠标在屏幕上的位置Vector3 mousePosition = Input.mousePosition;// 将屏幕坐标转换为画布坐标Vector2 canvasPosition;RectTransformUtility.ScreenPointToLocalPointInRectangle(TipObject.parent as RectTransform, // 使用父对象的RectTransformmousePosition,null, // 如果Canvas是Overlay模式,可以传nullout canvasPosition);// 计算对象在鼠标右下角的位置Vector2 offset = new Vector2(TipObject.rect.width / 2, -TipObject.rect.height / 2f); // 右下角偏移// 设置对象的位置TipObject.localPosition = canvasPosition + offset;}
}

6. 脚本挂载和赋值

6.1 场景搭建

  1. Canvas:在场景中创建一个 Canvas,用于显示 UI 元素。

  2. Grid Layout Group:在 Canvas 下创建一个 Panel,并添加 Grid Layout Group 组件,用于排列背包格子。

  3. 提示框和信息面板:在 Canvas 下创建两个 Panel,分别命名为 OneTip 和 InfoRect,并分别添加 TextMeshPro 和 Image 组件。

  4. 道具格子模板:在 Canvas 下创建一个 Panel,命名为 GridMuban,并添加 Image 和 TextMeshPro 组件,用于显示道具的图标和名称。

6.2 脚本挂载

  1. InventoryManager:将 InventoryManager 脚本挂载到 Canvas 上,并将 GridMubanGridParentTransoneIamge 和 Name 字段赋值。

  2. UInterMaager232:该脚本会自动挂载到每个生成的背包格子上,无需手动挂载。

6.3 赋值

  1. GridMuban:将 GridMuban 对象拖拽到 InventoryManager 脚本的 GridMuban 字段。

  2. GridParentTrans:将 GridParentTrans 对象拖拽到 InventoryManager 脚本的 GridParentTrans 字段。

  3. oneIamge:将道具图标拖拽到 InventoryManager 脚本的 oneIamge 数组中。

  4. Name:将道具名称填入 InventoryManager 脚本的 Name 数组中。

总结

通过以上步骤,我们实现了一个简单的背包系统,包括道具信息的提示和显示功能。通过动态生成背包格子、处理鼠标事件,我们可以在 Unity 中轻松实现这一功能。希望本文对你在 Unity 中开发背包系统有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/475062.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器上部署并启动 Go 语言框架 **GoZero** 的项目

要在服务器上部署并启动 Go 语言框架 **GoZero** 的项目&#xff0c;下面是一步步的操作指南&#xff1a; ### 1. 安装 Go 语言环境 首先&#xff0c;确保你的服务器上已安装 Go 语言。如果还没有安装&#xff0c;可以通过以下步骤进行安装&#xff1a; #### 1.1 安装 Go 语…

Node.js | Yarn下载安装与环境配置

一、安装Node.js Yarn 是 Node.js 下的包管理工具&#xff0c;因此想要使用 Yarn 就必须先下载 Node.js。 推荐参考&#xff1a;Node.js | npm下载安装及环境配置教程 二、Yarn安装 打开cmd&#xff0c;输入以下命令&#xff1a; npm install -g yarn检查是否安装成功&…

【Linux实践2】实验四:存储管理

文章目录 一、存储管理的目的1.1 内存空间的分配与回收1.2 地址转换1.3 内存保护1.4 内存共享1.5 内存扩充 二、可变分区存储管理2.1 分区结构体定义2.2 初始化分区链表 三、内存分配算法实现3.1 首次适应算法&#xff08;First Fit&#xff09;3.1.1 算法实现 3.2 循环首次适应…

linux 中mysql查看慢日志

1、到mysql容器&#xff0c;先登录到数据库&#xff0c;查看是否开启 mysql -h 127.0.0.1 -uroot -p SHOW VARIABLES LIKE slow_query_log; 2、如果没有开启&#xff0c;需要先开启 set global slow_query_log ON; 3、查看慢日志文件 SHOW VARIABLES LIKE slow_query_log…

微服务day09

DSL查询 快速入门 GET /items/_search {"query": {"match_all": {}} } 叶子查询 GET /items/_search {"query": {"match_all": {}} }GET /items/_search {"query": {"multi_match": {"query": "脱…

vue中el-select 模糊查询下拉两种方式

第一种&#xff1a;先获取所有下拉数据再模糊查询&#xff0c;效果如下 1&#xff0c;页面代码&#xff1a;speciesList是种类列表List, speciesId 是speciesList里面对应的id&#xff0c;filterable是过滤查询标签 <el-form-item label"种类" prop"species…

django启动项目报错解决办法

在启动此项目报错&#xff1a; 类似于&#xff1a; django.core.exceptions.ImproperlyConfigured: Requested setting EMOJI_IMG_TAG, but settings are not c启动方式选择django方式启动&#xff0c;以普通python方式启动会报错 2. 这句话提供了对遇到的错误的一个重要线索…

【Redis】Redis实现的消息队列

一、用list实现【这是数据类型所以支持持久化】 消息基于redis存储不会因为受jvm内存上限的限制&#xff0c;支持消息的有序性&#xff0c;基于redis的持久化机制&#xff0c;只支持单一消费者订阅&#xff0c;无法避免消息丢失。 二、用PubSub【这不是数据类型&#xff0c;是…

【AI+教育】一些记录@2024.11.16

《万字长文&#xff0c;探讨关于ChatGPT的五个最核心问题》 万字长文&#xff0c;探讨关于ChatGPT的五个最核心问题关于 ChatGPT 铺天盖地的信息让人无所适从。本文则试图提炼出五个关键问题&#xff1a;如何理解这次范式突破&#xff0c;未来能达到的技术天花板&#xff0c;行…

【计算机网络】TCP协议

一、TCP协议格式 1.报头的含义 (1) 16位源端口号/16位目的端口号 自己的端口号 和 对方的端口号 (2) 4位首部长度 表示报头长度&#xff08;TCP报头总长度 4位首部长度 * 4字节&#xff09;最少有20字节 TCP报头总长度 -> 0000 ~ 1111 -> [0, 15] * 4 -> [0, 60…

http自动发送请求工具(自动化测试http请求)

点击下载《http自动发送请求工具(自动化测试http请求)》 前言 在现代软件开发过程中&#xff0c;HTTP 请求的自动化测试是确保应用程序稳定性和可靠性的关键环节。为了满足这一需求&#xff0c;我开发了一款功能强大且易于使用的自动化 HTTP 请求发送工具。该工具基于 C# 开发…

C++ —— 剑斩旧我 破茧成蝶—C++11

江河入海&#xff0c;知识涌动&#xff0c;这是我参与江海计划的第2篇。 目录 1. C11的发展历史 2. 列表初始化 2.1 C98传统的{} 2.2 C11中的{} 2.3 C11中的std::initializer_list 3. 右值引用和移动语义 3.1 左值和右值 3.2 左值引用和右值引用 3.3 引用延长生命周期…

Leetcode 有效的数独

这段代码解决的是 验证一个数独是否有效 的问题&#xff0c;其算法思想是基于 规则校验和状态记录。具体思想如下&#xff1a; 算法思想 核心目标&#xff1a; 检查每个数字在 同一行、同一列 和 同一个 3x3 子格 中是否重复。 状态记录&#xff1a; 使用 3 个布尔二维数组分别…

STM32设计学生宿舍监测控制系统-分享

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 本项目旨在利用STM32单片机为核心&#xff0c;结合传感器技术、无线通信技…

RabbitMQ消息可靠性保证机制4--消费端限流

7.7 消费端限流 在类似如秒杀活动中&#xff0c;一开始会有大量并发写请求到达服务端&#xff0c;城机对消息进行削峰处理&#xff0c;如何做&#xff1f; 当消息投递的速度远快于消费的速度时&#xff0c;随着时间积累就会出现“消息积压”。消息中间件本身是具备一定的缓冲…

爬虫开发工具与环境搭建——使用Postman和浏览器开发者工具

第三节&#xff1a;使用Postman和浏览器开发者工具 在网络爬虫开发过程中&#xff0c;我们经常需要对HTTP请求进行测试、分析和调试。Postman和浏览器开发者工具&#xff08;特别是Network面板和Console面板&#xff09;是两种最常用的工具&#xff0c;能够帮助开发者有效地捕…

单片机实验记录3

定时计数实验 【实验目的】 1)学习使用单片机定时/计数器 2)在程序中添加定时/计数功能&#xff0c;将相关程序部署在仿真环境中&#xff0c;观察运行的情况. 【实验内容】 必做&#xff1a;应用定时器中断和数码管&#xff0c;实现10秒倒计时功能 【实验代码】 必做&am…

(计算机毕设)基于SpringBoot+Vue的房屋租赁系统的设计与实现

博主可接毕设设计&#xff01;&#xff01;&#xff01; 各种毕业设计源码只要是你有的题目我这里都有源码 摘 要 社会的发展和科学技术的进步&#xff0c;互联网技术越来越受欢迎。网络计算机的生活方式逐渐受到广大人民群众的喜爱&#xff0c;也逐渐进入了每个用户的使用。互…

创新租赁APP开发提升用户体验与业务效率

内容概要 在这个互联网飞速发展的时代&#xff0c;租赁APP的开发成为了提升市场竞争力的重要一环。用户对租赁服务的需求与日俱增&#xff0c;而传统的方式已显得不够高效。这时候&#xff0c;创新的租赁APP就像是一道光&#xff0c;照亮了用户体验和业务效率的双重需求。通过…

【Java SE】数据库连接池

数据库连接池是一个管理数据库连接的容器。它的主要作用是分配和管理数据库连接&#xff0c;允许应用程序重复使用现有的连接&#xff0c;而不是每次都重新建立新的连接。此外&#xff0c;连接池会释放那些空闲时间超过最大限制的连接&#xff0c;从而避免因未及时释放连接而造…