广告位联系
返回顶部
分享到

Unity游戏开发实现背包系统的介绍

C#教程 来源:互联网 作者:F11站长开发者 发布时间:2022-08-11 19:08:44 人浏览
摘要

引言 背包是游戏中经常使用的一个组件,它负责管理玩家在游戏中所获得的道具。一个完整的背包系统应当具有将物品放置进背包、对背包内物品进行管理和使用背包内物品等功能。而

引言

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

一、UI设计

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

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

二、UI

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

1

2

3

4

5

//InventoryUI.cs

    public Button leftButton;

    public Button rightButton;

    public SlotUI slotUI;

    public int currentItemIndex;//当前物品序号

2.1 Slot中的物品显示

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

//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)方法实现)和左右按钮的可使用情况。

1

2

3

4

5

6

7

8

9

//InventoryUI.cs

    private void OnEnable()

    {

        EventHandler.UpdateUIEvent += OnUpdateUIEvent;

    }

    private void OnDisable()

    {

        EventHandler.UpdateUIEvent -= OnUpdateUIEvent;

    }

2.2 物品切换

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

//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图片设置为指定物品(包含物品为空的情况)、鼠标点击反馈、鼠标移入移出反馈(这里主要要实现当鼠标移入显示物品文字描述信息,移出取消显示的功能)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

//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来记录文本信息。

1

2

//ItemToolTip.cs

    public Text itemNameText;

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

1

2

3

4

5

6

7

8

9

10

//ItemToolTip.cs

    public void UpdateItemName(ItemName itemName)

    {

        itemNameText.text = itemName switch

        {

            ItemName.Key => "信箱钥匙",

            ItemName.Ticket => "一张船票",

            _ => ""

        };

    }

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

1

2

3

4

5

6

7

8

9

10

//Enums.cs

/// <summary>

/// 物品名

/// </summary>

public enum ItemName

{

    None,

    Key,

    Ticket,

}

三、数据

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

1

2

3

4

5

6

7

8

9

10

11

//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 对象。

1

2

3

4

5

6

//ItemDataList.cs

    public List<ItemDetails> itemDetailsList = new List<ItemDetails>();

    public ItemDetails GetItemDetails(ItemName itemName)

    {

        return itemDetailsList.Find(i => i.itemName.Equals(itemName));

    }

四、逻辑

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

1

2

3

4

5

6

7

8

9

//Item.cs

    public ItemName itemName;

    public void ItemClicked()

    {

        //隐藏鼠标点击物体

        this.gameObject.SetActive(false);

        //将物品添加到背包

        InventoryManager.Instance.AddItem(itemName);

    }

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

1

2

3

//InventoryManager.cs

    [SerializeField] private List<ItemName> itemList = new List<ItemName>();

    public ItemDataList itemData;//通过物品名在物品列表中查找相应物品

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

1

2

3

4

private void OnStartNewGameEvent(int gameWeek)

{

    itemList.Clear();

}

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

1

2

3

4

5

6

7

private void OnItemUsedEvent(ItemName itemName)

{

    var index = GetItemIndex(itemName);

    itemList.RemoveAt(index);

    if (itemList.Count == 0)

        EventHandler.CallUpdateUIEvent(null, -1);

}

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

1

2

3

4

5

6

7

8

9

10

11

12

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在背包中左右切换物品时,需要实时更改物品的图片并判断是否越界

1

2

3

4

5

6

7

8

9

10

11

12

private void OnChangeItemEvent(int index)

{

    if (index >= 0 && index < itemList.Count)

    {

        ItemDetails item = itemData.GetItemDetails(itemList[index]);

        EventHandler.CallUpdateUIEvent(item, index);

    }

    else

    {

        Debug.Log("越界!");

    }

}

注册这些事件:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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;

}

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

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;

}


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。

您可能感兴趣的文章 :

原文链接 : https://juejin.cn/post/7130079021353664549
相关文章
  • WPF实现窗体亚克力效果的代码

    WPF实现窗体亚克力效果的代码
    WPF 窗体设置亚克力效果 框架使用大于等于.NET40。 Visual Studio 2022。 项目使用MIT开源许可协议。 WindowAcrylicBlur设置亚克力颜色。 Opacity设置透
  • C#非托管泄漏中HEAP_ENTRY的Size对不上解析

    C#非托管泄漏中HEAP_ENTRY的Size对不上解析
    一:背景 1. 讲故事 前段时间有位朋友在分析他的非托管泄漏时,发现NT堆的_HEAP_ENTRY的 Size 和!heap命令中的 Size 对不上,来咨询是怎么回事?
  • C#中ArrayList 类的使用介绍
    一:ArrayList 类简单说明 动态数组ArrayList类在System.Collecions的命名空间下,所以使用时要加入System.Collecions命名空间,而且ArrayList提供添加,
  • C#使用BinaryFormatter类、ISerializable接口、XmlSeriali

    C#使用BinaryFormatter类、ISerializable接口、XmlSeriali
    序列化是将对象转换成字节流的过程,反序列化是把字节流转换成对象的过程。对象一旦被序列化,就可以把对象状态保存到硬盘的某个位
  • C#序列化与反序列化集合对象并进行版本控制
    当涉及到跨进程甚至是跨域传输数据的时候,我们需要把对象序列化和反序列化。 首先可以使用Serializable特性。 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  • C#事件中关于sender的用法解读

    C#事件中关于sender的用法解读
    C#事件sender的小用法 开WPF新坑了,看了WPF的炫酷界面,再看看winForm实在是有些惨不忍睹(逃)。后面会开始写一些短的学习笔记。 一、什么
  • 在C#程序中注入恶意DLL的方法

    在C#程序中注入恶意DLL的方法
    一、背景 前段时间在训练营上课的时候就有朋友提到一个问题,为什么 Windbg 附加到 C# 程序后,程序就处于中断状态了?它到底是如何实现
  • 基于C#实现一个简单的FTP操作工具
    实现功能 实现使用FTP上传、下载、重命名、刷新、删除功能 开发环境 开发工具: Visual Studio 2013 .NET Framework版本:4.5 实现代码 1 2 3 4 5 6 7
  • C#仿QQ实现简单的截图功能

    C#仿QQ实现简单的截图功能
    接上一篇写的截取电脑屏幕,我们在原来的基础上加一个选择区域的功能,实现自定义选择截图。 个人比较懒,上一篇的代码就不重新设计
  • C#实现线性查找算法的介绍
    线性查找,肯定是以线性的方式,在集合或数组中查找某个元素。 通过代码来理解线性查找 什么叫线性?还是在代码中体会吧。 首先需要一
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计