自学内容网 自学内容网

【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 中开发背包系统有所帮助。


原文地址:https://blog.csdn.net/leoysq/article/details/143849559

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!