当前位置: 代码网 > it编程>编程语言>Asp.net > 【Unity知识点详解】Button点击事件拓展,单击、双击、长按实现

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

2024年08月01日 Asp.net 我要评论
根据需求我们要实现点击、双击、长按、长按开始、长按结束事件的回调,所以在代码中我们提供了OnClick、OnDoubleClick、OnPressBegin、OnPress、OnPressEnd回调方法。首先我们来认识一下Selectable这个类,Selectable是所有交互组件的基类,Unity原生的Button组件就是继承了Selectable,我们要拓展Button功能也是对Selectable下的OnPointerDown、OnPointerUp等接口进行重写。

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

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com