前言

  在unity中我们常用的获取鼠标点击的方法有:

  1、在3D场景中,一般用在Update方法中,每一帧调用

void Update(){
if(Input.GetMouseButtonDown()){
Debug.log("鼠标左键点击");
}
}

  2、在画布场景中,一般用在OnGUI方法中,这个也是一个循环调用的方法,这个方法在3D场景也可以触发点击事件

    void OnGUI()
{
Event e = Event.current;
if (e.isMouse && (e.clickCount == ))
{
Debug.Log("用户双击了鼠标");
}
}

  当我们想同时给一个游戏对象绑定单击、双击事件是就会一个问题,双击事件必然会触发至少一次单击事件,不管你点的有多快,因此我们需要引入定时器来解决这个问题

  定时器介绍

  MonoBehaviour简单介绍

using System;
using System.Collections;
using System.Runtime.CompilerServices;
using UnityEngine.Bindings;
using UnityEngine.Internal;
using UnityEngine.Scripting; namespace UnityEngine
{
//MonoBehaviour是每个Unity脚本派生的基类
public class MonoBehaviour : Behaviour
{
//检查当前是否有定时器
public bool IsInvoking() //取消所有定时器调用
public void CancelInvoke() //在time秒后,调用方法名为methodName的方法
public void Invoke(string methodName, float time) //在time秒后,调用方法名为methodName的方法,然后每repeatRate秒重复一次
public void InvokeRepeating(string methodName, float time, float repeatRate) //取消方法名为methodName的定时器调用
public void CancelInvoke(string methodName) //检查在方法名为methodName上是否有定时器调用
public bool IsInvoking(string methodName) //其他的介绍省略...
}
}

  MonoBehaviour是每个Unity脚本派生的基类,只要脚本引入了UnityEngine可以直接使用

  前面也有用System.Timers.Timer来实现,定时器也能正常触发,但有一个问题,在定时函数中,我无法访问gameObject,但是可以访问到我们的两个标识,很奇怪,如果有在函数中调用到gameObject等其他属性,程序也不打印报错信息,脚本直接终止,再点击对象已经没有反应,后面通过打断点调试发现,访问这些属性将会产生一个异常:Exception of type System.NotSupportedException,因此放弃使用这个定时器

  思路

  1、当触发点击,且点击对象为当前绑定脚本的对象才继续往下执行

  2、将单、双击标识设置取反,当前为false

  3、判断是否为新一轮

  4、触发定时器,在300毫秒后执行定时调用函数,同时锁定本次判断,再本次判断没结束之前不会触发定时器

  5、在函数里进行单、双击的判断(false单击、true双击),同时重置标识,开启下一轮

  那么在这300毫秒的时间里,如果我们再次点击将会执行到第二步,单、双击标识将会被设置成true,则定时调用函数的if分支就会走双击

  隐藏bug

  那么问题来了,如果有人手速非常快,他在300毫秒内点了好几下那岂不是会有问题?如果他点了两下,那定时调用函数的if分支又会走单击....

  这种情况下只能设置一个合适的触发时间来解决了

  最终脚本、效果

  C#脚本

using UnityEngine;

/**
* 鼠标点击事件绑定
*/
public class Click : MonoBehaviour
{
private Ray _ray;//物理射线相关 public RaycastHit _hit;//物理射线相关 private bool _first = true;//新一轮标识(或者也可以叫是否结束的标识) private bool _flag = true;//单击或双击的标识(默认单击) private void Update()
{
monitor();
} /**
* 鼠标单、双击监听
*/
private void monitor()
{
//触发鼠标左键点击
if (!Input.GetMouseButtonDown()) return; //射线检测到的对象是当前对象
if (Camera.main != null) _ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (!Physics.Raycast(_ray, out _hit) || _hit.collider.gameObject != gameObject) return; _flag = !_flag; //上一次的事件是否已经执行完毕,也就是判断是否为新一轮
if (!_first) return; _first = false; //初始化定时器,300毫秒后执行预定方法
Invoke("Timer", 0.3f);
} /**
* 定时调用函数
*/
private void Timer()
{
//进行判断
if (_flag)
{
OnDblclick();
}
else
{
OnClick();
} //定时调用结束,重置标识
_first = true;
_flag = true;
} /**
* 单击事件
*/
private void OnClick()
{
Debug.Log(gameObject.name + "单击事件被触发");
} /**
* 双击事件
*/
private void OnDblclick()
{
Debug.Log(gameObject.name + "双击事件被触发");
}
}

  把脚本绑定在具体的游戏对象即可,要注意的是,用物理射线检测是否点击的是当前对象,这个需要对象本身有Collider碰撞体组件,因为射线是与对象的碰撞体发生碰撞

  效果演示

  上图的鼠标操作流程:单击,双击,单击,双击,双击,单击;(具体打印情况看控制台右边的打印次数)

  更新脚本

  2020-05-15更新

  更新一下脚本,之前是一个脚本只能绑定一个对像,因为事件处理时直接写在脚本里的,现在改一下,改成事件处理需要传进来UnityEvent,这样一来绑定事件就更加灵活了

    using UnityEngine.Events;
using UnityEngine; /**
* 鼠标点击事件绑定,利用射线检测碰撞,需要对象本身有Collider碰撞体组件
*/
public class Click : MonoBehaviour
{
private Ray _ray;//物理射线相关 private RaycastHit _hit;//物理射线相关 private bool _first = true;//新一轮标识(或者也可以叫是否结束的标识) private bool _flag = true;//单击或双击的标识(默认单击) public UnityEvent OnClickListener; //单击事件监听 public UnityEvent OnDblclickListener; //双击事件监听 private void Update()
{
monitor();
} /**
* 鼠标单、双击监听
*/
private void monitor()
{
//触发鼠标左键点击
if (!Input.GetMouseButtonDown()) return; //射线检测到的对象是当前对象
if (Camera.main != null) _ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (!Physics.Raycast(_ray, out _hit) || _hit.collider.gameObject != gameObject) return; _flag = !_flag; //上一次的事件是否已经执行完毕,也就是判断是否为新一轮
if (!_first) return; _first = false; //初始化定时器,300毫秒后执行预定方法
Invoke("Timer", 0.3f);
} /**
* 定时调用函数
*/
private void Timer()
{
//进行判断
if (_flag)
{
OnDblclickListener.Invoke();
}
else
{
OnClickListener.Invoke();
} //定时调用结束,重置标识
_first = true;
_flag = true;
}
}

  如何使用

        //添加Click组件
Click gameObjectClick = gameObject.AddComponent<Click>(); //绑定单击事件
gameObjectClick.OnClickListener = new UnityEvent();
gameObjectClick.OnClickListener.AddListener(() =>
{
Debug.Log("单击获取对象名称:"+gameObject.name);
}); //绑定双击事件
gameObjectClick.OnDblclickListener= new UnityEvent();
gameObjectClick.OnDblclickListener.AddListener(() =>
{
Debug.Log("双击获取对象名称:"+gameObject.name);
});

  后记

  unity3D 游戏物体同时绑定单击、双击事件暂时记录到这,后续还可以进一步封装,使游戏对象绑定单、双击更加简单

unity3D 游戏物体同时绑定单击、双击事件的更多相关文章

  1. MVC中使用Echart后台加载数据 实现饼图、折线图、全国地图数据,单击双击事件等

    @{ Layout = null; } @if (false) { <script src="~/Js/jquery-easyui-1.5/jquery.min.js"> ...

  2. electron 系统托盘 单击 双击事件冲突解决方法

    部分代码 // 任务栏点击事件 let timeCount = 0 tray.on('click', function (Event) { setTimeout(() => { if (time ...

  3. unity3d游戏物体跟着鼠标方向移动

    效果:当点击鼠标左键时,游戏对象会朝鼠标点击的方向移动,类似魔兽争霸一样. 思路:把鼠标的坐标转化成世界坐标(鼠标默认是屏幕坐标),然后当点击鼠标时,物体将朝着鼠标的世界坐标方向移动. 如果你看到这的 ...

  4. [转] Ext Grid (ExtJs)上的单击以及双击事件

    例1: 1.双击 var cb = new Ext.grid.RowSelectionModel({ singleSelect:true //如果值是false,表明可以选择多行:否则只能选择一行 } ...

  5. easyui datagrid 自定义单元格单击与双击事件(Day_38)

    $(function(){ $('#tableId').datagrid({//单击事件   onClickRow:function(rowIndex,rowData){  alert("单 ...

  6. IE和Chrome执行javascript对鼠标双击事件的不同响应

    最近在用天地图API帮同学做点开发的工作,主要是基于天地图的API实现违法用地举报的在线地图标绘,要实现的效果如下: 由于是基于天地图API的TPolygonTool工具实现面积量测和多边形绘制功能, ...

  7. Unity3D学习笔记(一):Unity简介、游戏物体、组件和生命周期函数

    Project(工程.项目):工程是把游戏开发当前所需要的资源归类管理用的. Console控制台:日志.报错.调试,右上角,消息过滤 Assets:资源,存储游戏中一切用到的资源 Library:临 ...

  8. GridView/DataGrid行单击和双击事件实现代码_.Net教程

    功能: 单击选中行,双击打开详细页面 说明:单击事件(onclick)使用了 setTimeout 延迟,根据实际需要修改延迟时间 ;当双击时,通过全局变量 dbl_click 来取消单击事件的响应  ...

  9. [Unity3D]Unity3D游戏开发之在3D场景中选择物体并显示轮廓效果

    大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei. 在<仙剑奇侠传>.<古剑奇谭>等游戏中,常常须要玩家在一个3D场景中 ...

随机推荐

  1. AtCoder Grand Contest 036 A-C

    目录 \(\bf A - Triangle\) \(\bf B - Do\ Not\ Duplicate\) \(\bf C - GP 2\) \(\bf D - Negative \ Cycle\) ...

  2. [考试反思]0828NOIP模拟测试32:沉底

    ,,190,180,170,170... 倒数第6,75. 啊...再这么下去要失去理想了... 开学翘课停课以来的第一场考试,就考成这鬼模样. 本来还可以凭借那几次高分苟在公共卷总分的第2,这一场直 ...

  3. csp模拟69

    考试一眼看出$T3$原题,但是没做过,心态爆炸. 然后去看$T1$,迷之认为它是矩阵快速幂?推了一个小时,发现在转移过程中方案数并不均匀分布,然后就挂了. 决定先去看T3,只会$O(n\sqrt{n} ...

  4. NOIP模拟 34

    次芝麻,喝喝喝,长寿花! 什么鬼畜题面...一看就不是什么正经出题人 skyh双双双AK了..太巨了... T1 次芝麻 稍稍手玩就能发现分界点以一个优美的方式跳动 然后就愉快地帮次货们次掉了这个题- ...

  5. css实现鼠标悬浮后的提示效果

    一.概述 很多时候网站中需要在鼠标划过小图标时,悬浮出提示性的文字.比如下图: 鼠标悬浮后的效果 这种效果可以使用css中的伪类hover来实现.但有时候搞不清两个元素的嵌套关系.使用了hover却没 ...

  6. linux常用的命令解释

    1.man命令的操作按键: 按键 用处 空格键 向下翻一页. [Page Down] 向下翻一页. [Page Up] 向上翻一页. [HOME] 直接前往首页. [END] 直接前往尾页. /关键词 ...

  7. 从Gartner IT Symposium,看RPA“一半是海水一半是火焰”

    2019年,艺赛旗和Gartner建立了咨询合作,并在企业发展策略中汲取了Gartner的部分建议.今年Gartner在全球召开了多场IT Symposium,并在Symposium发布2020的相关 ...

  8. nginx recv() failed (104: Connection reset by peer) while reading response header from upstream解决方法

    首先说下 先看 按照ab 每秒请求的结果 看看 都有每秒能请求几个 如果并发量超出你请求的个数 会这样 所以一般图片和代码服务器最好分开 还有看看io瓶ding 和有没有延迟的PHP代码执行 0 先修 ...

  9. nyoj 56-阶乘因式分解(一)(数学)

    56-阶乘因式分解(一) 内存限制:64MB 时间限制:3000ms Special Judge: No accepted:15 submit:16 题目描述: 给定两个数m,n,其中m是一个素数. ...

  10. 开始逆向objc基础准备(二)我的平台是simulator-x86_64

    建项目运行中断调试,lldb中显示寄存器看到有rax-r15, stm0-stm7, xmm0-xmm15, ymm0-ymm15,即为x64体系支持sse4. 再在lldb中查看寄存器别名得到以下对 ...