Unity游戏开发实现背包系统的示例详解

 更新时间:2022年08月11日 16:41:18   作者:lucky_  
这篇文章主要为大家介绍了Unity游戏开发实现背包系统的示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

背包是游戏中经常使用的一个组件,它负责管理玩家在游戏中所获得的道具。一个完整的背包系统应当具有将物品放置进背包、对背包内物品进行管理和使用背包内物品等功能。而往往一个背包系统的逻辑关系较为复杂,如果把所有功能都放在一个脚本中实现会使代码显得十分冗杂且缺乏逻辑。所以在背包系统的设计过程中,我们常将其分解为数据、逻辑和UI三部分分别来进行完成。

一、UI设计

以Cotton Puzzle中的背包设计为例,我们需要有物品展示栏、物品切换按键和物品提示信息等部分。

在Canvas中创建ItemHolder,在ItemHolder中创建LeftButton和RightButton控制物品的左右切换、Slot来控制物品的显示以及ItemToolTip来显示物品的提示信息。

二、UI

==创建InventoryUI脚本并挂在ItemHolder上以对整个背包UI进行管理。== 首先,确定InventoryUI可以控制的组件并定义当前所显示的物品序号,由于ItemToolTip的显示与否和Slot直接相关联,所以可以通过控制Slot间接控制ItemToolTip,在InventoryUI中便不再单独对其进行控制。

//InventoryUI.cs
    public Button leftButton;
    public Button rightButton;
    public SlotUI slotUI;
    public int currentItemIndex;//当前物品序号

2.1 Slot中的物品显示

//InventoryUI.cs
    /// <summary>
    /// 更新Slot中物品图片
    /// </summary>
    /// <param name="itemDetails"></param>
    /// <param name="index"></param>
    private void OnUpdateUIEvent(ItemDetails itemDetails, int index)
    {
        if (itemDetails == null)//当前物品为空
        {
            slotUI.SetEmpty();
            currentItemIndex = -1;
            leftButton.interactable = false;
            rightButton.interactable=false;
        }
        else
        {
            currentItemIndex = index;
            slotUI.SetItem(itemDetails);
            if (index > 0)
                leftButton.interactable = true;
            if (currentItemIndex == -1)
            {
                leftButton.interactable = false;
                rightButton.interactable = false;
            }
        }
    }

定义UpdateUIEvent事件来实时管理Slot中显示的物品(通过调用SlotUI中实现的SetEmpty()和SetItem(itemDetails)方法实现)和左右按钮的可使用情况。

//InventoryUI.cs
    private void OnEnable()
    {
        EventHandler.UpdateUIEvent += OnUpdateUIEvent;
    }
    private void OnDisable()
    {
        EventHandler.UpdateUIEvent -= OnUpdateUIEvent;
    }

2.2 物品切换

//InventoryUI.cs
    /// <summary>
    /// 左右按钮使用事件
    /// </summary>
    /// <param name="amount"></param>
    public void SwitchItem(int amount)
    {
        var index = currentItemIndex + amount;
        if(index< currentItemIndex)
        {
            leftButton.interactable = false;
            rightButton.interactable = true;
        }
        else if(index> currentItemIndex)
        {
            leftButton.interactable = true;
            rightButton.interactable = false;
        }
        else
        {
            leftButton.interactable = true;
            rightButton.interactable = true;
        }
        EventHandler.CallChangeItemEvent(index);
    }

2.3 SlotUI的实现

在SlotUI中需要实现将Slot图片设置为指定物品(包含物品为空的情况)、鼠标点击反馈、鼠标移入移出反馈(这里主要要实现当鼠标移入显示物品文字描述信息,移出取消显示的功能)。

//SlotUI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class SlotUI : MonoBehaviour, IPointerClickHandler, IPointerEnterHandler, IPointerExitHandler
{
    public Image itemImage;
    public ItemDetails currentItem;
    public ItemToolTip toolTip;
    private bool isClicked;
    /// <summary>
    /// 设置Slot图片为指定item
    /// </summary>
    /// <param name="itemDetails"></param>
    public void SetItem(ItemDetails itemDetails)
    {
        currentItem = itemDetails;
        this.gameObject.SetActive(true);
        itemImage.sprite = itemDetails.itemSprite;
        itemImage.SetNativeSize();
    }
    /// <summary>
    /// 设置Slot图片为空
    /// </summary>
    public void SetEmpty()
    {
        this.gameObject.SetActive(false);
    }
    public void OnPointerClick(PointerEventData eventData)
    {
        isClicked = !isClicked;
        EventHandler.CallItemSelectedEvent(currentItem, isClicked);
    }
    public void OnPointerEnter(PointerEventData eventData)
    {
        if (this.gameObject.activeInHierarchy)
        {
            toolTip.gameObject.SetActive(true);
            toolTip.UpdateItemName(currentItem.itemName);
        }
    }
    public void OnPointerExit(PointerEventData eventData)
    {
        toolTip.gameObject.SetActive(false);
    }
}

2.4 物品描述信息的展示

首先我们需要定义一个变量来记录物品的信息。这里我们在ItemToolTip下创建一个Text来记录文本信息。

//ItemToolTip.cs
    public Text itemNameText;

接下来定义方法根据目前Slot所展示的物品名字来修改Text的内容。

//ItemToolTip.cs
    public void UpdateItemName(ItemName itemName)
    {
        itemNameText.text = itemName switch
        {
            ItemName.Key => "信箱钥匙",
            ItemName.Ticket => "一张船票",
            _ => ""
        };
    }

为了方便使用我们将物品名写成了枚举变量,定义在Enums脚本中,方便在其他脚本中也可以使用。

//Enums.cs
/// <summary>
/// 物品名
/// </summary>
public enum ItemName
{
    None,
    Key,
    Ticket,
}

三、数据

首先为了我们能够在unity中更加直观地对数据进行修改,利用以下代码在unity的菜单下创建数据子菜单,并序列化对象。每个ItemDetails包含物品名(itemName)和物品贴图(itemSprite)两个属性。

//ItemDataList.cs
[CreateAssetMenu(fileName ="ItemDataList",menuName = "Inventory/ItemDataList")]
/// <summary>
/// 对象序列化
/// </summary>
[System.Serializable]
public class ItemDetails
{
    public ItemName itemName;
    public Sprite itemSprite;
}

在unity中可以直接新建一个ItemDataList的数据对象,创建方式为:右键 -> Create ->Inventory -> ItemDataList

定义GetItemDetails根据物品名获取ItemDetails 对象。

//ItemDataList.cs
    public List<ItemDetails> itemDetailsList = new List<ItemDetails>();
    public ItemDetails GetItemDetails(ItemName itemName)
    {
        return itemDetailsList.Find(i => i.itemName.Equals(itemName));
    }

四、逻辑

对于场景中的物体,在鼠标点击后需要能够被添加到背包内并在原有位置消失。可通过ItemClicked()函数来实现。

//Item.cs
    public ItemName itemName;
    public void ItemClicked()
    {
        //隐藏鼠标点击物体
        this.gameObject.SetActive(false);
        //将物品添加到背包
        InventoryManager.Instance.AddItem(itemName);
    }

最后,需要定义一个脚本InventoryManager对背包系统的UI、数据进行一个==统一的管理==。

//InventoryManager.cs
    [SerializeField] private List<ItemName> itemList = new List<ItemName>();
    public ItemDataList itemData;//通过物品名在物品列表中查找相应物品

(1)在新加载游戏的时候需要清空物品列表

    private void OnStartNewGameEvent(int gameWeek)
    {
        itemList.Clear();
    }

(2)当物品被使用时需要将物品移除背包并更新UI

    private void OnItemUsedEvent(ItemName itemName)
    {
        var index = GetItemIndex(itemName);
        itemList.RemoveAt(index);
        if (itemList.Count == 0)
            EventHandler.CallUpdateUIEvent(null, -1);
    }

(3)当场景加载之后,需要将目前背包中有的物品进行更新

    private void OnAfterSceneLoadedEvent()
    {
        if (itemList.Count == 0)
            EventHandler.CallUpdateUIEvent(null, -1);
        else
        {
            for (int i = 0; i < itemList.Count; i++)
            {
                EventHandler.CallUpdateUIEvent(itemData.GetItemDetails(itemList[i]), i);
            }
        }
    }

(4)当使用Button在背包中左右切换物品时,需要实时更改物品的图片并判断是否越界

    private void OnChangeItemEvent(int index)
    {
        if (index >= 0 && index < itemList.Count)
        {
            ItemDetails item = itemData.GetItemDetails(itemList[index]);
            EventHandler.CallUpdateUIEvent(item, index);
        }
        else
        {
            Debug.Log("越界!");
        }
    }

注册这些事件:

    private void OnEnable()
    {
        EventHandler.ChangeItemEvent += OnChangeItemEvent;
        EventHandler.AfterSceneLoadedEvent += OnAfterSceneLoadedEvent;
        EventHandler.ItemUsedEvent += OnItemUsedEvent;
        EventHandler.StartNewGameEvent += OnStartNewGameEvent;
    }
    private void OnDisable()
    {
        EventHandler.ChangeItemEvent -= OnChangeItemEvent;
        EventHandler.AfterSceneLoadedEvent -= OnAfterSceneLoadedEvent;
        EventHandler.ItemUsedEvent -= OnItemUsedEvent;
        EventHandler.StartNewGameEvent -= OnStartNewGameEvent;
    }

另外有一些工具函数需要实现:

    public void AddItem(ItemName itemName)
    {
        if(!itemList.Contains(itemName))//列表中不包含物品则添加到列表中
        { 
            itemList.Add(itemName);
        }
        //UI显示
        EventHandler.CallUpdateUIEvent(itemData.GetItemDetails(itemName), itemList.Count - 1);
    }
    /// &lt;summary&gt;
    /// 获取物品在列表中的序号
    /// &lt;/summary&gt;
    /// &lt;param name="itemName"&gt;&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    private int GetItemIndex(ItemName itemName)
    {
        for(int i=0;i&lt;itemList.Count;i++)
        {
            if(itemName.Equals(itemList[i]))
                return i;
        }
        return -1;
    }

以上就是Unity游戏开发实现背包系统的示例详解的详细内容,更多关于Unity游戏开发背包系统的资料请关注脚本之家其它相关文章!

相关文章

  • C#使用浏览按钮获得文件路径和文件夹路径的方法

    C#使用浏览按钮获得文件路径和文件夹路径的方法

    这篇文章主要介绍了C#使用浏览按钮获得文件路径和文件夹路径的方法,结合实例形式分析了C#浏览器事件响应及文件操作相关技巧,需要的朋友可以参考下
    2017-05-05
  • 基于数据类型转换(装箱与拆箱)与常量详解

    基于数据类型转换(装箱与拆箱)与常量详解

    下面小编就为大家分享一篇基于数据类型转换(装箱与拆箱)与常量详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-11-11
  • Unity3D开发教程:愤怒的小鸟

    Unity3D开发教程:愤怒的小鸟

    这篇文章详细的讲解了如何从0开发出一个Unity3D的小游戏愤怒的小鸟,本文包含大量的图片与文字描述,也含有大量的源代码,可以让你快速入手,希望本篇文章对你有所帮助
    2021-06-06
  • C#实现控制Windows系统关机、重启和注销的方法

    C#实现控制Windows系统关机、重启和注销的方法

    这篇文章主要介绍了C#实现控制Windows系统关机、重启和注销的方法,涉及C#调用windows系统命令实现控制开机、关机等操作的技巧,非常简单实用,需要的朋友可以参考下
    2015-04-04
  • C# httpwebrequest访问HTTPS错误处理方法

    C# httpwebrequest访问HTTPS错误处理方法

    下面小编就为大家带来一篇C# httpwebrequest访问HTTPS错误处理方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • 详解C#如何使用重载方法实现不同类型数据的计算

    详解C#如何使用重载方法实现不同类型数据的计算

    这篇文章主要为大家详细介绍了C#如何使用重载方法实现不同类型数据的计算,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-02-02
  • C#串口通信工具类的封装

    C#串口通信工具类的封装

    这篇文章主要为大家详细介绍了C#串口通信工具类封装,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • C# WPF实现3D操作几何体效果

    C# WPF实现3D操作几何体效果

    众所周知,我的世界就是无数个像素块的集合,而像素块也就是立方体。关于新建立方体,这个大家已经非常熟练了,本文就来说说如何实现3D操作几何体效果吧
    2023-03-03
  • DevExpress TreeList 常见问题解决方法

    DevExpress TreeList 常见问题解决方法

    这篇文章主要介绍了DevExpress TreeList 常见问题解决方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-12-12
  • Unity实现多平台二维码扫描

    Unity实现多平台二维码扫描

    这篇文章主要为大家详细介绍了Unity实现多平台二维码扫描,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07

最新评论