【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, // 使用父对象的RectTransform
            mousePosition,
            null, // 如果Canvas是Overlay模式,可以传null
            out 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 中开发背包系统有所帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

nodejs入门(1):nodejs的前后端分离

一、引言 我关注nodejs还是从前几年做了的一个电力大数据展示系统开始的&#xff0c;当然&#xff0c;我肯定是很多年的计算机基础的&#xff0c;万变不离其宗。 现在web网站都流行所谓的前后端结构&#xff0c;不知不觉我也开始受到这个影响&#xff0c;以前都是前端直接操作…

go语言闭包捕获的是变量的引用而不是变量的值

在 Go 语言中&#xff0c;闭包捕获的是变量的引用&#xff0c;而不是变量的值。这意味着闭包会引用循环变量或外部变量的实际内存位置&#xff0c;而不是在闭包创建时复制变量的值。这种行为有时会导致意外的结果&#xff0c;尤其是在循环中创建多个闭包时。 闭包捕获变量的引…

记录eslint报错的情况

这几天在调试vue的eslint&#xff0c;害&#xff0c;我领导说eslint要打开规范代码&#xff0c;顺带看了一下eslint的规则&#xff0c;并且研究一下报错。切记每次修改了.eslintrc配置文件&#xff0c;需要重启项目再查看控制台&#xff0c;否则之前的报错会一直存在。 第一个…

Flink错误:一historyserver无法启动,二存在的文件会报错没有那个文件或目录

一.historyserver无法启动 historyserver执行了启动命令后却没有启动&#xff0c;而且也没有报错&#xff0c;如果日志无法启动的话网页8082是无法访问的 只能去查看日志 去flink的log文件查看日志&#xff1a; 发现应该是缺包了&#xff0c;导入jar包后可以解决 &#xff1a…

QT实操中遇到的一些(C++)疑惑点汇总

QT实操中 遇到的一些C疑惑点汇总 1.实例化对象的两种方法及其访问方式 1.1 示例 1.2 总结 2.基类成员的访问 2.1 直接访问继承的基类成员 2.1.1示例代码 2.1.2 输出结果 2.2 使用作用域解析符来显式调用基类成员函数 2.2.1 示例代码 2.2.2 输出结果 2.3 使用 this 指针访问基类…

【运维自动化-作业平台】如何使用全局变量之数组类型?

数组类型的全局变量也是作业平台里常用的&#xff0c;支持关联数组和索引数组&#xff0c;目前仅支持shell&#xff0c;语法跟shell一致。索引数组 语法 arry(1 2 3 a b c) ---定义一个数组arry ${arry[*]} ---获取所有数组元素 ${arry[]} ---获取所有数组元素 ${arry[0]} --…

docker安装zabbix +grafana

安装zabbix grafana 1、部署 mkdir -p /opt/zabbix/{data,backups}mkdir -p /opt/grafanasudo chown -R 472:472 /opt/grafanasudo chmod -R 755 /opt/grafanacat > docker-compose.yml <<-EOF version: 3.3services:mysql-server:image: mysql:8.1container_name: m…

容器安全检测和渗透测试工具

《Java代码审计》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484219&idx1&sn73564e316a4c9794019f15dd6b3ba9f6&chksmc0e47a67f793f371e9f6a4fbc06e7929cb1480b7320fae34c32563307df3a28aca49d1a4addd&scene21#wechat_redirect Docker-bench-…

GB 35114-2017 学习笔记(规避版权阉割版)

GB 35114-2017 学习笔记&#xff08;规避版权阉割版&#xff09; openstd.samr.gov.cn 国家标准全文公开系统 这个政府网站提供GB 35114-2017标准的的预览和下载&#xff0c;有需要的自行下载 GB 35114-2017作为一个国家强制标准&#xff0c;在国家标准全文公开系统 自己做个…

高校企业数据挖掘平台推荐

TipDM数据挖掘建模平台是由广东泰迪智能科技股份有限公司自主研发打造的可视化、一站式、高性能的数据挖掘与人工智能建模服务平台&#xff0c;致力于为使用者打通从数据接入、数据预处理、模型开发训练、模型评估比较、模型应用部署到模型任务调度的全链路。平台内置丰富的机器…

ROSSERIAL与Arduino IDE交叉开发(UBUNTU环境,包含ESP32、arduino nano)

ROSSERIAL与Arduino IDE交叉开发 一、简介二、安装1、Ubuntu下的Arduino IDE安装 **针对ESP32报错问题原因溯源和修改**三、运行结点 一、简介 这个教程展示在ubuntu环境下如何利用Arduino IDE配合rosserial开发机器人部件。通过Arduino IDErosserial实现arduino/esp32开发板通…

word-毕业论文的每一章节的页眉单独设置为该章的题目怎么设置

在Microsoft Word中&#xff0c;为毕业论文的每个章节设置不同的页眉&#xff0c;通常需要使用“分节符”来分隔各个章节&#xff0c;然后在每个章节中单独设置页眉。以下是详细步骤&#xff1a; 使用分节符 插入分节符&#xff1a; 将光标放在每个章节的末尾&#xff08;注意…

Flutter:SlideTransition位移动画,Interval动画延迟

配置vsync&#xff0c;需要实现一下with SingleTickerProviderStateMixinclass _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{// 定义 AnimationControllerlate AnimationController _controller;overridevoid initState() {super.…

H.265流媒体播放器EasyPlayer.js网页全终端安防视频流媒体播放器可以播放本地视频吗

H.264/H.265播放器EasyPlayer.js主要用于在网页上实现视频播放功能&#xff0c;特别是针对RTSP流的播放。它允许开发者在不需要安装额外插件或软件的情况下&#xff0c;直接在网页中嵌入和播放来自监控摄像头或其他RTSP源的视频流。 可以播放本地视频吗&#xff1f; 回答&…

Linux: 任务的定时与延期

概述 ls 这种命令是立刻执行的命令&#xff0c;在linux中命令还可以延时执行&#xff0c;它们都涉及到时间的观念 常用命令 先来看下有关系统时间的规格 1 &#xff09; date 命令调节时间 $ date 显示当前时间还可以去定制 date 的一个输出, $ man date 可自定义输出 $ d…

RBAC——基于角色的访问控制

目录 一、RBAC核心概念 1. 角色&#xff08;Role&#xff09; 2. 用户&#xff08;User&#xff09; 3. 权限&#xff08;Permission&#xff09; 4. 会话&#xff08;Session&#xff09; 二、RBAC模型的演进 1. RBAC0&#xff1a;基本模型 2. RBAC1&#xff1a;角色…

OceanBase V4.x应用实践:如何排查表被锁问题

DBA在日常工作中常常会面临以下两种常见情况&#xff1a; 业务人员会提出问题&#xff1a;“表被锁了&#xff0c;导致业务受阻&#xff0c;请帮忙解决。” 业务人员还会反馈&#xff1a;“某个程序通常几秒内就能执行完毕&#xff0c;但现在却运行了好几分钟&#xff0c;不清楚…

同三维T80003JEHS 4K/60帧HDMI/SDI超高清H.265解码器

1路HDMI和1路SDI输出&#xff0c;1路3.5音频输入和1路3.5音频输出&#xff0c;1个USB2.0口1个USB3.0口&#xff0c;带1个RS232串口&#xff0c;2个网口&#xff0c;支持1路4K60或4路4K30或16路1080P或32路720P解码输出。4种画面分割显示模式。 产品简介&#xff1a; 同三维T80…

【更新中】《硬件架构的艺术》笔记(五):低功耗设计

介绍 能量以热量形式消耗&#xff0c;温度升高芯片失效率也会增加&#xff0c;增加散热片或风扇会增加整体重量和成本&#xff0c;在SoC级别对功耗进行控制就可以减少甚至可能消除掉这些开支&#xff0c;产品也更小更便宜更可靠。本章描述了减少动态功耗和静态功耗的各种技术。…