【Unity知识点详解】Button点击事件拓展,单击、双击、长按实现

这篇具有很好参考价值的文章主要介绍了【Unity知识点详解】Button点击事件拓展,单击、双击、长按实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Button拓展

        今天来聊一下关于Button的事件拓展,这里只是拿Button来举例,Unity中其他的UI组件如Toggle、Slider等都也适用。

        我们知道在Button中我们可以通过onClick的方式来添加点击事件,但在游戏开发过程中我们往往对Button有着更多的功能需求,比如说双击、长按、按钮按下、按钮弹起等。这里举一个游戏中实际的例子,在游戏背包中的道具,单击道具时我们需要显示道具的tips框,双击时我们会去使用道具,长按时我们则可以拖动道具,当长按弹起时则道具回到原位或移动到新格子内。虽然这里的背包道具不是按钮,但在单个UI组件上集合了单击、双击、长按、按钮弹起等事件的响应。接下来将介绍如何拓展UI组件来实现这些功能。

        首先我们来认识一下Selectable这个类,Selectable是所有交互组件的基类,Unity原生的Button组件就是继承了Selectable,我们要拓展Button功能也是对Selectable下的OnPointerDown、OnPointerUp等接口进行重写。

        话不多说先上代码,代码有点长大家可以先跳过细节,后面慢慢讲解。

using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;


public class ExButton : Button
{
    private enum EnumExButtonState
    {
        /// <summary>空</summary>
        None,
        /// <summary>鼠标按下</summary>
        PointerDown,
        /// <summary>鼠标按下</summary>
        PointerUp,
        /// <summary>单击</summary>
        Click,
        /// <summary>双击</summary>
        DoubleClick,
        /// <summary>长按开始</summary>
        PressBegin,
        /// <summary>长按</summary>
        Press,
        /// <summary>长按结束</summary>
        PressEnd,
    }

    /// <summary>按钮状态</summary>
    private EnumExButtonState mButtonState = EnumExButtonState.None;
    /// <summary>鼠标按下时间</summary>
    private float mPointerDownTime = 0.0f;
    [SerializeField]
    /// <summary>双击间隔时间</summary>
    private float mDoubleClickInterval = 0.2f;
    [SerializeField]
    /// <summary>长按开始时间</summary>
    private float mPressBeginTime = 0.3f;
    [SerializeField]
    /// <summary>长按间隔时间,0为每帧调用</summary>
    private float mPressIntervalTime = 0.2f;
    /// <summary>长按缓存时间</summary>
    private float mPressCacheTime = 0f;

    public Action OnClick { get; set; }
    public Action OnDoubleClick { get; set; }
    public Action OnPressBegin { get; set; }
    public Action OnPress { get; set; }
    public Action OnPressEnd { get; set; }

    public override void OnPointerDown(PointerEventData eventData)
    {
        base.OnPointerDown(eventData);

		if (OnDoubleClick != null)
		{
			if (mButtonState == EnumExButtonState.None)
			{
				mButtonState = EnumExButtonState.PointerDown;
				mPointerDownTime = Time.time;
			}
			else if (mButtonState == EnumExButtonState.PointerUp)
			{
				if (Time.time - mPointerDownTime < mDoubleClickInterval)
				{
					mButtonState = EnumExButtonState.DoubleClick;
					return;
				}
				else
				{
					mButtonState = EnumExButtonState.PointerDown;
					mPointerDownTime = Time.time;
				}
			}
		}

		if (OnPressBegin != null || OnPress != null || OnPressEnd != null)
		{
			if (mButtonState != EnumExButtonState.DoubleClick)
			{
				mButtonState = EnumExButtonState.PointerDown;
				mPointerDownTime = Time.time;
			}
		}

		if (OnClick != null)
		{
			mButtonState = EnumExButtonState.PointerDown;
		}
    }

    public override void OnPointerUp(PointerEventData eventData)
    {
        base.OnPointerUp(eventData);

		if (OnDoubleClick != null)
		{
			if (mButtonState == EnumExButtonState.PointerDown)
			{
				mButtonState = EnumExButtonState.PointerUp;
				return;
			}
			else if (mButtonState == EnumExButtonState.DoubleClick)
			{
				return;
			}
		}

		if (OnPressBegin != null || OnPress != null || OnPressEnd != null)
		{
			if (mButtonState == EnumExButtonState.Press)
			{
				mButtonState = EnumExButtonState.PressEnd;
				return;
			}
		}

		if (OnClick != null)
		{
			if (mButtonState == EnumExButtonState.PointerDown)
				mButtonState = EnumExButtonState.PointerUp;
		}
    }

    private void Update()
    {
        ProcessUpdate();
        ResponseButtonState();
    }

    private void ProcessUpdate()
    {
        if (OnDoubleClick != null) { }

        if (OnPressBegin != null || OnPress != null || OnPressEnd != null)
        {
            if (mButtonState == EnumExButtonState.PointerDown)
            {
                if (Time.time - mPointerDownTime > mPressBeginTime)
                {
                    mButtonState = EnumExButtonState.PressBegin;
                    mPressCacheTime = 0f;
                    return;
                }
            }
        }

        if (OnClick != null)
        {
            if (mButtonState == EnumExButtonState.PointerUp)
            {
                if (OnDoubleClick != null)
                {
                    if (Time.time - mPointerDownTime > mDoubleClickInterval)
                        mButtonState = EnumExButtonState.Click;
                }
                else
                {
                    mButtonState = EnumExButtonState.Click;
                }
            }
        }
    }

    private void ResponseButtonState()
    {
        switch (mButtonState)
        {
            case EnumExButtonState.None:
                break;
            case EnumExButtonState.Click:
                OnClick?.Invoke();
                mButtonState = EnumExButtonState.None;
                break;
            case EnumExButtonState.DoubleClick:
                OnDoubleClick?.Invoke();
                mButtonState = EnumExButtonState.None;
                break;
            case EnumExButtonState.PressBegin:
                OnPressBegin?.Invoke();
                mButtonState = EnumExButtonState.Press;
                break;
            case EnumExButtonState.Press:
                {
                    mPressCacheTime += Time.deltaTime;
                    if (mPressCacheTime >= mPressIntervalTime)
                    {
                        mPressCacheTime = mPressCacheTime - mPressIntervalTime;
                        OnPress?.Invoke();
                    }
                    break;
                }
            case EnumExButtonState.PressEnd:
                OnPressEnd?.Invoke();
                mButtonState = EnumExButtonState.None;
                break;
            default:
                break;
        }
    }
}

        ExButton组件功能的拓展需要继承自Button类,并且重写OnPointerDown、OnPointerUp方法(这里根据需求只重写了OnPointerDown、OnPointerUp方法,大家可以根据自己的需求重写Selectable下的方法)。根据需求我们要实现点击、双击、长按、长按开始、长按结束事件的回调,所以在代码中我们提供了OnClick、OnDoubleClick、OnPressBegin、OnPress、OnPressEnd回调方法。

public Action OnClick { get; set; }
public Action OnDoubleClick { get; set; }
public Action OnPressBegin { get; set; }
public Action OnPress { get; set; }
public Action OnPressEnd { get; set; }

        逻辑采用了单状态机来实现,在OnPointerDown、OnPointerUp、Update方法中去改变成员mButtonState的状态,最终在ResponseButtonState方法中根据mButtonState的状态去进行事件的回调。

        在逻辑中也进行了事件回调的优化处理,当OnClick、OnDoubleClick、OnPressBegin、OnPress、OnPressEnd所有回调都被注册时,会优先处理OnDoubleClick,其次是OnPressBegin、OnPress、OnPressEnd,最后才是OnClick。例如当OnDoubleClick未被注册时,则会跳过OnDoubleClick对应的逻辑判断,提前处理并响应其他回调事件。

        

base.OnPointerDown、base.OnPointerUp

public override void OnPointerDown(PointerEventData eventData)
{
	base.OnPointerDown(eventData);
}

public override void OnPointerUp(PointerEventData eventData)
{
	base.OnPointerUp(eventData);
}

        在重写OnPointerDown、OnPointerUp后如需保留原有功能,需要调用base.OnPointerDown、base.OnPointerUp方法。只有调用基类方法,按钮的按下颜色改变才会有效果,当然这些基类方法也可以在别处调用。

官方文档连接

Selectable文档连接:https://docs.unity3d.com/Packages/com.unity.ugui@2.0/manual/script-Selectable.html

Selectable类API文档连接:https://docs.unity3d.com/Packages/com.unity.ugui@2.0/api/UnityEngine.UI.Selectable.html?q=selectable文章来源地址https://www.toymoban.com/news/detail-846488.html

到了这里,关于【Unity知识点详解】Button点击事件拓展,单击、双击、长按实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【unity知识点】Unity 协程Coroutine

    Unity 协程是一种特殊的函数,可以在游戏中实现延迟执行、按顺序执行和异步操作等功能。它使用了迭代器(Iterator)的概念,通过 yield 来控制执行流程。下面是 Unity 协程的使用和使用场景的详细介绍。 在脚本中定义一个协程方法,返回值类型为 IEnumerator 。 在协程方

    2024年02月01日
    浏览(37)
  • unity开发知识点小结02

    虚拟轴就是一个数值在-1 1内的轴,这个数轴上重要的数值就是-1,0和1。当使用按键模拟一个完整的虚拟轴时需要用到两个按键,即将按键1设置为负轴按键,按键2设置为正轴按键。在没有按下任何按键的时候,虚拟轴的数值为0;在按下按键1的时候,虚拟轴的数值会从0 -1进行

    2024年02月07日
    浏览(45)
  • Unity知识点 -- AssetBundle(AB包)

    特定于平台的资产压缩包,类似于压缩文件 资产包括:模型、贴图、预制体、音效、材质球等 2.1 相对于 Resources 下的资源,AB 包更好管理资源 Resource:打包时定死,只读,无法修改 AB包:存储位置可以自定义,压缩方式可以自定义,后期可以动态更新,通过 AB 包可以做热更

    2024年02月13日
    浏览(43)
  • Unity3D知识点精华浓缩

    一、细节 1、类与组件的关系 2、Time.deltaTime的含义 3、怎么表示一帧的移动距离 4、Update和LateUpdate的区别和适用场景 5、找游戏对象的方式(别的对象 / 当前对象的子对象) 6、组件1调用组件2中方法的方式 7、在面板中获取外部数据的方法 8、序列化属性、序列化自定义对象的

    2024年04月09日
    浏览(39)
  • 详解MVCC相关知识点

    前言:学习前,先叙述mysql相关基础知识,一步步了解mysql底层机制。 数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read committed、Repeatable read 、Serializable ,这四个级别可以逐个解决脏读 、不可重复读 、幻读 这几类问题。 √: 可能出现    ×: 不会出现

    2024年02月06日
    浏览(42)
  • pgzero所有知识点详解

    目录  什么是pgzero? pgzero的安装 4,正式开始! 1,调整背景色 2,导入角色 3,鼠标事件 5,按键事件 6,刷新功能 1,角色属性 2,功能介绍 7,全局变量and局部变量 1,全局变量与局部变量的区别 2,全局变量如何在功能内使用 8,角色功能及窗口功能 1,角色功能 2,窗口功

    2024年02月05日
    浏览(40)
  • 基于Qt数据库项目实现(Sqlite3为例)|考查数据库、绘制(画家)、事件等知识点(进阶)

    坚持最初的梦想,扬帆起航,乘风破浪,永不言败。 01 数据库 数据库是什么?简易言之,就是保存数据的文件。可以存储大量数据,包括插入数据、更新数据、截取数据等。用专业术语来说,数据库是“按照数据结构来组织、存储和管理数据的仓库”。是一个长期存储在计

    2024年02月19日
    浏览(45)
  • javascript打飞机程序8x8x飞机大战js打飞机程序,飞机大战知识点包含了JavaScript面向过程的全部知识点,包括变量、运算符、判断、循环、数组、自定义函数、系统函数、事件等。...

    讲解了JavaScript编程语言制作游戏界面,添加游戏控制、制作元素动画、制作多元素场景,添加碰撞功能、制作精灵动画等功能 源码如下: html:

    2024年02月16日
    浏览(64)
  • Spring AOP知识点详解

    Spring AOP是 Spring最核心的能力,那到底什么是AOP呢,今天了不起带大家了解一下。 AOP(Aspect Oriented Programming): 面向切面编程 ,是OOP(面向对象编程)的一个延续,其和OOP一样,也是一种编程思想,不过AOP是一种横向开发模式。 OOP ,面向对象,允许开发者定义纵向的关系,但并适

    2024年02月16日
    浏览(53)
  • 【unity数据持久化】XML数据管理器知识点

    👨‍💻个人主页 :@元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏 :Unity基础实战 XML是什么 XML(Extensible Markup Language)是一种类似于 HTML,但是没有使用预定义标记的语言。因此,可以根据自己的设计需求

    2024年02月11日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包