【Unity】 2D 游戏 库存模块实现

2023-10-26

库存模块主要参考了 youtube 上的视频

BMo 的 Flexible INVENTORY SYSTEM in Unity with Events and Scriptable Objects 和 Simple Inventory UI in Unity With Grid Layouts 这两个视频是一个系列

还是一个视频也是 BMo的 How To INTERACT with Game Objects using UNITY EVENTS Tutorial

这三个视频讲述了怎么用Unity Event、delegate、Collider Trigger 的功能去做一个库存系统。

但我感觉 delegate 代理类注册的写法需要在另外一个类中硬编码会比较不美观,所有换了一种两个事件调用的写法。

功能点主要有两个:一个是物品从地图进入到库存,另一个就是,反过来,物品从库存中消失。

总体来说,前者比较复杂,后者比较简单。后者的功能代码仅仅是前者的一部分。

物品从地图进入到库存中的过程有三个:人物进到物品可以交互的范围里、人物和物品交互、物品进入到人物的库存中。这三个流程可以分别设计成独立的实体。

人物进到物品可以交互的范围里

人物可以交互的范围是有限的,不然就会出现人物隔着很远的距离可以和N多个物品交互。

这块功能的实现主要是用了 Unity Collider 2D 的功能,Collider 2D不仅可以作为实体碰撞的功能,也能检测物体从范围外进入到范围内。通过在 C# 中实现 OnTriggerEnter2D 和 OnTriggerExit2D 方法,就可以达到检测人物是否进入到物品可以交互的范围里。

在这里插入图片描述

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class PickUpControl : MonoBehaviour
{
    public Boolean isInRange;
    public KeyCode interactKey;
    public UnityEvent interactEvent;

    void Update()
    {
        if(isInRange)
        {
            if(Input.GetKeyDown(interactKey))
            {
                interactEvent.Invoke();
                UnityEngine.Debug.Log($"{transform.parent.name} Interact Event invoke");
            }
        }
    }

    /// <summary>
    /// Sent when another object enters a trigger collider attached to this
    /// object (2D physics only).
    /// </summary>
    /// <param name="other">The other Collider2D involved in this collision.</param>
    void OnTriggerEnter2D(Collider2D other)
    {
        if(other.transform.CompareTag("Player"))
        {
            isInRange = true;
            UnityEngine.Debug.Log($"{transform.parent.name} is in range");
        }

    }

    /// <summary>
    /// Sent when another object leaves a trigger collider attached to
    /// this object (2D physics only).
    /// </summary>
    /// <param name="other">The other Collider2D involved in this collision.</param>
    void OnTriggerExit2D(Collider2D other)
    {
        if(other.transform.CompareTag("Player"))
        {
            isInRange = false;
            UnityEngine.Debug.Log($"{transform.parent.name} is out of range");
        }
    }

}

在这里插入图片描述

(注意看左下角的Log 和 Scene 中 花所在位置的 Collider)

人物和物品交互

人物和物品的交互主要通过两个UnityEvent 交互完成,一个事件做在了 Prefab里,这个Prefab包含了一个上面说的范围检测,除此之外,还有一份受到键位交互触发事件的代码。

这段代码的作用是如果玩家已经到了交互范围内,并且按下了交互对应的案件,则会触发一个事件,这个事件是他parent transform 中对应交互的方法,例如图中的 Flower.class 的 bePickUp方法,对应花被捡起。

public Boolean isInRange;
    public KeyCode interactKey;
    public UnityEvent interactEvent;

    void Update()
    {
        if(isInRange)
        {
            if(Input.GetKeyDown(interactKey))
            {
                interactEvent.Invoke();
                UnityEngine.Debug.Log($"{transform.parent.name} Interact Event invoke");
            }
        }
    }

下一个事件则是由这个Collider中绑定的事件去调用玩家库存的交互函数,并将自己的实体对象作为参数传递进去。

public class Flower : MonoBehaviour
{
    public ItemData itemData;
    public int number;

    public UnityEvent<ItemData, int> pickUpFunction;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void bePickedUp()
    {
        // 资源销毁
        Destroy(gameObject);
        // 玩家拾起
        // ?. 是检查对应是否为空 的 C# 语法
        pickUpFunction?.Invoke(itemData, number);
    }
}

物品进入到人物库存中

物品进入到人物库存中,需要有一套库存相对应的代码,库存对应的概念可以是背包、仓库或者物品栏,我这里就简单以物品栏为例。

在这里插入图片描述

上从图中,可以简单看出物品栏有三个UI元素组成,一个物品栏,物品栏中的每一个格子与加入物品栏的物品元素。这三个都是由Unity Image 组件做的,不过物品组件多了一个 Sprite属性,可以由外界(比较说上面提到花)传入。

在这里插入图片描述

在我的设计中,InventoryPanel 对应了一份 InventoryManager代码,用来管理物品栏中的每一个格子。而每一个Slot对应可一份InventorySlot的代码,用来管理每一个格子对应的物品和数量。

从下而上来说,InventorySlot这份代码中,只需要做一件事,那就是构建物品图标和数量。当有新的物品加入时,就将新物品的Sprite传入到Icon属性中,数量传到 Count中。如果消除,则将这两个的enable属性改为 false,从而让物品不显示(消失)。

using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class InventorySlot : MonoBehaviour
{
    // Start is called before the first frame update
    public Image icon;
    public TextMeshProUGUI displayCount;
    public InventoryItem inventoryItem;
    void Start()
    {
        icon.enabled = false;
        displayCount.enabled = false;
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void ClearSlot()
    {
        icon.enabled = false;
        displayCount.enabled = false;
        inventoryItem = null;
    }

    public void DrawData(InventoryItem item)
    {

        if(item is null)
        {
            ClearSlot();
            return;
        }

        icon.enabled = true;
        displayCount.enabled = true;

        inventoryItem = item;
        icon.sprite = item.itemData.icon;
        
        displayCount.text = item.number.ToString();
    }
}

再说 InventoryManager,这份代码中需要写一个被交互物品可以调用的函数,这个函数的主要功能就是让物品加入物品栏时,到底是进入那一个格子。他的的入参是一个 物品对象 和 一个 int 的变量代表数量。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InventoryPanelManager : MonoBehaviour
{
private List inventorySlots = new List(10);

public 
// Start is called before the first frame update
void Start()
{
    for(int i = 0; i < transform.childCount && i < inventorySlots.Capacity; i++) 
    {

        inventorySlots.Add(transform.GetChild(i).GetComponent<InventorySlot>());
    }
}

// Update is called once per frame
void Update()
{
    
}

public void add(ItemData itemData, int number)
{
    InventoryItem inventoryItem = new InventoryItem(itemData, number);
    Boolean sign = false;
    for(int i = 0; i < inventorySlots.Capacity; i++)
    {
        Debug.Log($"{i} && {inventorySlots[i].inventoryItem}");
        // 物品已经存在 就用Slots中已有的 和 添加的 做叠加 并写入到对应Slot中
        if(inventorySlots[i].inventoryItem is not null && inventorySlots[i].inventoryItem.itemData.id.Equals(inventoryItem.itemData.id))
        {
            sign = true;
            InventoryItem sumInventroyItem = new InventoryItem(inventoryItem.itemData, inventoryItem.number + inventorySlots[i].inventoryItem.number);
            inventorySlots[i].DrawData(sumInventroyItem);
            return;
        }
    }
    // 物品不存在 找到第一个空位置 进行写数据
    if(!sign)
    {
        for(int i = 0; i < inventorySlots.Capacity; i++)
        {
            if(inventorySlots[i].inventoryItem is null)
            {
                inventorySlots[i].DrawData(inventoryItem);
                return;
            }
        }
    }
}

}

代码在Start()函数中,会将自己的子对象中的InventorySlot类绑定到自己的列表中,供下面的方法进行调用。

而在 void add(ItemData itemData, int number)函数中,会对列表中的InventorySlot做一个遍历查询,将相同的物品进行归并,如果没有的话,就会找到一个空格子,将物品放进去。

效果展示

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Unity】 2D 游戏 库存模块实现 的相关文章

  • cocos creator学习笔记 十分详细

    游戏系统 分辨率及适配 当屏幕分辨率与设计分辨率不同时会出现适配问题 widget 对节点实现自动定位 运行原理 生命期回调 onLoad 回调会在节点首次激活时触发 比如所在的场景被载入 或者所在节点被激活的情况下 通常我们会在 onLo
  • 【Unity步步升】监控与检测物体的各种方案,如:射线、碰撞、挂载等...

    在制作AR模型数值控制方案的时候遇到了检测的问题 学习过程受益匪浅 故今天为大家整理带来一篇监控与检测物体的参考方案集合 目录 一 射线检测 二 物体存在检测 三 碰撞检测 一 射线检测 单射线检测 首先完成搭建场景如下图1 1 我这里用到
  • 基于Python手把手教你实现flappy bird游戏

    目录 前言 开始前的准备工作 进入正题 结束语 前言 想必玩过游戏的都知道 Flappy Bird是一款简单却富有挑战性的经典的小鸟飞行游戏 让许多玩家为之痴迷 而作为开发者 那肯定要通过技术手段来再做一遍这款经典游戏 那么本文就来通过万能
  • Unity万向节死锁解决方案(2023/12/4)

    1 万向节死锁无法解决 这是因为它的特性就是如此 就像玻璃杯就是玻璃 这不可否认 别钻牛角尖昂 2 大多数情况下欧拉角足够用 例如 CF 摄像机不可能绕z轴旋转 x轴旋转也不会超过九十度 因为那样人物的腰子会被扭断 塔防游戏 保卫萝卜 吃鸡
  • 【原神游戏开发日志1】缘起

    原神游戏开发日志1 缘起 版权声明 本文为 优梦创客 原创文章 您可以自由转载 但必须加入完整的版权声明 文章内容不得删减 修改 演绎 相关学习资源见文末 大家好 最近看到原神在TGA上频频获奖 作为一个14年经验的游戏开发行业的老兵 我就
  • unity小球跟随音乐节奏放大缩小和改变颜色

    放在小球身上 设置对应组件即可 using System Collections using System Collections Generic using Unity VisualScripting using UnityEngine
  • 【转载】【Unity】WebSocket通信

    1 前言 Unity客户端常用的与服务器通信的方式有socket http webSocket 本文主要实现一个简单的WebSocket通信案例 包含客户端 服务器 实现了两端的通信以及客户端向服务器发送关闭连接请求的功能 实现上没有使用U
  • 坦克大战(二)

    欢迎来到程序小院 坦克大战 二 玩法 键盘 A W S D 键来控制方向 空格键发射子弹 N 下一关 P 上一关 Enter 开始 赶紧去闯关吧 开始游戏 https www ormcc com play gameStart 221 htm
  • Metasequoia4 for Mac/win:带您进入三维模型游戏建模的新世界!

    在当今游戏行业中 三维模型的重要性无可置疑 而在这个充满创造力和无限可能的领域中 Metasequoia4 简称M4 无疑是您的最佳选择 作为一款专业的三维模型游戏建模软件 M4凭借其强大的功能和简便易用的界面 成为了无数游戏开发者和设计师
  • 收单外包服务机构的评级工作已经开始了!

    评级收单外包服务机构的工作不仅是金融监管部门规范和引导收单外包服务市场的重要举措 也影响着外包机构的业务发展 并且是每年最重要的合规工作之一 中国支付清算协会于2023年12月18日发布了一份关于进行2023年度收单外包服务机构评级工作的通
  • Unity学习笔记

    一 旋转欧拉角 四元数 Vector3 rotate new Vector3 0 30 0 Quaternion quaternion Quaternion identity quaternion Quaternion Euler rota
  • 揭开神秘面纱,探索犹格索托斯的庭院:一款令人陶醉的模拟经营+AVG游戏

    你是否曾梦想过踏入一个充满神秘与奇幻的世界 体验一番独特的冒险 现在 这个梦想将成为现实 我们荣幸地向你介绍一款全新的模拟经营 AVG游戏 犹格索托斯的庭院 犹格索托斯的庭院是一款极具创意的游戏 它将带你进入一个神秘而充满魅力的世界 在这里
  • 全面解析找不到xinput1_3.dll无法继续执行代码的多种解决方案(实用教程)

    xinput1 3 dll文件是什么 xinput1 3 dll是一个动态链接库文件 它是DirectInput的组件之一 DirectInput是微软公司开发的一种输入设备驱动程序 用于处理游戏控制器 键盘 鼠标等输入设备的信号 xinp
  • Unity中URP下的指数雾

    文章目录 前言 一 指数雾 雾效因子 1 FOG EXP 2 FOG EXP2 二 MixFog 1 ComputeFogIntensity 雾效强度计算 2 lerp fogColor fragColor fogIntensity 雾效颜
  • Unity中URP下的指数雾

    文章目录 前言 一 指数雾 雾效因子 1 FOG EXP 2 FOG EXP2 二 MixFog 1 ComputeFogIntensity 雾效强度计算 2 lerp fogColor fragColor fogIntensity 雾效颜
  • VS2022 | 显示Unreal Engine日志

    VS2022 显示Unreal Engine日志 视图 gt 其他窗口 gt Unreal Engine日志 视图 gt 其他窗口 gt Unreal Engine日志
  • 游戏开发创建操作之玩家信息系统的建立

    游戏一般都需要玩家信息系统 那么我们应该如何搭建玩家信息系统 接下来我将展示一种简单的方法 完整代码如下 using System Collections using System Collections Generic using Uni
  • 游戏开发常见操作系列之敌人系统的开发一(U3D)

    在开发游戏的过程中 我们常常会出现一些敌人攻击我们玩家 并且实现掉血以及死亡的现象 敌人还会源源不断地生成 这是怎么制作的呢 接下来为大家提供方法 其中使用了NGUI 后续会更新其它方法 敬请期待 使用HUDText实现扣血时显示文本 直接
  • 2024年华为OD机试真题-虚拟游戏理财-Python-OD统一考试(C卷)

    题目描述 在一款虚拟游戏中生活 你必须进行投资以增强在虚拟游戏中的资产以免被淘汰出局 现有一家Bank 它提供有若干理财产品m 风险及投资回报不同 你有N 元 进行投资 能接受的总风险值为X 你要在可接受范围内选择最优的投资方式获得最大回报
  • 计算机Java项目|java游戏账号交易系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板

随机推荐

  • css样式表的作用和意义,什么是CSS?

    CSS是大家很熟悉的一个词了 但是如果问你 什么是CSS 你能回答得出吗 到底什么是CSS CSS有什么作用 CSS长什么样子 今天我们就给大家一一解答 CSS全称为Cascading Style Sheets 层叠样式表 中文翻译为 层叠
  • SUSE linux 使用LVM安装系统和管理

    引出 在我们安装好linux系统后会发现在需要修改磁盘分区的时候会比较困难 系统安装的 目录的文件系统要更改基本不太可能 其他目录如 home目录也比较困难 但是系统安装时要是采用的LVM管理的方式安装的话就会截然不通 一 首先普及下LVM
  • 嵌入式python智能实训总结_嵌入式智能家居心得体会 智能家居实训报告2000字

    家里装全套智能家居是一种什么体验 男士体验 5 半年后 我们发现有一篇回到第一篇文章 女性体验 第一篇 嗯 半夜哺乳 不用涂抹 第二篇 睡觉时忘记关灯 不要踢老公 第三 可以随时检查宝宝的状态 而且你可以监控老公是否不在家 第四 出行时 不
  • 软件测试之白盒测试

    白盒测试 一 白盒测试定义 白盒测试 又称结构测试 是在已知程序的内部工作过程的情况下 用来测试程序的内部结构 并判定其结果是否与预期的结果一致 一般说来 白盒测试相对简单 因为白盒测试是在已知程序的内部工作流程的情况下进行的 而且白盒测试
  • GIT常用命令以及使用详解图示

    1配置个人信息 方便提交代码管理 获取Git配置信息 执行以下命令 git config list 如果你还没有设置名字 user name 和 user email的话 可以用以下指令设置 git config global user n
  • 两种方法教你在postman设置请求里带动态token

    postman传递动态参数的最佳实践 问题描述 一 设置全局 环境变量传递 在postman中新增一个环境变量devToken 将获取到的token赋值给devToken 其他请求接口根据需要在请求时带上devToken 二 在每个请求中带
  • JAVA通过反射调用外部的jar包

    把外包jar的信息写在配置文件中 这样如果外部jar改变了 只需要修改properties相应的配置即可 config properties文件内容如下 jarUrl E MessageSend jar className org line
  • 高速USB转8串口产品设计-RS485串口

    基于480Mbps 高速USB转8路串口芯片CH348 可以为各类主机扩展出8个独立的串口 使用厂商提供的VCP串口驱动程序 可支持Windows Linux Android macOS等操作系统 使用单个CH348芯片即可实现USB一拖八
  • 离线 安装webssh

    1 安装包 和 webssh 代码准备 1 cmake 安装 安装参考文档 文档地址 下载地址 tar xvfz cmake 3 24 2 linux x86 64 tar gz 配置环境全局变量 vim etc profile 添加 ex
  • shell脚本初学(带参脚本传递、执行)(二)

    一 带有参数的shell脚本 脚本内获取参数的格式为 n n 代表一个数字 1 为执行脚本的第一个参数 2 为执行脚本的第二个参数 其中 0 为执行的文件名 包含文件路径 bin bash 指定编译器 test sh文件 echo Shel
  • C/C++和Python混合编程

    1 首先需要下载python源代码进行编译 源代码编译的过程访问如下链接 编译python源码 2 创建一个win32控制台项目 项目名称为 InvokePython 如图 3 然后将python源代码中的Include文件夹拷贝到该项目
  • 天线长度计算

    首先 理想天线的长度是半波长 平时说的四分之一波长天线 实际上需要考虑 地 才能构成完整的天线 也就是我们常说的 非平衡天线 天线本身只是天线的一部分 天线长度是波长的四分之一 波长 光速c 频率f 1 如 5GHz wifi天线长度计算
  • 二进制转换

    我们平时使用的十进制 十进制转二进制 整数情况 11表示成二进制数 11 2 5 余 1 5 2 2 余 1 2 2 1 余 0 1 2 0 余 1 得0结束 11的二进制表示为 从下往上 1011 小数情况 0 9表示成二进制数 0 9
  • DLNA协议

    一 DLNA协议 多屏互动技术的核心 dlna协议 利用网络技术 有线或者无线 将各种各样的设备互联 通过标准的协议 主流的是dlna协议 进行数据交互 实现媒体资源共享 比如 生活中常用的视频投屏技术 dlna协议提供的是设备互联资源共享
  • 2022 第十三届蓝桥杯大赛软件赛决赛, 国赛,C/C++ 大学B组题解

    2022 第十三届蓝桥杯大赛软件赛决赛 国赛 C C 大学B组题解 文章目录 第1题 2022 5分 第2题 钟表 5分 第3题 卡牌 10分 第4题 最大数字 10分 第5题 出差 15分 第6题 费用报销 15分 第7题 故障 20分
  • 【进程间通信 之 通信的建立】

    目录 前言 进程间通信的目的 进程间通信的方式 管道 1 匿名管道 简单示例1 消息传输 五个特性 四种场景 简单示例2 进程控制 对管道的深入理解 2 命名管道 简单示例3 不相关进程间通信 system V 共享内存 简单示例4 通知事
  • loadrunner11目标场景

    目标场景 设置一个运行目标 通过Controller的自动加载功能进行自动化负载 如果测试的结果达到目标 说明系统的性能符合测试目标 否则就提示无法达到目标 编辑目标场景 目标类型有5种
  • python-图像边缘化处理

    本文由本人原创 仅作为自己的学习记录 主要利用Sobel 用作边缘检测 它是一离散性差分算子 用来运算图像亮度函数的灰度值 在图像的任何一点使用此算子 将会产生对应的灰度矢量或是其法矢量 Sobel边缘检测通常带有方向性 可以只检测竖直边缘
  • 【Linux0.11 源码历险记 2】《保护模式》

    继续跟着stup s 来看 lidt idt 48 load idt with 0 0 lgdt gdt 48 load gdt with whatever appropriate idt 48 word 0 idt limit 0 wor
  • 【Unity】 2D 游戏 库存模块实现

    库存模块主要参考了 youtube 上的视频 BMo 的 Flexible INVENTORY SYSTEM in Unity with Events and Scriptable Objects 和 Simple Inventory UI