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

本节最终效果演示

在这里插入图片描述

文章目录

  • 本节最终效果演示
  • 系列目录
  • 前言
  • 库存系统
    • 素材
    • 绘制简单的库存UI
    • 控制库存开关
    • 实现物品拖拽功能
    • 拾取物品
    • 添加更多物品
  • 源码
  • 完结

系列目录

前言

欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第23篇中,我们将探索如何制作一个类似于七日杀和森林的生存游戏。

本篇内容会比较多,我会分几篇来实现,感兴趣的可以关注一下,以免错过内容更新。

本节主要一个简单的库存系统,并完善之前的拾取功能。

库存系统

之前我们做过不少库存系统,这次就实现一个简单的,想要更复杂的可以看看我之前的文章:
【制作100个unity实战之3】从零手戳一个库存背包系统(附项目源码)
【Unity实战】最全面的库存系统(一)
【用unity实现100个游戏之13】复刻类泰瑞利亚生存建造游戏——包括建造系统和库存系统(附项目源码)
【制作100个unity实战之6】手戳一个库存系统,非常适合RPG、Roguelike和星露谷物语之类的游戏(附项目源码)
【unity实战】unity3D中的PRG库存系统和换装系统(附项目源码)

素材

https://assetstore.unity.com/packages/2d/gui/icons/gui-parts-159068
在这里插入图片描述

绘制简单的库存UI

在这里插入图片描述

控制库存开关

新增脚本InventorySystem,控制库存开关

public class InventorySystem : MonoBehaviour
{
    public static InventorySystem Instance { get; set; }
    // 引入UI界面对象
    public GameObject inventoryScreenUl;
    // 记录物品系统是否打开的状态
    [HideInInspector]
    public bool isOpen;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Tab))
        {
            // 打开物品系统界面
            inventoryScreenUl.SetActive(!isOpen);
            
            isOpen = !isOpen;

            // 设置鼠标锁定模式为无锁定,允许鼠标在界面上移动
            Cursor.lockState = isOpen ? CursorLockMode.None : CursorLockMode.Locked;
        }
    }
}

挂载配置脚本参数
在这里插入图片描述
打开库存,我们不希望人物视角还可以移动

修改MouseLook

void FreeLook()
{
    if(InventorySystem.Instance.isOpen) return;
    //。。。
}

效果
在这里插入图片描述

实现物品拖拽功能

新增DragDrop,控制物品拖拽

public class DragDrop : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
{
    // [SerializeField] private Canvas canvas;
    // 缓存RectTransform和CanvasGroup组件
    private RectTransform rectTransform;
    private CanvasGroup canvasGroup;
    // 定义公共静态变量,用于记录当前被拖拽的物体
    public static GameObject itemBeingDragged;
    // 记录物体拖拽前的起始位置和父级对象
    private Vector3 startPosition;
    private Transform startParent;

    private void Awake()
    {
        rectTransform = GetComponent<RectTransform>();
        canvasGroup = GetComponent<CanvasGroup>();
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        Debug.Log("OnBeginDrag");
        // 在物体开始被拖拽时,降低其不透明度来给用户反馈
        canvasGroup.alpha = 0.6f;
        // 防止射线检测到当前拖拽的物体,以避免与其他UI元素冲突
        canvasGroup.blocksRaycasts = false;
        // 记录物体拖拽前的起始位置和父级对象
        startPosition = transform.position;
        startParent = transform.parent;
        // 将物体从原有的父级对象移动到画布下,以便它始终在可见范围内
        transform.SetParent(transform.root);
        // 记录当前被拖拽的物体
        itemBeingDragged = gameObject;
    }

    public void OnDrag(PointerEventData eventData)
    {
        // 在物体被拖拽时,使其位置跟随鼠标移动

        rectTransform.anchoredPosition += eventData.delta;

        // 由于Canvas缩放会影响鼠标移动量,因此使用canvas.scaleFactor来保持一致性
        // rectTransform.anchoredPosition += eventData.delta / canvas.scaleFactor;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        itemBeingDragged = null;
        // 如果物体被拖拽到了根节点上
        if (transform.parent == transform.root)
        {
            // 将物体放回起始位置,并将其父对象设置为起始父对象
            transform.position = startPosition;
            transform.SetParent(startParent);
        }


        Debug.Log("OnEndDrag");
        // 恢复物体的不透明度和射线检测,使其可以再次被拖拽
        canvasGroup.alpha = 1f;
        canvasGroup.blocksRaycasts = true;
    }
}

新增ItemSlot脚本,控制物品插槽

public class ItemSlot : MonoBehaviour, IDropHandler
{
    // 定义公共属性Item,用于获取或设置当前物品槽中的物体
    public GameObject Item
    {
        get
        {
            // 如果物品槽中已经有物体,则返回其子对象,即当前的物体
            if (transform.childCount > 0)
            {
                return transform.GetChild(0).gameObject;
            }
            // 否则返回null
            return null;
        }
    }

    // 当拖拽物体被放置到当前物品槽时
    public void OnDrop(PointerEventData eventData)
    {
        Debug.Log("OnDrop");
        // 如果当前物品槽中没有物体,则将拖拽的物体设置为当前物品槽的子对象
        if (!Item)
        {
            DragDrop.itemBeingDragged.transform.SetParent(transform);
            // 设置拖拽物体的本地坐标为(0,0),即与物品槽重合
            DragDrop.itemBeingDragged.transform.localPosition = new Vector2(0, 0);
        }
    }
}

挂载脚本,并配置参数
在这里插入图片描述
物品插槽记得添加CanvasGroup组件
在这里插入图片描述

效果
在这里插入图片描述

拾取物品

修改InventorySystem

public class InventorySystem : MonoBehaviour
{
    public static InventorySystem Instance { get; set; }
    // 引入UI界面对象
    public GameObject inventoryScreenUl;
    // 记录物品系统是否打开的状态
    [HideInInspector]
    public bool isOpen;
    // [HideInInspector]
    public List<GameObject> slotList = new List<GameObject>();
    public List<string> itemList = new List<string>();
    private GameObject itemToAdd;//物品插槽
    private GameObject whatSlotToEquip;//空闲的槽位

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }

    private void Start()
    {
        PopulateSlotList();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Tab))
        {
            // 打开物品系统界面
            inventoryScreenUl.SetActive(!isOpen);

            isOpen = !isOpen;

            // 设置鼠标锁定模式为无锁定,允许鼠标在界面上移动
            Cursor.lockState = isOpen ? CursorLockMode.None : CursorLockMode.Locked;
        }
    }

    //遍历获取所有的插槽
    private void PopulateSlotList()
    {
        // 遍历物品系统界面下的所有子物体
        foreach (Transform child in inventoryScreenUl.transform.GetChild(0).transform)
        {
            // 如果子对象的标签为"Slot"
            if (child.CompareTag("Slot"))
            {
                // 将子对象添加到slotList列表中
                slotList.Add(child.gameObject);
            }
        }
    }

    //添加物品
    public void AddToInventory(string itemName)
    {
        // 找到下一个空闲的槽位
        whatSlotToEquip = FindNextEmptySlot();

        // 根据物品名称实例化一个新的物体,并设置其位置和旋转信息为whatSlotToEquip的位置和旋转信息
        itemToAdd = Instantiate(Resources.Load<GameObject>(itemName), whatSlotToEquip.transform.position, whatSlotToEquip.transform.rotation);
        // 将新实例化的物体的父对象设置为whatSlotToEquip
        itemToAdd.transform.SetParent(whatSlotToEquip.transform);

        // 将物品名称添加到itemList中
        itemList.Add(itemName);
    }

    //找到空闲的槽位
    private GameObject FindNextEmptySlot()
    {
        // 遍历slotList列表中的每个槽位对象
        foreach (GameObject slot in slotList)
        {
            // 如果槽位对象没有子对象(即为空闲)
            if (slot.transform.childCount == 0)
            {
                // 返回该槽位对象
                return slot;
            }
        }

        // 如果没有找到空闲的槽位,则返回一个新的空游戏对象
        return new GameObject();
    }

    //判断库存是否已满
    public bool CheckIfFull()
    {
        int counter = 0;
        // 遍历slotList列表中的每个槽位对象
        foreach (GameObject slot in slotList)
        {
            // 如果槽位对象有子对象(即已被占用)
            if (slot.transform.childCount > 0)
            {
                counter++;
            }
        }

        // 如果占用的槽位数等于21(满了),返回true,否则返回false
        if (counter == 21)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

修改InteractableObject,调用添加库存功能

//拾取物品
public void PickUp(){
    if(!InventorySystem.Instance.CheckIfFull()){
        InventorySystem.Instance.AddToInventory(ItemName);   
        Destroy(gameObject);
    }else{
        Debug.Log("库存已满");
    }
}

把石头物品插槽样式放到Resources文件夹
在这里插入图片描述
效果
在这里插入图片描述

添加更多物品

比如我这里再加一些小树枝
https://sketchfab.com/3d-models/collection-of-forest-branches-11df981a8ff7441a9bdded31cc770e5f
在这里插入图片描述
效果
在这里插入图片描述

源码

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

完结

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

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

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux实验记录:远程控制服务

前言&#xff1a; 本文是一篇关于Linux系统初学者的实验记录。 参考书籍&#xff1a;《Linux就该这么学》 实验环境&#xff1a; VmwareWorkStation 17——虚拟机软件 RedHatEnterpriseLinux[RHEL]8——红帽操作系统 备注&#xff1a; SSH&#xff08;Secure Shell&…

【Python基础018】在程序中怎么实现自定义抛出异常

在上一节中&#xff0c;我们讲了如何对程序中的异常进行处理&#xff0c;但这是针对程序在运行过程中系统自动抛出的异常&#xff0c;而让程序被动的抛出异常在实践中也具有重要作用。 1、raise语句抛出异常 raise 语句可以使用一个类&#xff08;必须是 Exception 或者 Excep…

C++-内存管理(1)

1. C/C内存分布 首先我们需要知道&#xff0c;在C中的内存分为5个区。 1. 栈 又叫堆栈 -- 非静态局部变量 / 函数参数 / 返回值等等&#xff0c;栈是向下增长的。 2. 内存映射段 是高效的 I/O 映射方式&#xff0c;用于装载一个共享的动态内存库。用户可使用系统接口 创建…

解说 AIGC(人工智能生成内容) 是什么?

前言 AIGC (AI Generated Content)即人工智能生成内容,一般认为是相对于PCG(专业生成内容)、UCG(用户生成内容)而提出的概念。AIGC狭义概念是利用AI自动生成内容的生产方式。广义的AIGC可以看作是像人类一样具备生成创造能力的AI技术,即生成式AI,它可以基于训练数据和生成算法…

漏洞原理SSRF漏洞

漏洞原理SSRF漏洞 服务器请求伪造 SSRF(Server Side Request Forgery)是一种服务器端请求伪造漏洞。它允许攻击者利用后端服务器来发送未经授权的请求。攻击者可以通过修改请求的目标地址,将请求发送到内部网络或其他受信任的服务器上,从而绕过防火墙和访问控制。 SSRF漏洞…

redis使用Big key的问题

文章目录 BigKey带来的问题业务场景具体现象解决思路 BigKey带来的问题 客户端执行命令的时延变大&#xff1a;对大Key进行的慢操作会导致后续的命令被阻塞&#xff0c;从而导致一系列慢查询。 引发操作阻塞&#xff1a;Redis内存达到maxmemory参数定义的上限引发操作阻塞或重…

2016年苏州大学837复试机试C/C++

2016年苏州大学复试机试 第一题 题目 公鸡5元一只&#xff0c;母鸡3元一只&#xff0c;幼鸡1元3只。若100元钱买了100只鸡&#xff0c;问其中公鸡、母鸡、幼鸡各多少只&#xff1f; 博主注&#xff1a;此题经典百元买百鸡问题&#xff0c;出自&#xff1a;公元5世纪末&#…

mysql 允许其他ip访问

1.改表法。 可能是你的帐号不允许从远程登陆&#xff0c;只能在localhost。这个时候只要在localhost的那台电脑&#xff0c;登入mysql后&#xff0c;更改 “mysql” 数据库里的 “user” 表里的 “host” 项&#xff0c;从"localhost"改称"%" //执行以下…

基础知识总结

概念概述 计算机网络是通过传输介质、通信设施和网络通信协议&#xff0c;把分散在不同地点的计算机设备互连起来&#xff0c;实现资源共享和数据传输的系统。而网络编程就是编写程序使联网的两个或多个设备&#xff08;比如计算机&#xff09;之间进行数据传输。Java语言对网…

JRT人大金仓测试

之前基于IRIS导出的Sql脚本用JRT的导表脚本执行Sql语句在PostGreSql数据库把IRIS导出的库还原。并且试了模板设计器的打开和保存及打印功能。本次测试IRIS导出的Sql在人大金仓上还原数据库&#xff0c;并且测试模板设计器功能和打印。 首先碰到的一个坑是人大金仓把空串存成NU…

P1228 地毯填补问题(葬送的芙蓉王【bushi】)

地毯填补问题 题目描述 相传在一个古老的阿拉伯国家里&#xff0c;有一座宫殿。宫殿里有个四四方方的格子迷宫&#xff0c;国王选择驸马的方法非常特殊&#xff0c;也非常简单&#xff1a;公主就站在其中一个方格子上&#xff0c;只要谁能用地毯将除公主站立的地方外的所有地…

Vue Router 动态路由

聚沙成塔每天进步一点点 本文内容 ⭐ 专栏简介1. 动态路由的使用2. 动态路由的原理解析路由匹配路由参数的传递组件渲染动态路由的变化 3. 更多动态路由的实例3.1. 动态路径匹配多层级3.2. 动态路径的正则匹配3.3. 编程式导航与动态路由 总结 ⭐ 写在最后 ⭐ 专栏简介 Vue学习之…

CSS 3D三角彩色锥形旋转动画效果

<template><view class="pyramid-loader"><view class="wrapper"><span class="side side1"></span> <!-- 金字塔的一个面 --><span class="side side2"></span> <!-- 金字塔的…

会计试算平衡

目录 一. 试算平衡的意义二. 试算平衡的原理和内容三. 试算平衡表 \quad 一. 试算平衡的意义 \quad ①验证错误 ②便于编制会计报表 试算表根据各分类账借贷余额汇总编制而成&#xff0c;依据试算表编制会计报表将比直接依据分类账来编制更为方便,拥有大量分类账的企业尤为便捷…

浙大发布Agent学习框架,13B 模型达到 ChatGPT 水平!

2023 年下半年&#xff0c;AI Agent 正式开启「大模型下半场」。 自“人工智能”这门学科创立之初&#xff0c;一种可以“观察世界”-“思考推理”-“做出行动”-“反思学习”的人造代理就是构建通用人工智能的终极目标之一。而基于大模型的 AI Agent 借助大模型强大的推理判断…

(天坑的87端口)nginx代理端口不生效,代理87端口遇到的问题及原因

目录 一. 问题产生 二.问题现象 三.问题排查 四.柳暗花明 五.解决方案 六.不安全的端口号 七.总结 一. 问题产生 因为之前的一个项目一直是用的86端口&#xff0c;这次要在一台新的服务器上重新部署两个项目&#xff0c;很自然而然的继续86端口&#xff0c;另一个也没想&…

【数据结构与算法】之哈希表系列-20240130

这里写目录标题 一、383. 赎金信二、387. 字符串中的第一个唯一字符三、389. 找不同四、409. 最长回文串五、448. 找到所有数组中消失的数字六、594. 最长和谐子序列 一、383. 赎金信 简单 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不…

C++/MFC:在窗体Form(Dialog)中多个编辑框时,在输入时将回车解释为TAB键,将输入焦点移到下一个编辑框的方法

很多时候&#xff0c;为了输入方便&#xff0c;常用的做法&#xff0c;就是将回车键解释为将输入焦点移动到下一个编辑框中。就像是我的VxTerm中的快速连接输入一样&#xff1a; VxTerm是一个国产化替代的SSH工具&#xff0c;可以从本站的资源中免费下载并且免费使用&#xff…

R高级绘图 | P1 | 带边缘分布散点图 | 代码注释 + 结果解读

新系列 —— R高级绘图&#xff0c;准备整理所有曾经绘制过的图图和未来需要的图图们的代码&#xff01;预计这个系列会囊括所有常见图形&#xff0c;只提供高级绘图代码&#xff0c;基础绘图主要在 R语言绘图 系列中进行介绍&#xff0c;这个系列咱们主打&#xff1a;需要XX图…

数学公式OCR识别php 对接mathpix api 使用公式编译器

数学公式OCR识别php 对接mathpix api 一、注册账号官网网址&#xff1a;https://mathpix.com 二、该产品支持多端使用注意说明&#xff08;每月10次&#xff09; 三、api 对接第一步创建create keyphp对接api这里先封装两个请求函数&#xff0c;get 和post &#xff0c;通过官方…
最新文章