【unity小技巧】unity事件系统创建通用的对象交互的功能

文章目录

  • 前言
  • 实现
    • 1. **InteractEvent 类**:
    • 2. **Interact 类**:
    • 3. **Player 类**:
    • 4. **Chest 类**:
  • 工作流程说明:
  • 开单个箱子
  • 按钮触发打开很多箱子
  • 拾取物品(传参)
  • 参考
  • 完结

前言

游戏开发过程中,要实现玩家和物体之间的交互是非常常见的事情。如果在开发过程中,你希望和箱子交互触发开箱子的方法,和门交互,又触发开门的方法,实现方式其实有很多,比如继承同一个分类或者定义一个接口就是不错的方法,门和箱子都继承这个接口,然后各自重写方法接口里面的触发方法。

但是,如果我说要实现点击一个按钮,打开几个箱子同时开启几个门呢?你可能会说我先获取所有的箱子或者门,然后循环遍历执行里面对应的触发方法不就可以了?当然这种方法是可行的,但是不够优雅。今天我就分享一种使用委托和事件的方式来实现一个通用的物品的交互方式。

至于什么是委托和事件,之前文章我已经有所介绍了,感兴趣可以先去看看:
【unity小技巧】委托(Delegate)的基础使用和介绍
【unity实战】事件(Event)的基本实战使用

实现

1. InteractEvent 类

  • InteractHandler 委托: 定义了一个没有参数和返回值的委托类型。
  • HasInteracted 事件: 事件,当触发时调用所有注册的委托。

方法:

  • CallInteractEvent 方法: 触发 HasInteracted 事件,如果有订阅者,则调用它们。
public class InteractEvent
{public delegate void InteractHandler();public event InteractHandler HasInteracted;// 调用互动事件public void CallInteractEvent() => HasInteracted?.Invoke();
}

2. Interact 类

  • InteractEvent interact: 这是一个 InteractEvent 类的实例,用于处理交互事件。
  • Player player: 用于存储与之交互的玩家实例。

属性和方法:

  • GetInteractEvent 属性: 返回 InteractEvent 实例。如果 interact 为 null,会在首次访问时初始化。
  • GetPlayer 属性: 返回存储的玩家实例。
  • CallInteract 方法: 接受一个 Player 参数,设置 player 属性为该参数,然后调用 interactCallInteractEvent 方法。
public class Interact : MonoBehaviour
{InteractEvent interact = new InteractEvent();Player player;// 获取互动事件public InteractEvent GetInteractEvent{get{if (interact == null)interact = new InteractEvent();return interact;}}// 获取玩家public Player GetPlayer{get { return player; }}// 调用互动方法public void CallInteract(Player interactedPlayer){player = interactedPlayer;interact.CallInteractEvent();}
}

3. Player 类

  • Update 方法: 每帧检查玩家是否按下 E 键,如果是,则调用 PlayerInteract 方法。
  • PlayerInteract 方法: 创建一条射线从相机的视口中心向前发射,然后检测是否击中了特定层级(层0和层3)的物体。如果击中了一个具有 Interact 组件的物体,则调用其 CallInteract 方法,并传递自身实例。
public class Player : MonoBehaviour
{void Update(){// 如果玩家按下E键,进行交互操作if (Input.GetKeyDown(KeyCode.E)){PlayerInteract();}}// 处理玩家交互的函数public void PlayerInteract(){// 定义用于层0和层3的层蒙版,0和3图层都可以满足条件var layerMask0 = 1 << 0;var layerMask3 = 1 << 3;var finalMask = layerMask0 | layerMask3;// 从屏幕中心创建一条射线Ray ray = Camera.main.ViewportPointToRay(new Vector3(.5f, .5f, 0));// 进行射线投射,检查在最终蒙版上是否命中物体(距离不超过15个单位)RaycastHit hit;if (Physics.Raycast(ray, out hit, 15, finalMask)){// 从命中的物体获取Interact脚本组件Interact interactScript = hit.transform.GetComponent<Interact>();// 如果Interact脚本组件存在,调用其CallInteract方法并传递玩家实例if (interactScript != null){interactScript.CallInteract(this);}}}
}

4. Chest 类

  • Interact openFromInteraction: 存储一个 Interact 类的实例,用于处理与宝箱的交互。

方法:

  • OnEnable 方法: 当对象激活时,订阅 openFromInteractionHasInteracted 事件到 OpenChest 方法。
  • OnDisable 方法: 当对象禁用时,取消订阅 openFromInteractionHasInteracted 事件。
  • OpenChest 方法: 当宝箱应该打开时调用,可以在其中添加具体的打开宝箱逻辑,例如生成掉落物品。
public class Chest : MonoBehaviour
{public Interact interact;// 当对象启用时订阅交互事件private void OnEnable(){if (interact != null){interact.GetInteractEvent.HasInteracted += OpenChest;}}// 当对象禁用时取消订阅交互事件private void OnDisable(){if (interact != null){interact.GetInteractEvent.HasInteracted -= OpenChest;}}// 处理宝箱打开的函数public void OpenChest(){// 掉落一些酷炫的东西}
}

工作流程说明:

  • Player 类中的 PlayerInteract 方法检测玩家按下 E 键后,发射一条射线检测是否与可交互物体碰撞。
  • 如果射线击中了具有 Interact 组件的物体,就调用其 CallInteract 方法,并传递玩家实例。
  • Interact 类中的 CallInteract 方法将玩家实例存储,并调用其内部的 InteractEvent 实例的 CallInteractEvent 方法,从而触发 HasInteracted 事件。
  • Chest 类中的 OnEnable 方法在对象启用时订阅 HasInteracted 事件,当事件触发时调用 OpenChest 方法来打开宝箱。

开单个箱子

挂载脚本
在这里插入图片描述
效果
在这里插入图片描述

按钮触发打开很多箱子

我们可以让一个按钮与多个对象进行交互,挂载脚本
在这里插入图片描述
效果
在这里插入图片描述

拾取物品(传参)

带玩家参数的拾取物品功能,脚本挂载在物体预制体上即可

public class ItemPickup : MonoBehaviour
{public string item; // 物品名称public int amount; // 物品数量public Interact interact; // 拾取物品的交互对象private void OnEnable(){Interact getInteract = GetComponent<Interact>();if (getInteract == null){getInteract = gameObject.AddComponent<Interact>(); // 如果没有,则添加Interact组件   }interact = getInteract;interact.GetInteractEvent.HasInteracted += InteractPickup;}private void OnDisable(){if (interact){interact.GetInteractEvent.HasInteracted -= InteractPickup; // 取消监听交互事件}}public void InteractPickup(){AddItem(interact.GetPlayer); // 执行AddItem方法,传入交互对象的玩家信息}public void AddItem(Player player){// 给玩家添加物品的逻辑在这里实现}
}

参考

https://www.youtube.com/watch?v=MdOi9ymb07s

完结

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

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

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

在这里插入图片描述

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

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

相关文章

ONLYOFFICE8.1版本桌面编辑器测评

OO官方链接点这里&#xff1a;ONLYOFFICE 文档 8.1 现已发布&#xff1a;功能全面的 PDF 编辑器、幻灯片版式、优化电子表格的协作等等 | ONLYOFFICE 博客 一、界面与用户体验 整体布局和设计的美观性、易用性&#xff1a; ONLYOFFICE 8.1 版本的桌面编辑器展现出了令人眼前一亮…

磁芯电感 晶谷电容可镀银浆用玻璃 晶谷电阻银浆料低温玻璃粉(耐强酸)

晶谷电阻银浆料低温玻璃粉&#xff08;耐强酸&#xff09;软化点在490至580度之间&#xff0c;线膨胀系数为&#xff08;75至95&#xff09;10-7&#xff0c;粒径为1.5至3微米&#xff08;可按要求订做&#xff09;&#xff0c;外观颜色为白色超细粉末&#xff0c;烧后颜色无色…

新能源汽车 LabCar 测试系统方案(-)

什么是LabCar测试 LabCar测试目标是进行整车黄板台架功能测试&#xff0c;用于整车开发和测试阶段&#xff0c;满足设计人员和测试人员的试验需求&#xff0c;以验证整车性能&#xff0c;减少开发工作量。系统主要用于测试静态及动态工况下的纯电动汽车的各项功能实现情况。 …

设计模式原则——里氏替换原则

设计模式原则 设计模式示例代码库地址&#xff1a; https://gitee.com/Jasonpupil/designPatterns 里氏替换原则 继承必须确保父类所拥有的性质在子类中依然成立 与开闭原则不同的是开闭原则可以改变父类原有的功能&#xff0c;里氏替换原则不能修改父类的原有的性质&#…

在线装修管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;装修队管理&#xff0c;用户管理&#xff0c;装修管理&#xff0c;基础数据管理&#xff0c;论坛管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;…

197.回溯算法:复原IP地址(力扣)

代码解决 class Solution { public:// 存储最终结果的向量vector<string> result;// 判断字符串s从start到end范围内的子串是否是一个合法的IP地址段bool isValid(const string& s, int start, int end){if (start > end) {return false; // 起始位置大于结束位置…

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档&#xff1a;https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址&#xff1a;https://github.com/Hufe921/canvas-editor 前提声明&#xff1a; 由于CanvasEditor目前不支持vue、react 等框架开箱即用版&#xff0c;所以…

开源seata的分布式事务解决方案-XA、AT、TCC、SAGA哪个模式好

分布式事务是分布式系统中非常重要的一部分。假设一个用户购买商品的业务逻辑&#xff0c;系统有3个微服务组成&#xff0c;分别是订单服务、账户服务、库存服务&#xff0c;用户在提交订单后会从用户账户余额中扣款&#xff0c;同时扣减库存数量。在这样的场景下扣款和减库存需…

IDEA中 pom.xml 设置自动提示

IDEA中 pom.xml 自动提示 IDEA中 pom.xml 自动提示设置如下&#xff1a; file–>Settings–>Build,Execution…–>Build Tools–>Maven–>Repositories 会看到类似表格的画面&#xff0c;内容是你的maven地址&#xff0c;选中后&#xff0c;右边有个Update的按…

开放式耳机哪种好用又实用?开放式耳机必入品牌推荐,内行人分享

随着数码技术的不断推出各种各样的新产品&#xff0c;开放式耳机已经逐渐成为有份音乐发烧友的选择&#xff0c;这类耳机从早期的简单音质发展至今日的高解析度&#xff0c;其技术进步&#xff0c;也吸引了一大批开放式耳机的爱好者&#xff0c;开放式耳机以其开放式的设计&…

2024中国第三方算力中心服务商发展研究报告

来源&#xff1a;科智咨询 近期历史回顾&#xff1a;《江苏省绿色建筑评价标识实施细则》(1).pdf 《江苏省绿色建筑评价标识实施细则》.pdf 【计算工具】钢铁企业碳排放各工序数据收集表.xlsx 【深度报告】钢铁产品碳足迹核算及报告指南.pdf 【专家PPT】宝钢低碳钢铁技术策划及…

巧用newSingleThreadExecutor让异步任务顺序跑

背景 Flume 是 Cloudera 提供的一个高可用的&#xff0c;高可靠的&#xff0c;分布式的海量日志采集、聚合和传输的系统 。一个用来控制 Flume 采集任务的 Web 应用&#xff0c;需要对任务进行管理&#xff0c;主要操作「启动、停止、新建、编辑、删除」&#xff0c;本质就是对…

头歌——机器、深度学习——手写体识别

第1关&#xff1a;神经网络基本概念 任务描述 本关任务&#xff1a;根据本节课所学知识完成本关所设置的选择题。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.神经网络基本概念。 神经网络基本概念 神经网络由输入层、隐藏层、输出层组成&#xff1b;…

【源码】含70演示高转化率Magento2外贸时装女装跨境电商模板V1.2.2

MagMog是下一代最高转化率和可扩展的跨境电商Magento2主题&#xff0c;让您几乎可以立即上手。这是一个终极解决方案&#xff1a;主题附带一系列电子商务功能&#xff0c;可以启用您商店的隐藏功能&#xff0c;并且您无需支付任何额外费用。 100% 免费。 MagMog从定制设计到内…

AI大模型企业应用实战(16)-langchain核心组件

1 stuff 将文档列表插入到提示词中&#xff0c;适合文档较小或少量文档的应用。 2 refine 通过循环输入文档并迭代更新答案来构建响应&#xff0c;一次只传递给LLM一个文档&#xff0c;适合LLM上下文大小不能容纳的小文档。 参考&#xff1a; https://js.langchain.com/v0.1…

搭建个人官网时如何配置SMTP邮件自动发送

什么是 SMTP&#xff1f; SMTP( Simple Mail Transfer Protocol ) 是一种简单邮件传输协议&#xff0c;可以在互联网上通过SMTP来发送电子邮件&#xff0c;是建模在 FTP 文件传输服务上的一种邮件服务&#xff0c;主要用于传输系统之间的邮件信息并提供来信有关的通知。SMTP 服…

pycharm不能安装包的解决方法

一直使用VScode写python&#xff0c;最近使用pycharm&#xff0c;但是pycharm不能安装包&#xff0c;类似这种 后面直接使用ALT F12跳转终端&#xff1a; pip install 需要添加的包 -i https://pypi.tuna.tsinghua.edu.cn/simple不报错了

量检具管理有一套

量检具是用于测量和检验产品尺寸、形状和质量的工具。有一位年轻的工程师小张&#xff0c;他负责管理工厂的量检具&#xff0c;确保它们能够准确地测量产品尺寸和质量。有一天&#xff0c;小张发现量检具出现了一些问题。他注意到一些量具的读数不准确&#xff0c;导致生产出来…

【吊打面试官系列-Mysql面试题】NULL 是什么意思?

大家好&#xff0c;我是锋哥。今天分享关于 【NULL 是什么意思&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; NULL 是什么意思? 答&#xff1a;NULL 这个值表示 UNKNOWN(未知):它不表示“”(空字符串)。对 NULL 这个值的任何比较都会生产一个 NULL 值。您不能…

ABAP - SALV SET_ZERO方法不显示金额0.00

财务觉得报表上的金额为0的数据混淆视线&#xff0c;所以提出了报表不显示0.00的格式要求。 要求报表是这个样&#xff1a; SALV提供了 cl_salv_column_table->set_zero() 来进行控制金额0.00是否显示 实现SALV不显示金额0.00关键代码&#xff1a; DATA:lo_columns TYPE …