Unity之QTE快速反应事件

26 篇文章 1 订阅
9 篇文章 1 订阅

今天给各位带来的是游戏中一种常见的交互玩法---------QTE玩法。首先给大家解释一些什么是QTE呢?玩过PS游戏的都知道,里面有许多的QTE事件,手游上面不能说是没有,只是比较少。QTE是Quick Time Event(快速反应事件)的缩写。要求玩家要对游戏画面上出现的按键迅速作出反应,并按下与画面所对应的按键,其出现的按键有单个的按键也有组合按键。这就是QTE玩法了。那么如何在我们的unity中实现我们的QTE效果呢?

废话不多说,直接看代码吧!
不过前提是大家需要拼接好指针这样的QTE的UI界面哦,毕竟是一个2D的界面。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestQTE : MonoBehaviour
{
    private void Awake()
    {
        _Init();
    }

    private void Start()
    {
        //调用示范
        OpenQteView(KeyCode.O, () => PressQTE(), 50, () =>
        {
            Debug.Log("未及时按下键QTE按键失败");
        }, () =>
        {
            Debug.Log("QTE按键成功");
        });
    }

    /// <summary>
    /// QTE按键的类型
    /// </summary>
    enum E_QTEKey
    {
        Triangle = 0,
        Circle = 1,
        Squre = 2,
        Cross = 3
    }

    WildQTEBtn[] wildQteBtns;
    Dictionary<KeyCode, int> btnMap;
    KeyCode key;
    protected void _Init()
    {
        //初始化不同类型的按键对应的形状的按钮
        wildQteBtns = new WildQTEBtn[] {
                new WildQTEBtn(KeyCode.Q, transform.Find("Btn01")),
                new WildQTEBtn(KeyCode.T, transform.Find("Btn02")),
                new WildQTEBtn(KeyCode.O, transform.Find("Btn03")),
                new WildQTEBtn(KeyCode.K, transform.Find("Btn04"))
            };

        btnMap = new Dictionary<KeyCode, int>();
        btnMap.Add(KeyCode.Q, (int)E_QTEKey.Triangle);
        btnMap.Add(KeyCode.T, (int)E_QTEKey.Circle);
        btnMap.Add(KeyCode.O, (int)E_QTEKey.Squre);
        btnMap.Add(KeyCode.K, (int)E_QTEKey.Cross);
    }

    /// <summary>
    /// 打开QTE视图
    /// </summary>
    /// <param name="key">绑定的键名</param>
    /// <param name="BindKeyCommand">绑定的键要执行的事情</param>
    /// <param name="areaAngle">qQTE区域触发的角度</param>
    /// <param name="failCallback">失败的回调</param>
    /// <param name="successCallBack">成功的回调</param>
    public void OpenQteView(KeyCode key, Action BindKeyCommand, int areaAngle, Action failCallback, Action successCallBack)
    {
        this.key = key;
        if (btnMap.ContainsKey(key))
        {
            WildQTEBtn qteBtn = wildQteBtns[btnMap[key]];
            qteBtn.BindKeyUpExcuteCommand(BindKeyCommand);
            qteBtn.angle = 0;
            qteBtn.isRotation = true;
            qteBtn.Open(areaAngle, () =>
            {
                qteBtn.angle = 0;
                failCallback?.Invoke();
            }, () =>
            {
                if (null != successCallBack)
                    successCallBack();
            });
            Open();
        }
        else
        {
            Debug.LogError("QteView Error ");
        }
    }

    public void PressQTE()
    {
        WildQTEBtn qteBtn = wildQteBtns[btnMap[key]];
        qteBtn.IsPerss = true;
    }

    private void Open()
    {

    }

    private void Close()
    {
        if (btnMap.ContainsKey(key))
        {
            WildQTEBtn qteBtn = wildQteBtns[btnMap[key]];
            qteBtn.Close();
        }
    }

    class WildQTEBtn
    {
        public bool IsShown { get; set; }
        public bool isRotation = true;
        public bool IsPerss = false;

        /// <summary>
        /// 绑定的事件触发键
        /// </summary>
        private KeyCode _Key;
        /// <summary>
        /// QTE失败回调
        /// </summary>
        private Action TimeOver;
        /// <summary>
        /// QTE成功回调
        /// </summary>
        private Action SucceedCallback;
        /// <summary>
        /// QTE绑定执行事件
        /// </summary>
        private Action BindKeyCommand;
        private GameObject _Obj;
        /// <summary>
        /// 指针
        /// </summary>
        private GameObject pointer;
        /// <summary>
        /// 中心点
        /// </summary>
        private GameObject centerPoint;
        /// <summary>
        /// 可触发的区域位置
        /// </summary>
        private GameObject area;
        /// <summary>
        /// 限定QTE左右边角度范围
        /// </summary>
        private int leftangle = 16;
        private int rightangle = -14;
        /// <summary>
        /// 角度值
        /// </summary>
        public int angle = 0;
        private int areaAngle;
        /// <summary>
        /// 指针旋转速度
        /// </summary>
        private int speed = 250;

        /// <summary>
        /// 初始化组件
        /// </summary>
        /// <param name="key"></param>
        /// <param name="root"></param>
        public WildQTEBtn(KeyCode key, Transform root)
        {
            _Key = key;
            _Obj = root.gameObject;
            pointer = _Obj.transform.Find("pointer").gameObject;
            centerPoint = _Obj.transform.Find("centerdot").gameObject;
            area = _Obj.transform.Find("area").gameObject;
            Close();
        }

        /// <summary>
        /// 绑定QTE事件
        /// </summary>
        /// <param name="BindKeyCommand"></param>
        public void BindKeyUpExcuteCommand(Action BindKeyCommand)
        {
            this.BindKeyCommand = BindKeyCommand;

        }

        /// <summary>
        /// 执行QTE事件
        /// </summary>
        public void ExcuteCommand()
        {
            if (Input.GetKeyUp(_Key))
            {
                BindKeyCommand?.Invoke();
            }
        }

        /// <summary>
        /// 打开QTE面板
        /// </summary>
        /// <param name="areaAngle"></param>
        /// <param name="failCallback"></param>
        /// <param name="succeedCallback"></param>
        public void Open(int areaAngle, Action failCallback, Action succeedCallback)
        {

            this.areaAngle = areaAngle;
            area.transform.RotateAround(centerPoint.transform.position, Vector3.forward, areaAngle);
            angle = 0;
            TimeOver = failCallback;
            SucceedCallback = succeedCallback;
            _Obj.SetActive(true);
            IsShown = true;

        }

        /// <summary>
        /// 关闭QTE面板
        /// </summary>
        public void Close()
        {
            area.transform.RotateAround(centerPoint.transform.position, Vector3.forward, -areaAngle);
            TimeOver = null;
            SucceedCallback = null;
            _Obj.SetActive(false);
            IsShown = false;
        }

        /// <summary>
        /// 每帧QTE事件检测判断
        /// </summary>
        public void OnTick()
        {
            if (isRotation)
            {
                if (angle <= (360 / (speed * Time.deltaTime)))
                {
                    angle += 1;
                    pointer.transform.RotateAround(centerPoint.transform.position, Vector3.forward, -speed * Time.deltaTime);
                }
                else
                {
                    if (TimeOver != null)
                    {
                        TimeOver();
                    }
                }
            }

            if (IsPerss)
            {
                isRotation = false;
                IsPerss = false;
                if (areaAngle < 0)
                {
                    if (this.pointer.transform.localEulerAngles.z > (areaAngle + rightangle + 360) && this.pointer.transform.localEulerAngles.z < (areaAngle + leftangle + 360))
                    {

                        if (SucceedCallback != null)
                        {
                            Debug.Log("按键成功");
                            SucceedCallback();
                        }
                    }
                    else
                    {
                        isRotation = true;
                        Debug.Log("按键失败!");
                        if (TimeOver != null)
                        {
                            TimeOver();
                        }
                    }
                }
                else
                {
                    if (this.pointer.transform.localEulerAngles.z > (areaAngle + rightangle) && this.pointer.transform.localEulerAngles.z < (areaAngle + leftangle))
                    {

                        if (SucceedCallback != null)
                        {
                            Debug.Log("按键成功!");
                            SucceedCallback();
                        }

                    }
                    else
                    {
                        isRotation = true;
                        Debug.Log("按键失败!");
                        if (TimeOver != null)
                        {
                            TimeOver();
                        }
                    }
                }
            }



        }

    }

    private void FixedUpdate()
    {

        WildQTEBtn qteBtn = wildQteBtns[btnMap[key]];
        if (qteBtn != null)
        {
            qteBtn.ExcuteCommand();
        }

        if (wildQteBtns != null)
        {
            for (int i = 0; i < wildQteBtns.Length; ++i)
            {
                if (wildQteBtns[i].IsShown)
                {
                    wildQteBtns[i].OnTick();
                }
            }
        }
    }
}


好了 以上就是关于QTE部分的实现过程源码啦!不足之处多多指出,高手请绕道!

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值