前言:

项目源码上传GitHub:Unity-knapsack

背包系统:

  • 背包系统是游戏中非常重要的元素,几乎每一款游戏都有背包系统,我们使用背包系统可以完成装备栏的数据管理,商店物体的数据管理等等一系列的功能,如何做好一个背包系统呢,来学习把!

本次案例是基于数据本地存储的方式设计的背包系统,首先在数据管理方面,使用ScriptableObject类来实创建数据仓库,可以保存在游戏系统中,重新开始后依旧可以再次加载出来该数据:

前期规划:

为了使得游戏逻辑简洁清晰,可以使用MVC框架完成背包系统的设计,来尽量降低数据、逻辑耦合,提升不同的模块的独立性。便于程序的扩展和维护

什么是MVC:

  • M即Model(模型)
  • V即View(视图)
  • C即Control(控制)

而使用MVC的目的就是将M和V进行代码分离,便于逻辑区分

背包系统要实现的是,存在于背包内的物体可以显示在UI上,而背包内物体是动态变化的(减少或增加),所以UI可以根据这种变化而进行动态的变化,所以我们划分为如下区块:

  • 首先是M(业务模型):我们通过ScriptableObject类创建数据仓库来构造业务模型
  • 然后是V(用户界面):通过UI界面显示背包内所有物体
  • 最后是C(逻辑控制):获取数据仓库模型并转换到UI界面

UI端:

一、UI搭建

创建一个Panel作为背包系统中所有物体的父元素,并为其更换一个背景图片,这样可以使得物体有容纳的空间,能够使得物体更加序列化,更规整:

接下来需要对MainGrid添加组件Grid Layout Group组件,该组件的作用是可以是的子元素按照一定的格式排列在父元素中,这样就很容易使我们动态的显示出不定长的UI元素同时保持规整的效果,

关于Grid Layout Group的具体作用和使用方式可以查看之前文章:

为了使得添加的子物体可以完美的匹配的每一个格子中,需要调整Grid Layout Group组件的相关参数,而其中主要是paddingCall SizeSpacing三个元素,这三个参数调整的具体内容为:

  • Padding:类似网页设计内边距
  • Cell Size:组中每个布局元素要使用的大小
  • Spacing:布局之间的元素间距

最终达到这样的效果,每添加一个图片子元素,则向后排列一位,这样可以完美的显示在格子之中:



二、格子元素预制体制作

为了使得背包内的物体可以在UI中显示出来,需要将这些物体做成对应的UI元素,而UI元素则有两个关键点,图标和数量,为了实现这样 的效果,首先创建一个Image命名为GridPrefab作为图标,然后为其添加Text子元素作为物体数量显示框:

在游戏中,我们只需要为GridPrefabImage组件中的Source Image添加图片,即可实现最终的显示效果,制作完成后将GridPrefab拖入到Assets中即可创建一个预制体

由于我们需要在使用预制体时,需要修改其一些信息,比如说Image组件中的Source Image添加图片和子元素Text中的显示内容(物体个数),为了方便更改,使用一个脚本整合这些需要修改地方,方便其他脚本调用,脚本命名为Grid,并挂载到GridPrefab上:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; public class Grid : MonoBehaviour
{
public Image gridImage;
public Text girdNum;
}

挂载完脚本后,将组件或元素拖入:

数据端:

一,基于ScriptableObject本地保存数据

ScriptableObject可以用来创建不需要挂载到场景物体上的脚本,这样可以将游戏数据保存于本地,不会在每次游戏结束时重置数据,我们可以利用这一点来设计出数据的存储仓库

关于ScriptableObject的一些细节可以查看该文章:

创建一个存储物体数据的仓库,我们可以使用CreateAssetMenu来完成创建AssetMenu 的方法,这样就可以使用Create来在资源中创建定义的仓库

具体操作流程:

1,物体数据仓库创建:

首先创建一个类Item(用来创建一个物体(比如说一件武器)数据存储仓库)继承于ScriptableObject,既然是背包物体,需要存储的数据主要是UI显示需要的图标图片,物体名称和物体数量,以及物体的详细信息(本案例用不到)等:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; //实现可以在Asset窗口创建资源文件的方法
[CreateAssetMenu(fileName ="New Item",menuName ="Bag/New Item")] public class Item : ScriptableObject
{
//物体名、需要在UI中显示的图片、持有物体的数量、物体信息的描述
public string itemName;
public Sprite itemImage;
public int itemNum;
[TextArea] //改变输入框格式,提示输入框容量
public string itemInfo;
}

完成脚本后保存,在Asset面板右键创建,即可看到New Item选项,点击可以创建一个物体数据仓库,并且可以填写其中的信息,也可以通过脚本来修改信息,并且是永久保存的

  • 创建一个数据仓库:

  • 修改数据仓库信息:

2,背包数据仓库的创建

创建该仓库是为了存储背包中究竟有哪些物体,也就是有哪些Item,创建一个类命名为MainItem同样继承于ScriptableObject,并定义一个列表来背包中所有物体:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; [CreateAssetMenu(fileName ="New MainItem",menuName ="Bag/New MainItem")]
public class MainItem : ScriptableObject
{
public List<Item> itemList=new List<Item>();
}

创建操作流程:

  • 在资源面板点击后创建一个MainItem背包物体管理仓库,用来存放背包中的Item数据:

  • 查看创建的数据仓库,可以发现是一个列表管理资源,我们可以将一系列的Item资源拖入其中,这样就可以在背包中保存所有物品的信息:

游戏场景端:

1,搭建场景

Sence面板搭建一个简单的场景,并添加一个Capsule作为玩家控制角色,然后添加一个Cube作为场景中可以捡拾的物体,当玩家捡拾到该物体后,就会在背包UI中显示出来

首先对于,玩家控制角色,为其添加Rigidbody组件并为其添加脚本PlayerCtrl来控制其移动和背包UI的显示和隐藏:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class PlayerCtrl : MonoBehaviour
{
Vector3 v3;
float speed = 2f;
public GameObject myBagUI;
private bool isPlay; // Update is called once per frame
void Update()
{
//控制角色移动
float x = Input.GetAxis("Horizontal");
float y = Input.GetAxis("Vertical");
v3 = new Vector3(x, 0, y);
transform.Translate(v3*speed*Time.deltaTime); //控制UI显示或隐藏
if(Input.GetKeyDown(KeyCode.B))
{
isPlay = !isPlay;
myBagUI.SetActive(isPlay);
}
}
}

完成脚本后挂载到Player上,并将UI元素MyBag拖入:

2,场景中物体的设计

接下来要完成在游戏场景中的物体代码设置,为其添加脚本,在玩家碰撞到该物体时,将该物体对应的数据仓库Item添加到背包中的数据仓库中,如果背包中的数据仓库已经存在该物体,则将对应物体的数据仓库中的持有数量加一

为了方便理解,可以将其看作为吃鸡游戏中地面上子弹,当玩家捡拾后,对应的角色背包中就会出现子弹,如果背包中有之前捡拾的子弹,则背包中子弹数量会增加,本案例使用Cube来代替

首先为Cube创建一个脚本命名为ScenesItem来检测碰撞,并获取该物体的数据仓库将其添加到背包数据仓库中:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class ScenesItem : MonoBehaviour
{
//物体的数据仓库
public Item item;
//背包的数据仓库
public MainItem mainItem;
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.name=="Player")
{ if(!mainItem.itemList.Contains(item))
{
mainItem.itemList.Add(item);
}
item.itemNum += 1;
Destroy(this.gameObject);
}
}
}

完成后,将脚本挂载到物体上,并拖入于该物体对应的物体数据仓库和背包数据仓库:

将数据显示于UI:

通过读取数据仓库的信息,将背包的数据转换到UI元素中显示出来

首先通过读取背包数据仓库中的列表信息,读取到列表中所有物体数据仓库中的信息,获取到背包仓库中存在的物体图片和数量,并显示在UI上面,创建一个脚本命名为BagDisplayUI并挂载到Canvas上,为了确保该类只有一个实例,用单例模式来实现该需求

public class BagDisplayUI : MonoBehaviour
{
static BagDisplayUI bagDisplayUI;
private void Awake()
{
if(bagDisplayUI!=null)
{
Destroy(this);
}
bagDisplayUI = this; }
}

然后定义一些我们所需要的变量,首先需要是背包数据仓库,需要通过该仓库遍历到背包中物体的数据仓库,然后就是之前做好的显示每一个物体图标和数量的UI预制体,第三个则是用来作为添加每一个UI预制体的父物体

    //背包数据仓库、格子中物体预制体、和UI中显示物体元素的父元素
public MainItem mainItem;
public Grid gridPrefab;
public GameObject myBag;

定义完后,将需要的变量拖入:

接下来编辑该脚本,实现在UI显示背包物体的功能:

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class BagDisplayUI : MonoBehaviour
{
//单例模式
static BagDisplayUI bagDisplayUI;
private void Awake()
{
if(bagDisplayUI!=null)
{
Destroy(this); }
bagDisplayUI = this; }
//每次游戏启动前,动态的更新背包UI元素
private void OnEnable()
{
updateItemToUI();
}
//背包数据仓库、格子中物体预制体、和UI中显示物体元素的父元素
public MainItem mainItem;
public Grid gridPrefab;
public GameObject myBag; /// <summary>
/// 在UI中将一个物体的数据仓库显示出来
/// </summary>
/// <param name="item"></param>
public static void insertItemToUI(Item item)
{ Grid grid = Instantiate(bagDisplayUI.gridPrefab, bagDisplayUI.myBag.transform);
grid.gridImage.sprite = item.itemImage;
grid.girdNum.text = item.itemNum.ToString(); } /// <summary>
/// 将背包数据仓库中所有物体显示在UI上
/// </summary>
public static void updateItemToUI()
{
for (int i = 0; i < bagDisplayUI.myBag.transform.childCount; i++)
{
Destroy(bagDisplayUI.myBag.transform.GetChild(i).gameObject);
}
for (int i = 0; i < bagDisplayUI.mainItem.itemList.Count; i++)
{
insertItemToUI(bagDisplayUI.mainItem.itemList[i]);
}
}
}

同时在每一个物体的碰撞检测脚本上调用更新UI元素的方法,这是为了在Player碰撞到物体时,背包数据仓库发生变化时,可以在UI元素上也同步变化:

总结:

通过MVC框架思想来设计背包系统,尽量保证数据、视图的分离,通过控制端来连接两者,提升独立性

而对于背包系统的主体设计,主要在于数据的保存和读取,本次案例我们采用的是本地存储的方式。在网络游戏中,如果采用数据保存在服务器的方式,可以通过读取网络发送过来的Json数据等方式来实现在UI界面的显示

无论是本地还是服务器,转换为UI界面的展示效果方法基本相同,主要是对数据的处理方式的差异

Unity 背包系统的完整实现(基于MVC框架思想)的更多相关文章

  1. Spring MVC -- MVC设计模式(演示4个基于MVC框架的案例)

    对于简单的Java Web项目,我们的项目仅仅包含几个jsp页面,由于项目比较小,我们通常可以通过链接方式进行jsp页面间的跳转. 但是如果是一个中型或者大型的项目,上面那种方式就会带来许多维护困难, ...

  2. Asp.net Core基于MVC框架实现PostgreSQL操作

    简单介绍 Asp.net Core最大的价值在于跨平台.跨平台.跨平台.重要的事情说三遍.但是目前毕竟是在开发初期,虽然推出了1.0.0 正式版,但是其实好多功能还没有完善.比方说编译时的一些文件编码 ...

  3. struts2.1笔记01:MVC框架思想浅层理解

      1. Struts 1是全世界第一个发布的MVC框架: 它由Craig McClanahan在2001年发布,该框架一经推出,就得到了世界上Java Web开发者的拥护,经过长达6年时间的锤炼,S ...

  4. 基于MVC框架的JavaWeb网站开发demo项目(JSP+Servlet+JavaBean)

    1.环境配置 Windows10+Eclipse2020+jdk8+Tomcat9+MySQL8+Navicat10 2.需求分析 ①用户登录注册注销(查找.增加) ②显示用户列表(查找) ③显示用户 ...

  5. 基于“MVC”框架集设计模式,开发用户管理系统!

    MVC----(Model View Controller)设计模型: M:表示业务数据和业务规则.包括DAO(beans).DBHelper(DBHelper),用于封装数据库连接,业务数据库处理. ...

  6. 基于MVC框架Aspose.Words打印到Word中写法

    控件bin文件下载地址:https://download.csdn.net/download/u012949335/10610726 //前端打印写法 @{ ViewBag.Title = " ...

  7. 基于MVC框架layui分页控件实现前端分页信息写法

    详细链接:https://shop499704308.taobao.com/?spm=a1z38n.10677092.card.11.594c1debsAGeak@{ ViewBag.Title = ...

  8. MVC系列——MVC源码学习:打造自己的MVC框架(三:自定义路由规则)

    前言:上篇介绍了下自己的MVC框架前两个版本,经过两天的整理,版本三基本已经完成,今天还是发出来供大家参考和学习.虽然微软的Routing功能已经非常强大,完全没有必要再“重复造轮子”了,但博主还是觉 ...

  9. 自定义MVC框架

    我们在学习自定义MVC框架的时候常常会听到Model1 ,Model2和MVC.那么什么是Model1 什么是Model2什么又是MVC呢? 什么是Model1? Model1就是一种纯jsp开发技术 ...

随机推荐

  1. ES2020 All in One

    ES2020 All in One ES2020 new features / ES11 ES2020 中的10个新功能 1. BigInt BigInt是JavaScript中最令人期待的功能之一, ...

  2. js 的 ArrayBuffer 和 dataView

    arrayBuffer文档 一个十六进制代表4位,0xF = 1111,0xFF = 1111 1111,八位是1字节,所以通常用两个16进制代表1字节. 假如我申请一个8字节的内存空间,然后初始化为 ...

  3. 【Android初级】如何实现一个有动画效果的自定义下拉菜单

    我们在购物APP里面设置收货地址时,都会有让我们选择省份及城市的下拉菜单项.今天我将使用Android原生的 Spinner 控件来实现一个自定义的下拉菜单功能,并配上一个透明渐变动画效果. 要实现的 ...

  4. Matplotlib 图表绘制工具学习笔记

    import numpy as np import matplotlib.pyplot as plt import pandas as pd arr1 = np.random.rand(10)#一维数 ...

  5. 微信小程序:解决小程序中有些格式如webpiPhone手机暂不支持的问题

    问题:小程序中有些格式是iPhone手机暂不支持的,如goods_introduce中的webp格式,在小程序的模拟器中是可以正常显示webp格式的,但是一旦你做真机调试,很可能某些iPhone手机是 ...

  6. Linux系统管理--part(1)

    Linux系统管理--part(1) Linux系统安装完毕,需要对Linux系统进行管理和维护,让Linux服务器能够真正英语于企业中 Linux运维的三个步骤安装.调试.启动 通过本篇文章,将学习 ...

  7. spring boot的 yml和properties的对比

    Spring Boot 虽然做了大量的工作来简化配置,但其配置依然是相当的复杂!支持的外部配置方式就有很多种,笔者没有去统计,也许是为了灵活使用吧.   application.yml 和 appli ...

  8. 大数据开发-Spark-Streaming处理数据到mysql

    前面一篇讲到streamin读取kafka数据加工处理后写到kafka数据,大数据开发-Spark-开发Streaming处理数据 && 写入Kafka是针对比如推荐领域,实时标签等场 ...

  9. 后端程序员之路 58、go wlog

    daviddengcn/go-colortext: Change the color of console text.https://github.com/daviddengcn/go-colorte ...

  10. 树莓派4B安装官方Ubuntu20 Server版(64位)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...