UnityVR--EventManager--事件中心3

news2024/12/23 15:38:40

前期准备

  接上一篇,来实现事件中心的管理:使用定义好的事件中心管理器EventManager,实现鼠标拖拽、角色移动、发射子弹等几个功能。

  1. InputSystem的准备:需要设置输入设备并关联事件,比如监听键盘输入"WASD"事件实现角色移动的回调,监听鼠标点击事件实现拖拽物体移动等。详见插件1--新版InputSystem;

  2. 需要使用并修改之前的几个脚本:

    (1)修改Rigidbody--移动控制当中控制角色移动的方法;

    (2)在Ray/Raycast/Linecast/OverlapSphere中点击拖拽物体的方法不再需要了,更新为使用事件监听判断鼠标按键;

    (3)开火的功能,也不需要if去判断按键,修改为监听开火Fire事件。

  以下开始一个一个地实现:

控制移动

  在Rigidbody--移动控制当中使用Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")的方式获取键盘WASD的输入数据,在有了事件中心后,改为采用注册移动事件的方式,发送并回传一个位置的参数。写一个HeroMoveEvent.cs脚本:

//注册一个移动的事件
public class HeroMoveEvent : MonoBehaviour
{
    private Rigidbody rb;
    private Vector2 moveInput; //接收回传的参数
    private Vector3 movement;//移动的坐标位置(将之前的二维坐标转成这里的三维)
    private Quaternion targetRotation;
    public float moveSpeed = 2;
    public float rotateSpeed = 2;
    GameObject Bullet;
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        EventManager.Instance.AddEvent(EventType.OnPlayerMove, this, data =>
        { //注册一个移动的事件,监听者是HeroMoveEvent(本类),这个事件由
          //InputManager中的OnMove()发送给场景中的PlayerInput

            var eventData = data as EventDataPlayerMove;
            //EventData参数转为EventDataPlayerMove类型

            moveInput = eventData.position; 
            //移动的距离由EventDataPlayerMove中的position变量决定
        });
    }

    void FixedUpdate()
    {
        //moveInput = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")); //之前使用Input拿到的水平、垂直方向数据

        //使用事件后,通过回传的EventData数据赋值给moveInput变量
        movement.Set(moveInput.x, 0, moveInput.y);//得到移动的坐标
        movement.Normalize();

        //检测是否有输入
        bool hInput = !Mathf.Approximately(moveInput.x, 0);
        bool vInput = !Mathf.Approximately(moveInput.y, 0);
        if (hInput || vInput)
        {
            movement = Quaternion.Euler(0, Camera.main.transform.eulerAngles.y, 0) * movement;
        }
        Vector3 lookForward = Vector3.RotateTowards(transform.forward, movement, rotateSpeed * Time.fixedDeltaTime, 360);
        targetRotation = Quaternion.LookRotation(lookForward);
        rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
        rb.MoveRotation(targetRotation);
    }

  注册事件后,需要发送事件,以及在PlayerInput中绑定它(详见插件1--新版InputSystem中的添加并绑定移动事件)在脚本中建立一个方法OnMove(),用于发送OnPlayerMove事件:

    public void OnMove(InputAction.CallbackContext context)
    {//绑定PlayerInput中的PlayerMap-Move事件
        EventManager.Instance.SendEvent(EventType.OnPlayerMove, new EventDataPlayerMove()
        {//发送事件
            position=context.ReadValue<Vector2>()  //返回context参数
        });
    }

并且在场景中的PlayerInput->Event->PlayerMap->Move中绑定这个方法:

 

控制鼠标点击拖拽物体

  拖拽的方式还是使用Ray/Raycast/Linecast/OverlapSphere中的方法应用2:实现鼠标点击拖拽物体,使用射线检测是否点击到物体,如果以及点击到了,就将鼠标输入的XY坐标位置转换为物体的XZ场景位置。不同的是,这里改为监听鼠标点击的事件,不再在update()中判断鼠标的输入状态。同样,也需要在InputSystem中设置鼠标按键。步骤如下:

  1. 参照新版InputSystem的设置,在InputControl中添加LeftMouseClick、LeftMouseUp和MouseDrag三个Action,设置如下:

 

  

   2. 注册添加鼠标拖拽事件,并且定义回调函数,回调函数的内容与Ray/Raycast/Linecast/OverlapSphere一文中的应用2:实现鼠标点击拖拽物体类似,主要就是利用从摄像机向鼠标位置射出的射线,判断是否点击到物体:

public class MouseClick : MonoBehaviour
{
    private Ray ray;  //定义射线
    private Transform clicked; //被鼠标点击的物体

    void Start()
    {//注册鼠标输入事件
        EventManager.Instance.AddEvent(EventType.OnMouseInput, this, MoveGameObject);
    }

    //定义回调函数
    void MoveGameObject(EventDataBase data)
    {
        var eventData = data as EventDataMouseInput;
        var state = eventData.State; //检测鼠标状态
        var key= eventData.Key;  //检测鼠标按键

        if(key==EMouseInputKey.Left&&state==EMouseInputState.Down)
        {//当检测到左键、按下
            ray = Camera.main.ScreenPointToRay(eventData.MousePosition);
            //使用事件数据库传入的二维向量参数,做一套从屏幕射向鼠标位置的射线
            Physics.Raycast(ray, out RaycastHit hit, 100, LayerMask.GetMask("Enemy"));
            if (hit.collider != null)
            {//被点击中的物体,赋值给Click变量,准备之后被鼠标拖拽
                clicked = hit.transform; 
                var wPos = Tools.MouseToWorld(clicked.position);
                //使用工具集中的坐标转换,将鼠标坐标转为世界坐标
            }
        }

        if(key == EMouseInputKey.Left && state == EMouseInputState.Stay)
        {//鼠标左键停留持续按下的状态
            if (clicked != null)
            {
                Vector3 pos = Tools.MouseToWorld(clicked.position);
                clicked.position = new Vector3(pos.x , clicked.position.y, 
                    pos.z);
            }
        }
        if (key == EMouseInputKey.Left && state == EMouseInputState.Up)
        {//鼠标抬起
            clicked= null;
        }
    }
}

 3. 发送事件,建立一个新脚本,或者我直接放在InputManager.cs中,管理所有输入事件(详见InputManager),这个脚本挂在场景中的SingleMono上。这里写了三个发送事件方法,“左键点击”、“左键拖拽”、“左键释放”:

public class InputManager : SingleMono<InputManager>
{
    public void OnLeftMouseClick(InputAction.CallbackContext context)
    {
         //Debug.LogError("发送鼠标左键单击世界事件");
         //鼠标点击世界左键按下事件,可以在任何一个地方监听这个事件
         EventDataMouseInput mouseInput= new EventDataMouseInput(EMouseInputKey.Left,
         EMouseInputState.Down,Input.mousePosition);
         EventManager.Instance.SendEvent(EventType.OnMouseInput, mouseInput);
    }
    public void OnMouseDrag(InputAction.CallbackContext context)
    {
         //Debug.LogError("鼠标左键持续点击世界事件");
         EventManager.Instance.SendEvent(EventType.OnMouseInput, new EventDataMouseInput()
        {
          State = EMouseInputState.Stay,
          Key = EMouseInputKey.Left,
          MousePosition = context.ReadValue<Vector2>()
        });
    }
    public void OnLeftMouseUp(InputAction.CallbackContext context)
    {
        //Debug.LogError("发送鼠标左键抬起事件");
        EventManager.Instance.SendEvent(EventType.OnMouseInput, new EventDataMouseInput
            (EMouseInputKey.Left, EMouseInputState.Up, Input.mousePosition));
    }
}

  4. 上面3中定义的“左键点击”、“左键拖拽”、“左键释放”三个方法,在场内的PlayerInput组件中,绑定到上面1中添加的LeftMouseClick、LeftMouseUp和MouseDrag三个Action上,详见新版InputSystem中的方法,这里简单放一下设置结果:

 

   5. 运行结果,与Ray/Raycast/Linecast/OverlapSphere中应用2:实现鼠标点击拖拽物体相同

 添加开火事件

  在新版InputSystem中有详细的方法,这里放一下简单的步骤和脚本:

  1. 注册事件:

public class BulletFireEvent : MonoBehaviour
{
        public GameObject bullet;
        void Start()
        {
            EventManager.Instance.AddEvent(EventType.OnPlayerFire, this, callback =>
            {
                bullet = Resload.Instance.LoadPrefab("Bullet");
                bullet.SetActive(true);
                bullet.transform.position = transform.position;
                bullet.transform.rotation = transform.rotation;
                Destroy(bullet, 2);
            });
        }
    }

  2. 发送事件,这里写在上面的InputManager.cs中

    public void OnFire(InputAction.CallbackContext context)
    {//绑定新版InputSystem中的PlayerMap-Fire事件
        EventManager.Instance.SendEvent(EventType.OnPlayerFire, null);
    }

  3. 在场景中PlayerInput组件中绑定OnFire事件,详见新版InputSystem中的设置方法:

 

  效果与之前的开火效果相同,就不放效果图了。

总结

  可以比较一下使用“事件”和不使用“事件”的代码,比如在Ray/Raycast/Linecast/OverlapSphere一篇中的应用2:实现鼠标点击拖拽物体,和本篇的鼠标点击拖拽事件相比较,前者在update()中用了3个If判断鼠标的状态,而后者没有使用update(),因此在节约性能方面,事件中心的建立和使用更胜一筹。

  更重要的是,如果在建立一个较大项目时,事件中心的优点就更能体现出来了,否则代码量会非常庞大。

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

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

相关文章

自制操作系统第三站

修改haribote.nas&#xff0c;界面显示 ; haribote.nas ; TAB4ORG 0xc200MOV AL, 0x13MOV AH, 0x00INT 0x10fin:HLTJMP fin编译运行

MySQL存储引擎概述

前言&#xff1a;MySQL语句执行流程为&#xff1a;SQL语句→查询缓存→解析器→优化器→执行器&#xff08;执行器会调用执行引擎API&#xff09;&#xff1b;人们把“连接管理、查询缓存、语法解析、查询优化”这些并不涉及真实数据存储的功能划分为MySQL server的功能&#x…

TiDB亿级数据亚秒响应查询整体架构

目录 1 TiDB的优势2 TiDB的组件2.1 TiDB Server2.2 PD (Placement Driver) Server2.3 TiKV Server2.4 TiSpark2.5 TiFlash 3 TiKV整体架构3.1 Region分裂与合并3.2 Region调度3.3 分布式事务 4 高可用架构4.1 TiDB高可用4.2 PD高可用4.3 TiKV高可用 5 应用场景5.1 MySQL分片与合…

在地质区划图上绘制伪震中

import numpy as np import matplotlib.pyplot as plt #matplotlib inline from matplotlib import image from matplotlib import pyplot as plt import cv2 # 解析文件&#xff0c;按空格分割字段&#xff0c;得到一个浮点数字类型的矩阵 def loadDataSet(fileName): dataMa…

chatgpt赋能python:Python办公自动化:优化SEO工作效率的关键

Python办公自动化&#xff1a;优化SEO工作效率的关键 随着互联网的不断发展&#xff0c;SEO已经成为了许多企业在网络中展示自己的必备手段。然而&#xff0c;SEO工作需要大量重复性、繁琐的操作&#xff0c;如关键词排名、竞争对手分析、数据收集等&#xff0c;这些工作占据了…

一文说透ES6中的箭头函数表达式

一 总述 ​箭头函数表达式的语法比函数表达式更简洁&#xff0c;并且没有自己的this&#xff0c;arguments&#xff0c;super或new. target。箭头函数表达式更适用于那些本来需要匿名函数的地方&#xff0c;并且它不能用作构造函数。 二 详细 1 1个或多个参数 (param1, par…

【数据结构每日一题】队列——用栈实现队列

[数据结构习题]队列——用栈实现队列 &#x1f449;知识点导航&#x1f48e;&#xff1a;【数据结构】栈和队列 &#x1f449;[王道数据结构]习题导航&#x1f48e;&#xff1a; p a g e 85.3 page85.3 page85.3 本节为栈和队列的综合练习题 题目描述&#xff1a; &#x1f…

【AI绘图】五、stable diffussion模型的介绍与使用

1. 下载模型 主流模型下载网站&#xff1a; 1&#xff09;Hugging face 是一个专注于构建、训练和部署先进开源机器学习模型的网站&#xff1a; https://huggingface.co/ 2&#xff09;Civitai 是一个专为 Stable Diffusion AI 艺术模型设计的网站&#xff1a; https://civi…

Python数据分析script必备知识(四)

Python数据分析script必备知识(四) 1.保留最近N天的日志 1.批量创建多个文件 首先,为演示方便,在指定文件夹目录下用下面代码批量新建多个log文件 """ 批量创建多个文件 """ import os file_path = os.path.join(os.getcwd(),LOG) # 如果不…

「详细教程」使用git将本地项目上传至Github仓库(MacOS为例)

前言&#xff1a;最近需要将自己的代码开源至自己的Github仓库&#xff0c;然而发现并没有一键上传文件夹的选项&#xff0c;于是参考现有教程进行了实践&#xff0c;成功✌️以下是详细步骤。 Tips&#xff1a;在文章录用之后&#xff0c;小伙伴们可以选择将自己的代码开源&am…

QMessageBox信息模态对话框详细使用教程,对象创建栈和指针类型,对话框的风格样式设置,不要浪费实时间自己封装了,图文并茂,看图说话。

QMessageBox 界面设计图展示效果【1】PC端使用QMessageBoxinformation &#xff08;常规信息&#xff09;warning &#xff08;警告消息&#xff09;critical &#xff08;错误信息&#xff09;about (关于信息&#xff0c;无按钮)question &#xff08;问题信息&#xff1f;&a…

Android开发 LogDog (日志狗)V2.0.0

目录 一、简介 二、使用推荐 1、初始化LogDog 2、运行中如何更改初始化时的配置&#xff1f; 三、更改 四、新功能 1、Log过滤 2、自定义打印 3、提供占位符式打印 一、简介 LogDog V1.0 版本https://blog.csdn.net/Ym_quiet/article/details/130453232?spm1001.2014…

javascript基础二十六:JavaScript中如何实现函数缓存?有哪些应用场景?

一、是什么 函数缓存&#xff0c;就是将函数运算过的结果进行缓存 本质上就是用空间&#xff08;缓存存储&#xff09;换时间&#xff08;计算过程&#xff09; 常用于缓存数据计算结果和缓存对象 const add (a,b) > ab; const calc memoize(add); // 函数缓存 calc(1…

Linux邮件发送教程:深入了解mail命令

前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&#xff0c;本文是专栏【linux基本功-基础命令实战】的第59篇文章。 专栏地址&#xff1a;[linux基本功-基础命令专栏] &#xff0c; 此专栏是沐风晓月对Linux常用命令的汇总&#xff0c;希望能够加深自己的印象&am…

Java进行公众号开发的常见使用场景及解决方案

Java进行公众号开发的常见使用场景解决方案 文章简介 本文总结了本人在开发过程中遇到的有关于微信开发的诸多常见功能&#xff0c;这些问题在网上找都是零散的回答&#xff0c;所以再此总结一下&#xff0c;方便后续开发。如果有错误之处&#xff0c;还望批评指出&#xff0…

使用Kaggle GPU资源免费体验Stable Diffusion开源项目

使用Kaggle GPU资源免费体验Stable Diffusion开源项目 前言相关介绍Stable Diffusion Kaggle开源项目编辑并复制项目运行项目打开网址&#xff0c;即可体验 参考 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩内容&#xff0c;可点击进入Y…

javascript基础二十五:说说你对函数式编程的理解?优缺点?

一、是什么 函数式编程是一种"编程范式"&#xff08;programming paradigm&#xff09;&#xff0c;一种编写程序的方法论 主要的编程范式有三种&#xff1a;命令式编程&#xff0c;声明式编程和函数式编程 相比命令式编程&#xff0c;函数式编程更加强调程序执行…

C SS复习笔记

1.img标签 img的src属性是图片显示不出来时显示的文字 ing的title属性是光标放到图片上&#xff0c;提示的文字 2.a标签 a标签的target属性表示打开窗口的方式&#xff0c;默认的值是_self表示当前窗口的打开页面&#xff0c;_blank表示新窗口打开页面。 a标签的href链接分…

2023.06.04 学习周报

文章目录 摘要文献阅读1.题目2.背景3.方案4.本文贡献5.模型5.1 图注意力形式5.2 superGAT 6.实验7.结论 有限元数学建模深度学习1.高斯扩散2.原理 总结 摘要 This week, I read a computer science about GNN. At present, the attention mechanism of graph neural network i…

Go Web下GORM框架使用(二)

〇、前言 本文将会写一个前后端分离的的小项目&#xff0c;本文将会只实现后端。 一、定义全局变量与模型 本文需要一个数据库&#xff0c;因此将这个数据库定义为全局变量将会非常轻松。 var (DB *gorm.DB )type Todo struct {ID int json:"id"Title s…