【Unity】仓库逻辑:拾取物体进仓库和扔掉物品

需求说明

目标:实现玩家移动过程中,拾取物体,物体被放入仓库;点击仓库中物体,重新扔回3D场景中逻辑。

逻辑分析:

  • 需要玩家可以移动;
  • 需要检测玩家和物体的碰撞,并摧毁物体;
  • 需要识别物体的类别;
  • 新物体直接新建,已有的物体增加数量;
  • 需要记录仓库的物体详情列表,并响应列表的变化;
  • 需要仓库的UI界面,点击物体可以生成物体到3D中;
  • 需要提供物体的素材,可以动态的增删和展示物体。

成果展示

请添加图片描述

Scene部分

在这里插入图片描述

玩家移动

需要绑定移动相关的脚本
在这里插入图片描述

碰撞检测

两个物体能够检测到碰撞,需要至少一个物体绑定刚体组件,需要绑定碰撞体组件,碰撞体组件需要勾选 isTrigger 属性。

被绑定刚体组件的物体,需要取消勾选 use gravity 重力属性,才能阻止物体自然下落(不在平面上的情况)。

在这里插入图片描述

识别物体

将需要放进仓库中的物体,做成 profab 预制体。

定义不同的 tag 区分物体类别。

UI仓库栏

建议做成滚动界面【点击查看相关文章】,应对仓库物品多的情况。

仓库栏中展示物体使用 Image 组件,不同的物品对应不同的图片。

制作单个物体UI模板,当有物品增删到仓库时,只需要实例化该模板,修改其中的物体图片和数量即可。

动态素材

新建空物体,绑定素材资源输入的脚本
在这里插入图片描述

脚本部分

类的设计
物体类

包括可以放入仓库的物体信息,物体名称、物品个数、物体对应的Profab、物体对应的UI图片等。

public class Goods
{
    private GoodsName goodsName;
    private int num;

    public Goods(GoodsName goodsName)
    {
        this.goodsName = goodsName;
        num = 1;
    }

    public void AddNum()
    {
        num++;
    }

    public void DecNum()
    {
        num--;
    }

    public int GetNum()
    {
        return num;
    }

    public GoodsName GetGoodsName()
    {
        return goodsName;
    }

    public Sprite GetSprite()
    {
        switch (goodsName)
        {
            case GoodsName.Cube:
                return GameAsset.instance.Cube;
            case GoodsName.Cylinder:
                return GameAsset.instance.Cylinder;
            default:
                return null;
        }
    }

    public Transform GetProfab()
    {
        switch (goodsName)
        {
            case GoodsName.Cube:
                return GameAsset.instance.CubeTransform;
            case GoodsName.Cylinder:
                return GameAsset.instance.CylinderTransform;
            default:
                return null;
        }
    }
}
仓库类

管理仓库,包括物品列表、增删物品等。

public class Inventory
{
    //列表发生变化时触发
    public event EventHandler OnItemListChanged;

    private List<Goods> goodsList;
    private Action<Goods> useGoodsAction;
    public Inventory(List<Goods> goodsList, Action<Goods> useGoodsAction)
    {
        this.goodsList = goodsList;
        this.useGoodsAction = useGoodsAction;
    }

    //增加时,新物体加入列表,已有的物体改变数量
    public void AddGoods(GoodsName goodsName)
    {
        Goods target = goodsList.Find(_ => _.GetGoodsName() == goodsName);
        if (target != null)
        {
            target.AddNum();
        }
        else
        {
            Goods goods = new Goods(goodsName);
            goodsList.Add(goods);
        }
        OnItemListChanged?.Invoke(this, EventArgs.Empty);
    }

    //删除时,数量为1的物体从列表移除,否则只改变数量
    public void DeleteGoods(GoodsName goodsName)
    {
        Goods target = goodsList.Find(_ => _.GetGoodsName() == goodsName);
        if (target != null)
        {
            if (target.GetNum() == 1)
            {
                goodsList.Remove(target);
            }
            else
            {
                target.DecNum();
            }
        }
        OnItemListChanged?.Invoke(this, EventArgs.Empty);
    }

    public List<Goods> GetGoodsList() {
        return goodsList;
    }

    //需要使用仓库中的物品
    public void UseGoods(Goods goods) {
        useGoodsAction(goods);
    }
}
素材脚本

提供不同物体的素材

public class GameAsset : MonoBehaviour
{
    public static GameAsset instance;
    private void Awake()
    {
        instance = this;
    }
    public Sprite Cube;
    public Sprite Cylinder;

    public Transform CubeTransform;
    public Transform CylinderTransform;
}
玩家脚本

键盘按键控制玩家移动;

检测与物体的碰撞;

实例化仓库类;

建立仓库UI和仓库类的关系;

public class Player : MonoBehaviour
{
    [SerializeField] private float moveSpeed = 20f;

    private void Update()
    {
        //玩家的移动
        Vector3 inputDir = new Vector3(0, 0, 0);
        if (Input.GetKey(KeyCode.UpArrow)) inputDir.z += +1f;
        if (Input.GetKey(KeyCode.DownArrow)) inputDir.z += -1f;
        if (Input.GetKey(KeyCode.LeftArrow)) inputDir.x += -1f;
        if (Input.GetKey(KeyCode.RightArrow)) inputDir.x += +1f;


        Vector3 moveDir = transform.forward * inputDir.z + transform.right * inputDir.x;
        transform.position += moveDir * moveSpeed * Time.deltaTime;
    }


    Inventory inventory;
    [SerializeField] UI_Inventory ui_inventory;
    private void Awake()
    {
        inventory = new Inventory(new List<Goods>(), (goods) =>
        {
            //使用物体时,删除仓库中的物体,生成新的物体预制体,并随机扔在3D场景中。
            inventory.DeleteGoods(goods.GetGoodsName());
            Instantiate(goods.GetProfab(), new Vector3(UnityEngine.Random.Range(-20, 20), 0, UnityEngine.Random.Range(-20, 20)), new Quaternion());
        });
        
        //初始化UI
        ui_inventory.Init(inventory);
    }

    void OnTriggerEnter(Collider c)
    {
        //可以放进仓库的物体,增加到仓库,同时摧毁3d场景中的物体
        if (Enum.TryParse(c.gameObject.tag, true, out GoodsName goodsName))
        {
            inventory.AddGoods(goodsName);
            Destroy(c.gameObject);
        }
    }
}
UI脚本

随着仓库物品的列表变化而更新;

点击UI, 可以使用物品;

public class UI_Inventory : MonoBehaviour
{
    Transform itemTemplate;
    List<Transform> itemTransformList;

    Inventory inventory;
    public void Init(Inventory inventory)
    {
        this.inventory = inventory;
        inventory.OnItemListChanged += Inventory_OnItemListChanged;

        //记录物体UI模板
        itemTemplate = transform.Find("itemTemplate");
        
        itemTransformList = new List<Transform>();
    }

    //事件: 列表变化,刷新UI
    private void Inventory_OnItemListChanged(object sender, System.EventArgs e)
    {
        UpdateItemsList();
    }

    //列表变化,刷新UI
    private void UpdateItemsList()
    {
        //先删除所有UI的物体
        itemTransformList.ForEach(_ =>
        {
            Destroy(_.gameObject);
        });
        itemTransformList.Clear();
        
        //重新加载仓库类中的物品列表
        inventory.GetGoodsList().ForEach(goods =>
        {
            Transform itemTemplateTransform = Instantiate(itemTemplate, transform);
            itemTemplateTransform.gameObject.SetActive(true);
            //输入对应物品图片和数量
            itemTemplateTransform.Find("Image").GetComponent<Image>().sprite = goods.GetSprite();
            itemTemplateTransform.Find("text").GetComponent<TextMeshProUGUI>().SetText(goods.GetNum().ToString());
            
            itemTransformList.Add(itemTemplateTransform);
            
			//点击物品,触发事件
            itemTemplateTransform.GetComponent<Button_UI>().ClickFunc = () => {
                inventory.UseGoods(goods);
            };
        });
    }
}

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

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

相关文章

css知识点梳理2

1. 选择器拓展 在 CSS 中&#xff0c;可以根据选择器的类型把选择器分为基础选择器和复合选择器&#xff0c;复合选择器是建立在基础选择器之上&#xff0c;对基本选择器进行组合形成的。 ​ 复合选择器是由两个或多个基础选择器&#xff0c;通过不同的方式组合而成的&#xf…

【Flask】一、安装与第一个测试程序

目录 Flask简介 安装Flask 安装pip&#xff08;Python包管理器&#xff09; 使用pip安装Flask 验证安装 创建Flask程序 创建应用 运行 访问测试 Flask简介 Flask是一个用Python编写的轻量级Web应用框架。它被设计为易于使用和扩展&#xff0c;使其成为构建简单网站或复…

[项目][boost搜索引擎#4] cpp-httplib使用 | log.hpp | 前端 | 测试及总结

目录 编写http_server模块 1. 引入cpp-httplib到项目中 2. cpp-httplib的使用介绍 3. 正式编写http_server 九、添加日志到项目中 十、编写前端模块 十一. 详解传 gitee 十二、项目总结 项目的扩展 写在前面 项目 gitee 已经上传啦 &#xff08;还是决定将学校和个人…

网络编程基础-Reactor线程模型-原理剖析

1、Reactor基本概念 Reactor线程模型其实是一种设计模式&#xff0c;其核心思想就是将输入多路复用和事件派发相结合&#xff0c;从而减少系统中活跃线程的数量。 像我们之前讲到的文章网络编程基础-IO模型深入理解_网络io-CSDN博客提到了其中网络IO模型&#xff08;BIO、NIO…

asp.net core 入口 验证token,但有的接口要跳过验证

asp.net core 入口 验证token,但有的接口要跳过验证 在ASP.NET Core中&#xff0c;你可以使用中间件来验证token&#xff0c;并为特定的接口创建一个属性来标记是否跳过验证。以下是一个简化的例子&#xff1a; 创建一个自定义属性来标记是否跳过验证&#xff1a; public clas…

基于PHP的http字段查询与注册(V1)(持续迭代)

目录 版本说明&#xff1a; 实现环境&#xff08;WAMP&#xff09;&#xff1a; 数据库链接 查询页面 php处理逻辑 字段添加 版本说明&#xff1a; 该查询功能以查询http首部字段为目的实现的字段属性、字段内容的查询&#xff0c;以及对新字段信息的数据注册。 v1实现…

python 制作 发货单 (生成 html, pdf)

起因&#xff0c; 目的: 某个小店&#xff0c;想做个发货单。 过程: 先写一个 html 模板。准备数据&#xff0c; 一般是从数据库读取&#xff0c;也可以是 json 格式&#xff0c;或是 python 字典。总之&#xff0c;是数据内容。使用 jinja2 来渲染模板。最终的结果可以是 h…

多线程进阶——线程池的实现

什么是池化技术 池化技术是一种资源管理策略&#xff0c;它通过重复利用已存在的资源来减少资源的消耗&#xff0c;从而提高系统的性能和效率。在计算机编程中&#xff0c;池化技术通常用于管理线程、连接、数据库连接等资源。 我们会将可能使用的资源预先创建好&#xff0c;…

WPF+MVVM案例实战(七)- 系统初始化界面字体描边效果实现

文章目录 1、案例效果展示2、项目准备3、功能实现1、资源获取2、界面代码3、后台代码 4 源代码获取 1、案例效果展示 2、项目准备 打开项目 Wpf_Examples&#xff0c;新建系统初始化界面 WelcomeWindow.xmal,如下所示&#xff1a; 3、功能实现 1、资源获取 案例中使用的CSD…

Java | Leetcode Java题解之第516题最长回文子序列

题目&#xff1a; 题解&#xff1a; class Solution {public int longestPalindromeSubseq(String s) {int n s.length();int[][] dp new int[n][n];for (int i n - 1; i > 0; i--) {dp[i][i] 1;char c1 s.charAt(i);for (int j i 1; j < n; j) {char c2 s.char…

【Java并发编程】信号量Semaphore详解

一、简介 Semaphore&#xff08;信号量&#xff09;&#xff1a;是用来控制同时访问特定资源的线程数量&#xff0c;它通过协调各个线程&#xff0c;以保证合理的使用公共资源。 Semaphore 一般用于流量的控制&#xff0c;特别是公共资源有限的应用场景。例如数据库的连接&am…

Python | Leetcode Python题解之第516题最长回文子序列

题目&#xff1a; 题解&#xff1a; class Solution:def longestPalindromeSubseq(self, s: str) -> int:n len(s)dp [[0] * n for _ in range(n)]for i in range(n - 1, -1, -1):dp[i][i] 1for j in range(i 1, n):if s[i] s[j]:dp[i][j] dp[i 1][j - 1] 2else:dp…

从病理AI的基础模型发展历程,看未来的医学AI发展趋势|个人观点·24-10-23

小罗碎碎念 在临床相关的人工智能&#xff08;AI&#xff09;模型发展方面&#xff0c;传统上需要大量标注数据集&#xff0c;这使得AI的进步主要围绕大型中心和私营企业展开。所以&#xff0c;在这期推文中&#xff0c;我会介绍一些已经商用的模型&#xff0c;并且为计划进军…

逻辑推理学习笔记

目的 立场辩护整理思绪 基本框架 论题 &#xff08;变化&#xff09; 我要证明&#xff08;讨论对象 变化&#xff09; 论据 &#xff08;变化&#xff09; 拿什么证明&#xff1f;也就是证据呈现。 论证 &#xff08;不变&#xff09; 要如何证明&#xff1f;逻辑框架…

通过conda install -c nvidia cuda=“11.3.0“ 安装低版本的cuda,但是却安装了高版本的12.4.0

问题 直接通过 conda install -c nvidia cuda"11.3.0"安装得到的却是高版本的 不清楚原理 解决方法 不过我们可以分个安装 runtime toolkit 和 nvcc 安装指定版本的 cudatoolkit 和 nvcc conda install -c nvidia cuda-cudart"11.3.58" conda instal…

【Linux系统编程】——Linux入门指南:从零开始掌握操作系统的核心(指令篇)

文章目录 查看 Linux 主机 ip以及登录主机Linux基础文件操作指令man&#xff1a;查看命令的手册页&#xff0c;了解命令的详细用法。pwd&#xff1a;显示当前目录路径。cd&#xff1a;切换目录。ls&#xff1a;列出当前目录下的文件和文件夹。mkdir&#xff1a;创建新目录。 文…

第三讲、C的运算符和表达式

一、运算符分类&#xff1a; &#xff08;1&#xff09;按运算对象的数目&#xff1a; 单目运算符 双目运算符 三目运算符 &#xff08;2&#xff09;按运算对象的数目&#xff1a; 算术运算符、赋值运算符、关系运算符、逻辑运算符、位运算符、自增自减运算符、…

菜叶子芯酸笔记3:GPU、GPGPU、CUDA之间的关系;CUDA之外;Tensor Core

我今天看到B站一个up主很好的资料【云计算科普研究所的个人空间-云计算科普研究所个人主页-哔哩哔哩视频】&#xff0c;结合我这周的积累整理了这份我觉得相比之前逻辑更加完善的笔记。 先是GPU到GPGPU 到CUDA之间进化关系部分&#xff0c;然后CUDA之外的友商竞品部分&#xf…

orbslam安装

1.linux操作命令 pwd&#xff1a;查看终端所在路径 cd&#xff1a;切换路径 cd ..&#xff1a;跳回到上级目录 ls: 列出当前路径下的所有文件夹 touch&#xff1a;创建新的文件 mv &#xff1a;移动文件(在该文件所在目录的路径下执行此操作) 例如&#xff1a;mv test_file /ho…

vue3中mitt和pinia的区别和主要用途,是否有可重合的部分?

在 Vue 中&#xff0c;Mitt 和 Pinia 是两个不同的工具&#xff0c;它们的主要用途和功能有所不同&#xff0c;但在某些方面也存在重合的部分。 区别 Mitt&#xff1a; Mitt 是一个简单而强大的事件总线库&#xff0c;用于在组件之间进行事件的发布和订阅。 它提供了一种简洁…