【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱1(附带项目源码)

效果演示

在这里插入图片描述

文章目录

  • 效果演示
  • 系列目录
  • 前言
  • 人物和视角基本控制
  • 简单的背包系统和物品交互
    • 绘制背包UI
    • 脚本控制
  • 源码
  • 完结

系列目录

前言

欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第25篇中,我们将探索如何用unity制作一个3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱等功能,我会附带项目源码,以便你更好理解它。

人物和视角基本控制

具体可以看我这篇文章:
【unity小技巧】unity最完美的CharacterController 3d角色控制器,实现移动、跳跃、下蹲、奔跑、上下坡、物理碰撞效果,复制粘贴即用

这里我就直接贴出代码了

人物移动控制

[RequireComponent(typeof(CharacterController))]
public class MovementScript : MonoBehaviour
{[Tooltip("角色控制器")] public CharacterController characterController;[Tooltip("重力加速度")] private float Gravity = -19.8f;private float horizontal;private float vertical;[Header("移动")][Tooltip("角色行走的速度")] public float walkSpeed = 6f;[Tooltip("角色奔跑的速度")] public float runSpeed = 9f;[Tooltip("角色移动的方向")] private Vector3 moveDirection;[Tooltip("当前速度")] private float speed;[Tooltip("是否奔跑")] private bool isRun;[Header("地面检测")][Tooltip("是否在地面")] private bool isGround;[Header("跳跃")][Tooltip("角色跳跃的高度")] public float jumpHeight = 8f;private float _verticalVelocity;void Start(){speed = walkSpeed;}void Update(){horizontal = Input.GetAxis("Horizontal");vertical = Input.GetAxis("Vertical");//地面检测isGround = characterController.isGrounded;SetSpeed();SetRun();SetMove();SetJump();}//速度设置void SetSpeed(){if (isRun){speed = runSpeed;}else{speed = walkSpeed;}}//控制奔跑void SetRun(){if (Input.GetKey(KeyCode.LeftShift)){isRun = true;}else{isRun = false;}}//控制移动void SetMove(){moveDirection = transform.right * horizontal + transform.forward * vertical; // 计算移动方向moveDirection = moveDirection.normalized; // 归一化移动方向,避免斜向移动速度过快  }//控制跳跃void SetJump(){bool jump = Input.GetButtonDown("Jump");if (isGround){// 在着地时阻止垂直速度无限下降if (_verticalVelocity < 0.0f){_verticalVelocity = -2f;}if (jump){_verticalVelocity = jumpHeight;}}else{//随时间施加重力_verticalVelocity += Gravity * Time.deltaTime;}characterController.Move(moveDirection * speed * Time.deltaTime + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);}
}

视角控制

public class MouseLook : MonoBehaviour
{// 鼠标灵敏度public float mouseSensitivity = 500f;// 玩家的身体Transform组件,用于旋转public Transform playerBody;// x轴的旋转角度float xRotation = 0f;void Start(){// 锁定光标到屏幕中心,并隐藏光标Cursor.lockState = CursorLockMode.Locked;}// Update在每一帧调用void Update(){// 执行自由视角查看功能FreeLook();}// 自由视角查看功能的实现void FreeLook(){// 获取鼠标X轴和Y轴的移动量,乘以灵敏度和时间,得到平滑的移动速率float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;//限制旋转角度在-90到90度之间,防止过度翻转xRotation = Mathf.Clamp(xRotation, -90f, 90f);// 累计x轴上的旋转量xRotation -= mouseY;// 应用摄像头的x轴旋转transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);// 应用玩家身体的y轴旋转playerBody.Rotate(Vector3.up * mouseX);}
}

效果
在这里插入图片描述

简单的背包系统和物品交互

对UI知识还不太懂的小伙伴可以看这篇基础篇文件:【Unity游戏开发教程】零基础带你从小白到超神30——UI组件和布局的使用

绘制背包UI

物品插槽背景框
在这里插入图片描述
物品插槽,可以把物品插槽做出预制体,后面好修改
在这里插入图片描述

准星图像和文本
在这里插入图片描述

脚本控制

物品信息脚本

public class Item : MonoBehaviour
{public new string name = "New Item";//物品名称[TextArea]public string description = "New Description";//物品描述public Sprite icon;//物品图标public int currentQuantity = 1;//物品当前数量public int maxQuantity = 16;//物品最大堆叠数量
}

背包插槽脚本

public class Slot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{public bool hovered; // 鼠标是否悬停在该槽位上的标志private Item heldItem; // 当前槽位持有的物品private Color opaque = new Color(1, 1, 1, 1); // 不透明颜色private Color transparent = new Color(1, 1, 1, 0); // 透明颜色private Image thisSlotImage; // 该槽位的图像组件public TMP_Text thisSlotQuantityText; // 用于显示物品数量的文本组件// 初始化槽位public void initialiseSlot(){thisSlotImage = gameObject.GetComponent<Image>();thisSlotQuantityText = transform.GetChild(0).GetComponent<TMP_Text>();thisSlotImage.sprite = null;thisSlotImage.color = transparent;setItem(null);}// 设置槽位中的物品public void setItem(Item item){heldItem = item;if (item != null){thisSlotImage.sprite = heldItem.icon;thisSlotImage.color = opaque;updateData();}else {thisSlotImage.sprite = null;thisSlotImage.color = transparent;updateData();}}// 获取当前槽位持有的物品public Item getItem(){return heldItem;}// 当前槽位是否持有的物品public bool hasItem(){return heldItem ? true : false;}// 更新槽位显示的数据public void updateData(){if (heldItem != null) // 如果持有物品thisSlotQuantityText.text = heldItem.currentQuantity.ToString(); // 显示物品的数量else // 如果不持有物品thisSlotQuantityText.text = "";}// 当鼠标指针进入槽位区域时调用public void OnPointerEnter(PointerEventData pointerEventData){hovered = true;}// 当鼠标指针离开槽位区域时调用public void OnPointerExit(PointerEventData pointerEventData){hovered = false;}
}

库存系统脚本

public class Inventory : MonoBehaviour
{[Header("UI")]public GameObject inventory; // 游戏中的背包界面public List<Slot> allInventorySlots = new List<Slot>(); // 所有的槽位列表public List<Slot> inventorySloats = new List<Slot>();//背包的的槽位列表public Image crosshair; // 准星图像public TMP_Text itemHoverText; // 当中心悬停在物品上时显示物品名称的文本[Header("射线检测")]public float raycastDistance = 5f; // 射线检测的距离public LayerMask itemLayer; // 射线检测的目标层,用于识别物品public void Start(){toggleInventory(false); // 初始时关闭背包界面//合并槽位allInventorySlots.AddRange(inventorySloats);foreach (Slot uiSlot in allInventorySlots) // 初始化所有槽位{uiSlot.initialiseSlot();}}public void Update(){itemRaycast(Input.GetKeyDown(KeyCode.E)); // 显示物品名称和按E拾取物品if (Input.GetKeyDown(KeyCode.Tab)) // 按下tab键切换背包界面的显示状态toggleInventory(!inventory.activeInHierarchy);}private void itemRaycast(bool hasClicked = false){itemHoverText.text = ""; // 默认不显示任何物品名称Ray ray = Camera.main.ScreenPointToRay(crosshair.transform.position); // 从准星位置发出射线RaycastHit hit;if (Physics.Raycast(ray, out hit, raycastDistance, itemLayer)) // 如果射线检测到物品层的对象{if (hit.collider != null){if (hasClicked) // 如果是按了操作,尝试捡起物品{Item newItem = hit.collider.GetComponent<Item>();if (newItem){addItemToInventory(newItem); // 将物品添加到背包中}}else // 否则,仅获取物品名称以显示{Item newItem = hit.collider.GetComponent<Item>();if (newItem){itemHoverText.text = newItem.name; // 显示物品名称}}}}}//将物品添加到背包中private void addItemToInventory(Item itemToAdd){int leftoverQuantity = itemToAdd.currentQuantity; // 剩余需要添加到背包的物品数量Slot openSlot = null; // 记录一个空的槽位for (int i = 0; i < allInventorySlots.Count; i++) // 遍历所有槽位{Item heldItem = allInventorySlots[i].getItem();if (heldItem != null && itemToAdd.name == heldItem.name) // 如果槽位中有相同名称的物品{int freeSpaceInSlot = heldItem.maxQuantity - heldItem.currentQuantity; // 计算槽位中的剩余空间if (freeSpaceInSlot >= leftoverQuantity) // 如果剩余空间足够{heldItem.currentQuantity += leftoverQuantity; // 添加物品到该槽位Destroy(itemToAdd.gameObject); // 销毁场景中的物品对象allInventorySlots[i].updateData(); // 更新槽位显示的数据return;}else // 如果剩余空间不足{heldItem.currentQuantity = heldItem.maxQuantity; // 填满当前槽位leftoverQuantity -= freeSpaceInSlot; // 更新剩余需要添加的物品数量}}else if (heldItem == null) // 如果槽位为空{if (!openSlot)openSlot = allInventorySlots[i]; // 记录第一个空槽位}allInventorySlots[i].updateData(); // 更新槽位显示的数据}if (leftoverQuantity > 0 && openSlot) // 如果还有剩余物品且找到了空槽位{openSlot.setItem(itemToAdd); // 将物品添加到空槽位itemToAdd.currentQuantity = leftoverQuantity; // 更新物品的数量itemToAdd.gameObject.SetActive(false); // 隐藏场景中的物品对象}else{itemToAdd.currentQuantity = leftoverQuantity; // 更新物品的数量}}private void toggleInventory(bool enable){//关闭背包时,关闭所有鼠标悬停在该槽位上的标志if (!enable){foreach (Slot curSlot in allInventorySlots){curSlot.hovered = false;}}inventory.SetActive(enable); // 根据参数显示或隐藏背包界面Cursor.lockState = enable ? CursorLockMode.None : CursorLockMode.Locked; // 根据背包界面的状态锁定或解锁鼠标指针Cursor.visible = enable; // 设置鼠标指针的可见性// 禁用或启用相机的旋转控制Camera.main.GetComponent<MouseLook>().enabled = !enable;}
}

物品挂载Item脚本,配置参数,记得添加碰撞体并修改图层为Item
在这里插入图片描述
背包插槽挂载Slot脚本
在这里插入图片描述
角色上挂载Inventory脚本
在这里插入图片描述

拾取
在这里插入图片描述

源码

源码不出意外的话我会放在最后一节

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

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

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

相关文章

【实习】深信服防火墙网络安全生产实习

一、实习概况 1.1实习目的 1.掌握防火墙规则的作用2.掌握代理上网功能的作用3.掌握端口映射功能的作用 1.2实习任务 1.防火墙的WEB控制台 2.需要在防火墙上配置dnat …

C语言第二十二弹---指针(六)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1. 回调函数是什么&#xff1f; 2、qsort使用举例 2.1、使用qsort函数排序整型数据 2.2 使用qsort排序结构体数据 3、qsort函数的模拟实现 总结 1. 回…

FFmpeg中的Color颜色参数解析、转码和HDR

前言 视频中帧的颜色信息非常重要&#xff0c;表示着编码时用到的标准&#xff0c;意味着解码时也要对应上&#xff0c;或者要使用正确的转换函数&#xff0c;否则就会带来色差问题。 关于FFmpeg中的颜色参数&#xff0c;有下边几个重要的结构体&#xff1a; 颜色参数相关的结…

C++ //练习 5.5 写一段自己的程序,使用if else语句实现把数字成绩转换成字母成绩的要求。

C Primer&#xff08;第5版&#xff09; 练习 5.5 练习 5.5 写一段自己的程序&#xff0c;使用if else语句实现把数字成绩转换成字母成绩的要求。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 代码块 /***************************…

Linux操作系统基础(七):Linux常见命令(二)

文章目录 Linux常见命令&#xff08;二&#xff09; 一、kill命令 二、ifconfig命令 三、clear命令 四、重启与关机命令 五、which命令 六、hostname命令 七、grep命令 八、|管道 九、useradd命令 十、userdel命令 十一、tar命令 十二、su命令 十三、ps命令 Linu…

腾讯云4核8G服务器多少钱?2024精准报价

腾讯云4核8G服务器S5和轻量应用服务器优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;标准型SA2服务器1444.8元一年&#xff0c;轻量应用服务器4核8G12M带宽一…

C语言-----自定义类型-----结构体枚举联合

结构体和数组一样&#xff0c;都是一群数据的集合&#xff0c;不同的是数组当中的数据是相同的类型&#xff0c;但是结构体中的数据类型可以不相同&#xff0c;结构体里的成员叫做成员变量 结构体类型是C语言里面的一种自定义类型&#xff0c;我们前面已经了解到过int,char,fl…

ChatGPT高效提问—prompt常见用法(续篇九)

ChatGPT高效提问—prompt常见用法(续篇九) ​ 如何准确地向大型语言模型提出问题,使其更好地理解我们的意图,从而得到期望的答案呢?编写有效的prompt的技巧,精心设计的prompt,获得期望的的答案。 1.1 增加条件 ​ 在各种prompt技巧中,增加条件是最常用的。在prompt中…

【漏洞复现】狮子鱼CMS某SQL注入漏洞01

Nx01 产品简介 狮子鱼CMS&#xff08;Content Management System&#xff09;是一种网站管理系统&#xff0c;它旨在帮助用户更轻松地创建和管理网站。该系统拥有用户友好的界面和丰富的功能&#xff0c;包括页面管理、博客、新闻、产品展示等。通过简单直观的管理界面&#xf…

2024年 前端JavaScript入门到精通 第一天

主要讲解JavaScript核心知识&#xff0c;包含最新ES6语法&#xff0c;从基础到API再到高级。让你一边学习一边练习&#xff0c;重点知识及时实践&#xff0c;同时每天安排大量作业&#xff0c;加深记忆&#xff0c;巩固学习成果。 1.1 基本软件与准备工作 1.2 JavaScript 案例 …

6 scala-面向对象编程基础

Scala 跟 Java 一样&#xff0c;是一门面向对象编程的语言&#xff0c;有类和对象的概念。 1 类与对象 与 Java 一样&#xff0c;Scala 也是通过关键字 class 来定义类&#xff0c;使用关键字 new 创建对象。 要运行我们编写的代码&#xff0c;同样像 Java 一样&#xff0c;…

力扣面试题 17.04. 消失的数字(求和,位运算)

Problem: 面试题 17.04. 消失的数字 文章目录 题目描述思路复杂度Code 题目描述 思路 思路1:求和 先求取1-n的数字和,再减去数组中所有元素的和即为缺失数 思路2:位运算 我们利用异或运算的特性:相同位为0,不同位为1;0与仍何数异或后得到仍何数,即我们先另一个变量(初始为0)与…

1Maven分模块设计与开发

目录 1.1 介绍 1.2 实践 1.2.1模块进行拆分 1.3 总结 首先&#xff1a;Maven 是一款构建和管理 Java 项目的工具 1.1 介绍 所谓分模块设计&#xff0c;顾名思义指的就是我们在设计一个 Java 项目的时候&#xff0c;将一个 Java 项目拆分成多个模块进行开发。 1). 未分模…

SpringCloud-高级篇(十九)

我们已经学过使用 SpringAMQP去收和发消息&#xff0c;但是发和收消息是只是MQ最基本的功能了&#xff0c;在收发消息的过程中&#xff0c;会有很多的问题需要去解决&#xff0c;下面需要学习rabbitMQ的高级特性去解决 死信交换机&#xff1a;这个可以帮助我们实现消息的延迟的…

深入了解Elasticsearch索引生命周期管理

在今天的数据驱动世界中&#xff0c;Elasticsearch因其强大的搜索和分析能力而受到许多企业和开发者的青睐。随着数据量的不断增长&#xff0c;如何高效地管理这些数据成为了一个挑战。Elasticsearch索引生命周期管理&#xff08;ILM&#xff09;就是为解决这一问题而设计的。本…

数据库管理-第14期 Oracle Vector DB AI-01(20240210)

数据库管理149期 2024-02-10 数据库管理-第149期 Oracle Vector DB & AI-01&#xff08;20240210&#xff09;1 机器学习2 向量3 向量嵌入4 向量检索5 向量数据库5 专用向量数据库的问题总结 数据库管理-第149期 Oracle Vector DB & AI-01&#xff08;20240210&#xf…

车载电子电器架构 —— 电子电气系统车载功能子系统

车载电子电器架构 —— 电子电气系统车载功能子系统 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 本就是小人物&#xff0c;输了就是输了&#xff0c…

290. Word Pattern(单词规律)

题目描述 给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。 提示: 1 < pattern.length < 300 pa…

蓝桥杯每日一解

可以看看a的ascii码为6532 而A为ascii码为65&#xff0c;大小写相差32位 #include <iostream>using namespace std; int main(){int n;cin >> n;char a;for (int i 1;i<n;i){while(scanf("%c",&a) ! EOF){//无限输入直到输入到空格if(a a || a …

【制作100个unity游戏之23】实现类似七日杀、森林一样的生存游戏10(附项目源码)

本节最终效果演示 文章目录 本节最终效果演示系列目录前言快捷栏绘制UI代码控制快捷列表信息 源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列&#xff01;本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第23篇中&#xff0c;我们将探索如何制作…