【无标题】

系列文章目录

麦田物语第八天



一、实现背包的数据结构

1.DataCollection->InventoryItem

在本小节要创建背包的相关数据,我们需要为背包创建一个单独的类型,背包不用存储很复杂的数据,只需要存储物品的ID和物品的数量即可。
首先我们需要在DataCollection(存放所有的结构体),添加一个单独的数据类型为Inventory使用,采用Struct而不是使用Class,原因在于Class在创建之后有可能为空,而这个空可能会影响游戏的正常运行,但是Struct创建时初始化为一个默认的值(不为空);同时不是直接删除物品信息,因为删除可能会造成背包中的物品失序。具体的Class和Struct的区别可以参考下面的这个网址:

https://www.cnblogs.com/jjg0519/p/10341010.html

然后进行这个结构体的编写InventoryItem,在这个结构体中的数据包括物品ID和物品的数量

InventoryItem代码如下

[System.Serializable]
public struct InventoryItem
{
    public int itemID;
    public int itemAmount;
}

2.InventoryBag_SO

所有的存储游戏信息的物品,我们都采用一个统一的SO文件进行存储,同时我们只需要创建多个针对不同的物体即可。
InventoryBag_SO与ItemDataList类似,代码如下。

[CreateAssetMenu(fileName = "InventoryBag_SO",menuName = "Inventory/InventoryBag")]
public class InventoryBag_SO : ScriptableObject
{
    public List<InventoryItem> itemList;
}

在这个SO文件中包含我们刚才创建的结构体用来存储物品。接着创建Assets->GameData->Inventory->Bags->PlayerBag_SO,给其在Inspector面板添加初始数组的大小。背包此时就创建好了,同时还需要InventoryManager的管理。

3.InventoryManager

首先在InventoryManager中声明变量playerBag_SO同时返回Unity为其赋值,取得背包后我们要在AddItem方法中为其添加物品(此时只是添加,不考虑背包是否有空位,是否有该物品的逻辑),添加和删除我们不是改变背包数组的数量,因此不能使用Add去添加,而是需要找到空位去添加(本节直接将拾取的物品添加到第一栏即可),我们通过形参将ItemID,ItemAmount的值添加到创建的newItem中,然后添加到playerBag_SO的List[0]的位置上。

namespace MFarm.Inventory
{
    public class InventoryManager : Singleton<InventoryManager>
    {
        [Header("背包数据")]
        public InventoryBag_SO playerBag_SO;

        /// <summary>
        /// 添加物品到Player背包
        /// </summary>
        /// <param name="item"></param>
        /// <param name="canDestory">是否要销毁物品</param>
        public void AddItem(Item item,bool canDestroy)
        {
            //背包是否有空位
            //是否已经有该物品
            InventoryItem newItem = new InventoryItem();
            newItem.itemID = item.itemID;
            newItem.itemAmount = 1;

            playerBag_SO.itemList[0] = newItem;

            if (canDestroy)
            {
                Destroy(item.gameObject);
            }
        }
    }
}

二、实现背包检查和添加物品

本小节要实现的功能是检查背包是否有空位以及是否背包中已经有了该物品。
我们编写CheckBagCapacity方法(检查背包是否有空位),对playerBag_SO数据的ItemID进行判断,如果itemID为0,则该位置的数据为空,返回true,否则返回false;
接着编写是否存在该物体的方法GetItemIndexInBag,对playerBag_SO中的数据进行遍历,判断是否有数据的序号等于添加进来的物品序号,有的话直接返回数据在数组中的位置,没有的话返回-1。
最后编写添加物品的方法AddItemAtIndex,利用前面编写的两个方法,如果index == -1并且背包存在空位置,那么找到第一个空位置,将物品添加进去;如果index != -1,那么物品的数量增加,并将原有的物品数据进行更改。
最后在AddItem方法只能中调用上述编写的方法即可。

编写的代码如下

public void AddItem(Item item,bool canDestroy)
        {
            //是否已经有该物品
            var index = GetItemIndexInBag(item.itemID);
            //背包是否有空位

            AddItemAtIndex(item.itemID, index, 1);

            
            if (canDestroy)
            {
                Destroy(item.gameObject);
            }
        }

        /// <summary>
        /// 检查背包是否有空位
        /// </summary>
        /// <returns></returns>
        private bool CheckBagCapacity()
        {
            for (int i = 0; i < playerBag_SO.itemList.Count; i++)
            {
                if (playerBag_SO.itemList[i].itemID == 0) return true;
            }
            return false;
        }

        /// <summary>
        /// 根据物品ID找到背包已有物品位置
        /// </summary>
        /// <param name="ID">物品ID</param>
        /// <returns>-1 表示没有找到这个物品</returns>
        private int GetItemIndexInBag(int ID)
        {
            for (int i = 0; i < playerBag_SO.itemList.Count; i++)
            {
                if (playerBag_SO.itemList[i].itemID == ID) return i;
            }
            return -1;
        }

        /// <summary>
        /// 在指定背包序号位置添加物品
        /// </summary>
        /// <param name="ID">物品ID</param>
        /// <param name="index">序号</param>
        /// <param name="amount">数量</param>
        private void AddItemAtIndex(int ID,int index,int amount)
        {
            if (index == -1 && CheckBagCapacity()) //背包里面没有这个物品同时背包有空位
            {
                var newItem = new InventoryItem { itemID = ID, itemAmount = amount };
                for (int i = 0; i < playerBag_SO.itemList.Count; i++)
                {
                    if (playerBag_SO.itemList[i].itemID == 0)
                    {
                        playerBag_SO.itemList[i] = newItem;
                        break;
                    }
                }
            }
            else //背包里面有这个物品
            {
                int currentAmount = playerBag_SO.itemList[index].itemAmount + amount;
                var newItem = new InventoryItem { itemID = ID, itemAmount = currentAmount };
                playerBag_SO.itemList[index] = newItem;
            }
        }

上述代码的实现效果是当我们拾取相同的物品时,物品数量会增加,拾取到不同的物品时,背包中的物品种类会增加(在背包不满的情况下)。

三、制作 Action Bar UI

本节是制作UI界面,制作背包的UI,UI界面的制作也是游戏中重要的一环,而且有一些小的点还是需要记录下来防止遗忘。
第一步就是创建新的场景UI,并拖拽到Hierarchy面板,同时删除场景中的Camera。
第二步就是添加UI了,那么首先就需要添加Canvas组件,然后调整Canvas组件的Canvas Scaler的参数,将UI Scale Mode改成Scale With Screen Size(随着屏幕大小改变),Reference Resolution(分辨率)改为640360,Match改为0.5,Reference Pixel Per Unit(像素大小)为20。
第三步就是在Canvas下添加空物体Inventory,使其拉到和屏幕一样的尺寸(更改Rect Transform组件的参数,即按住Alt键选择右下角的那个格式),接着创建Image组件(Panel也行),改名为ActionBar,也需要更改该组件的锚点位置,按住Alt键 + Shift键,点击第三行第二列的格式,使其锚点位于最下方,并调整其宽度(222)和高度(24),然后更改该组件的Source Image,但是我们需要进行拉伸时只想要更改其边框里面的大小,但是不想要更改其边框的大小(点击图片,打开Sprite Editor,然后拖拽其绿色的点,从而选择那些范围是可变的,那些范围是不可变的,然后点击Apply即可),调整完之后将Image组件的Image Type改成Sliced就OK啦。
第四步是创建可以点击的背包物体框,首先创建Button改名为Slot_Bag,更改其大小为22
22,然后为其添加子物体Image,保持和其父物体的大小相同,但是为了防止Image遮住边框,我们更改它的Rect Transform的偏移量 Left Top Right Bottom都改成1。将Text移动到下方,这样才可以显示Text的内容,更改Text的内容,文字大小,颜色,Alignment(对齐方式),以及偏移量(和上方相同)。

Unity的渲染层级中下方的会优先渲染。

接着再添加子物体Imge(改名为HightLight)作为被选中的高亮,也是调整锚点位置并更改Image组件的Source Image,这个高亮也是只有选中时才会被显示,因此现将其隐藏,接着将text改名为Amount,Button及其组物体的结构如下:
Buttom的组成
第四步就是我们想要我们创建的Button组件可以排布在边框的位置,我们就需要使用组件Horizontal Layout Group,在ActionBar下添加该组件并更改其对齐方式(Child Alignment)为Middle Center,更改其Padding的Left和Right均为1。
第五步就是我们想要显示背包的图片,那么我们将Image添加ActionBar下添加Image,但是由于ActionBar添加了Horizontal layout Group组件,所以该UI就会受其影响,但是我想要不受到这个组件的影响,因此给背包Image下添加组件Layout Element,并勾选Ignore layout,接着更改锚点的对其方式和偏移量,得到下面的效果。
在这里插入图片描述
最后将Slot_Bag制作成Prefab就OK啦,今天的学习就到这了!!!终于完了!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值