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

库存模块主要参考了 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 updatevoid Start(){}// Update is called once per framevoid 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 updatepublic Image icon;public TextMeshProUGUI displayCount;public InventoryItem inventoryItem;void Start(){icon.enabled = false;displayCount.enabled = false;}// Update is called once per framevoid 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做一个遍历查询,将相同的物品进行归并,如果没有的话,就会找到一个空格子,将物品放进去。

效果展示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/74429.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx详解 第五部分:Ngnix反向代理(负载均衡 动静分离 缓存 透传 )

Part 5 一、正向代理与反向代理1.1 正向代理简介1.2 反向代理简介 二、配置反向代理2.1 反向代理配置参数2.1.1 proxy_pass2.1.2 其余参数 2.2 配置实例:反向代理单台web服务器2.3 代理转发 三、反向代理实现动静分离四、缓存功能五、反向代理客户端的IP透传5.1 原理概述5.2 一…

谁在为网络安全制造标尺?

“我们想帮助企业往后退一步&#xff0c;去全局的看一下自己的安全能力建设水平如何&#xff0c;以及在当下的阶段最应该做的安全建设是什么&#xff1f; ” 度量&#xff0c;对应的是更清晰的认知。而对企业安全而言&#xff0c;这种认知&#xff0c;也更在成为一把新的标尺…

Redis带你深入学习数据类型set

目录 1、set 2、set相关命令 2.1、添加元素 sadd 2.2、获取元素 smembers 2.3、判断元素是否存在 sismember 2.4、获取set中元素数量 scard 2.5、删除元素spop、srem 2.6、移动元素smove 2.7、集合中相关命令&#xff1a;sinter、sinterstore、sunion、sunionstore、s…

CSS:屏幕正中间有个元素A,元素A中有文字A,随着屏幕宽度的增加

始终需要满足以下条件&#xff1a; A元素垂直居中于屏幕***&#xff1b;A元素距离屏幕左右边距各10px&#xff1b;A元素里面的文字”A”的font-size:20px&#xff1b;水平垂直居中;A元素的高度始终是A元素宽度的50%; (如果搞不定可以实现为A元素的高度固定为200px;)请用 html及…

【Unity基础】3.脚本控制物体运动天空盒

【Unity基础】3.脚本控制物体运动&天空盒 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity基础系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;搭建开发环境 &#xff08;1&#xff09;下载visual studio 在我们下载unity编译器的时候&…

Microsoft Edge网页视频播放绿屏解决方法(B站)

一&#xff1a;问题&#xff0c;在B站观看视频时有绿色条纹 二&#xff1a;查找原因&#xff0c;未知 三&#xff1a;解决方法 三.1网页设置关闭硬件加速 三.2 点击视频播放下的 “小齿轮”&#xff0c;然后点击“更多播放设置” 把播放策略 “默认” 改为“AVC” 四&…

Tomcat配置域名和端口

Tomcat配置域名和端口 1.进入tomcat文件夹2. cd 到你的tomcat下3. 修改server.xml文件中监听端口4. 重启tomcat 1.进入tomcat文件夹 2. cd 到你的tomcat下 3. 修改server.xml文件中监听端口 继续修改server.xml中Host 4. 重启tomcat 进入bin ./shutdown.sh ./startup.sh …

etcd分布式存储

etcd分布式存储 etcd简介etcd下载安装etcd常用命令etcd配置参数etcd集群golang操作etcd

rrweb入门

rrweb 背景 rrweb 是 record and replay the web&#xff0c;是当下很流行的一个录制屏幕的开源库。与我们传统认知的录屏方式&#xff08;如 WebRTC&#xff09;不同的是&#xff0c;rrweb 录制的不是真正的视频流&#xff0c;而是一个记录页面 DOM 变化的 JSON 数组&#x…

【鲁棒电力系统状态估计】基于投影统计的电力系统状态估计的鲁棒GM估计器(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

SpringCloud Alibaba 入门到精通 - Nacos

SpringCloud Alibaba 常用组件 一、基础结构搭建1.父工程创建2.子工程创建 二、Nacos&#xff1a;注册中心1.服务端搭建2.注册中心-客户端搭建3.注册中心-管理页面4.注册中心-常用配置5.注册中心-核心功能总结 三、Nacos注册中心集成Load Balancer 、OpenFeign1.Nacos客户端集成…

一键部署k8s集群

前置动作 关闭防火墙 systemctl disable firewalld && systemctl stop firewalld 关闭SELinux sed -i s#SELINUXenforcing#SELINUXdisabled#g /etc/selinux/config && grep SELINUXdisabled /etc/selinux/config setenforce 0 getenforce 关闭swap # 关闭…

前端面试题JS篇(4)

浏览器缓存 浏览器缓存分为强缓存和协商缓存&#xff0c;当客户端请求某个资源时&#xff0c;获取缓存的流程如下&#xff1a; 先根据这个资源的一些 http header 判断它是否命中强缓存&#xff0c;如果命中&#xff0c;则直接从本地获取缓存资源&#xff0c;不会发请求到服务…

c语言练习44:深入理解strstr

深入理解strstr strstr作用展示&#xff1a; #include <stdio.h> #include <string.h> int main() {char str[] "This is a simple string";char* pch;pch strstr(str, "simple");/*strncpy(pch, "sample", 6);*/printf("%s…

Android逆向学习(一)vscode进行android逆向修改并重新打包

Android逆向学习&#xff08;一&#xff09;vscode进行android逆向修改并重新打包 写在前面 其实我不知道这个文章能不能写下去&#xff0c;其实我已经开了很多坑但是都没填上&#xff0c;现在专利也发出去了&#xff0c;就开始填坑了&#xff0c;本坑的主要内容是关于androi…

Scrum认证高级Scrum Master (A-CSM) 认证培训课程

课程简介 高级ScrumMaster (Advanced Certified ScrumMaster, A-CSM) 认证课程是国际Scrum联盟推出的进阶级Scrum认证课程&#xff0c;是Scrum Master通往专业级敏捷教练必经的学习路径。 在ScrumMaster&#xff08;CSM&#xff09;认证课程中&#xff0c;您学习到了Scrum的价…

Centos 6.5 升级到Centos7指导手册

一、背景 某业务系统因建设较早&#xff0c;使用的OS比较过时&#xff0c;还是centos6.5的系统&#xff0c;因国产化需要&#xff0c;需将该系统升级到BClinux 8.6&#xff0c;但官方显示不支持centos 6.x升级到8&#xff0c;需先将centos6.5升级到centos7的最新版&#xff0c…

华为OD机试 - 战场索敌 - 深度优先搜索dfs算法(Java 2023 B卷 100分)

目录 一、题目描述二、输入描述三、输出描述四、深度优先搜索dfs五、解题思路六、Java算法源码七、效果展示1、输入2、输出3、说明4、如果增加目标敌人数量K为55、来&#xff0c;上强度 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 一、题目描述 有一个大小是N*M…

RNA 36. SCI 文基于转录组数据识别CNV并可视化 (CaSpER)

转录组生信分析教程 桓峰基因公众号推出转录组分析教程&#xff0c;有需要生信的老师可以联系我们&#xff01;转录分析教程整理如下&#xff1a; RNA 1. 基因表达那些事--基于 GEO RNA 2. SCI文章中基于GEO的差异表达基因之 limma RNA 3. SCI 文章中基于T CGA 差异表达基因之 …

python28种极坐标绘图函数总结

文章目录 基础图误差线等高线polar场图polar统计图非结构坐标图 &#x1f4ca;python35种绘图函数总结&#xff0c;3D、统计、流场&#xff0c;实用性拉满 matplotlib中的画图函数&#xff0c;大部分情况下只要声明坐标映射是polar&#xff0c;就都可以画出对应的极坐标图。但…