Unity手游制作记-制作通用输入管理器

今天不学机器学习,让我们一起搞(zuo)事(you)情(xi)

触摸输入管理器

触控

现在主流的手机就是苹果和安卓,支持的是多点触控,就是可以同时触摸好几个手指头(一般不超过5个),所以我们只需要将每个手指正在做的动作记录下来,并执行相应的响应即可。

Unity中的Touch类

让我们看一下Unity中的Touch类,看看它能给我们提供哪些输入信息。

// 摘要: 
//     Structure describing the status of a finger touching the screen.
//     描述手指触摸屏幕状态的结构。
public struct Touch {

   // 摘要: 
   //     Value of 0 radians indicates that the stylus is parallel to the surface,
   //     pi/2 indicates that it is perpendicular.
   //     0弧度的值表示触笔与表面平行,
//     pi/2表示它是垂直的。
   public float altitudeAngle { get; } // 高度角
   //
   // 摘要: 
   //     Value of 0 radians indicates that the stylus is pointed along the x-axis
   //     of the device.
   //     0弧度的值表示笔尖沿设备的x轴方向
   public float azimuthAngle { get; } // 方位角
   //
   // 摘要: 
   //     The position delta since last change.
   //     自上次变化以来的位置。
   public Vector2 deltaPosition { get; } // 增量位置
   //
   // 摘要: 
   //     Amount of time that has passed since the last recorded change in Touch values.
   //     自上次记录的触摸值更改以来已经过的时间。
   public float deltaTime { get; } // 时间增量
   //
   // 摘要: 
   //     The unique index for the touch.
   //     独一无二的触摸id。
   public int fingerId { get; } // 触摸id,用于识别是哪个指头
   //
   // 摘要: 
   //     The maximum possible pressure value for a platform. If Input.touchPressureSupported
   //     returns false, the value of this property will always be 1.0f.
   //     平台的最大可能压力值(3D Touch)。
   //     如果Input.touchPressureSupported(判断设备平台是否支持3D Touch)返回false,此属性的值始终为1.0f。
   public float maximumPossiblePressure { get; } // 最大可能压力值
   //
   // 摘要: 
   //     Describes the phase of the touch.
   //     描述触摸的时期(状态)。
   public TouchPhase phase { get; } // 时期(状态)
   //
   // 摘要: 
   //     The position of the touch in pixel coordinates.
   //     触摸在像素坐标中的位置。
   public Vector2 position { get; } // 坐标
   //
   // 摘要: 
   //     The current amount of pressure being applied to a touch. 1.0f is considered
   //     to be the pressure of an average touch. If Input.touchPressureSupported returns
   //     false, the value of this property will always be 1.0f.
   //     目前施加在触摸上的压力。1.0度被认为是平均接触的压力。
   //     如果输入touchPressureSupported返回false,此属性的值始终为1.0f。
   public float pressure { get; }  // 压力
   //
   // 摘要: 
   //     An estimated value of the radius of a touch. Add radiusVariance to get the
   //     maximum touch size, subtract it to get the minimum touch size.
   //     一个触摸半径的估计值。添加radius方差来得到最大触摸尺寸,减去它得到最小触摸尺寸。
   public float radius { get; } // 半径
   //
   // 摘要: 
   //     The amount that the radius varies by for a touch.
   //     触点半径的变化量。
   public float radiusVariance { get; }  // 半径变化
   //
   // 摘要: 
   //     The raw position used for the touch.
   //     触摸的原始位置。
   public Vector2 rawPosition { get; } // 开始坐标
   //
   // 摘要: 
   //     Number of taps.
   //     点击次数
   public int tapCount { get; } // 点击次数
   //
   // 摘要: 
   //     A value that indicates whether a touch was of Direct, Indirect (or remote),
   //     or Stylus type.
   //     一个表示触摸是否直接、间接(或远程)的值,或手写笔类型。
   public TouchType type { get; } // 触摸类型(分为三种,手指头直接按, 程序内部按(触摸精灵什么的), 触摸笔按)
}

好了,知道这些以后,我们就可以将这些信息利用,制作出自己的输入管理器。

总监听

我们需要在每隔一段时间的来判断用户的触摸情况,比如把手指按上去,移动,放开等等操作。

void FixedUpdate () {
    Touch[] t = Input.touches;
    bool flag = false;
    foreach(Touch to in t) {
        flag = true;
        switch (to.phase) {
            case TouchPhase.Began: // 刚开始触摸(刚把手指放下去)
                beganEvent(to);
                break;
            case TouchPhase.Canceled:
                // 取消触摸
                // 这个情况的话,就是系统取消了触摸,非法触摸
                // 比如超过5个手指头的情况,或者就是整个手掌拍上去
                canceledEvent(to);
                break;
            case TouchPhase.Ended: // 结束触摸(已经把手指抬起来)
                endedEvent(to);
                break;
            case TouchPhase.Moved: // 移动的
                movedEvent(to);
                break;
            case TouchPhase.Stationary: // 静止的
                stationaryEvent(to);
                break;
        }
    }
    if (flag) {
        // 判断拉伸状态
        if (hasUp && hasDown) {
            if (upPos.y < downPos.y) {
                shrinkEvent();
            } else {
                stretchEvent();
            }
        } else if (hasLeft && hasRight) {
            if (leftPos.x < rightPos.x) {
                shrinkEvent();
            } else {
                stretchEvent();
            }
        }
        hasUp = false;
        hasDown = false;
        hasLeft = false;
        hasRight = false;
    }
}
滑动

摩擦摩擦,在光滑的屏幕上摩擦,就会发生滑动事件,我们只需要检测上下左右拉缩即可。

protected virtual void movedEvent(Touch to) {
    touchList.Remove(to.fingerId);
    float angle = Mathf.Atan2((to.position.y - to.rawPosition.y), (to.position.x - to.rawPosition.x));
    if (Mathf.Abs(angle - Mathf.PI / 2.0f) <= shakeAngle) {
        hasUp = true;
        upPos = to.rawPosition;
        upEvent(to, angle);
    } else if (Mathf.Abs(angle + Mathf.PI / 2.0f) <= shakeAngle) {
        hasDown = true;
        downPos = to.rawPosition;
        downEvent(to, angle);
    }
    if (Mathf.Abs(angle - Mathf.PI) <= shakeAngle) {
        hasLeft = true;
        leftPos = to.rawPosition;
        leftEvent(to, angle);
    } else  if (Mathf.Abs(angle) <= shakeAngle) {
        hasRight = true;
        rightPos = to.rawPosition;
        rightEvent(to, angle);
    }
}
长按

我们需要判断长按事件,就是手指按下去,一直按下去的事件。
这里直接将按的时间传进去即可,开发的时候,根据需求自行判断静止时间。
还可以跟滑动组合,比如长按出来选项,滑动出来箭头,在根据touch的当前坐标进行选择。

protected virtual void stationaryEvent(Touch to) {
    if (!touchList.ContainsKey(to.fingerId)) {
        touchList.Add(to.fingerId, Time.fixedDeltaTime);
    } else {
        touchList[to.fingerId] += Time.fixedDeltaTime;
    }
    stationaryEvent(to, touchList[to.fingerId]);
}
总结

其他的就很简单了,主要逻辑还是要根据游戏的不同,实现的功能不同,这里主要统一处理一下各个触控的事件即可。

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

public class InputManager : MonoBehaviour {

    private float shakeAngle = Mathf.PI / 2.0f * 0.25f; // 抖动幅度

    protected bool hasUp; // 是否向上移动过
    private Vector2 upPos; // 向上移动的起始坐标
    protected bool hasDown;// 是否向下移动过
    private Vector2 downPos; // 向下移动的起始坐标
    protected bool hasLeft; // 是否向左移动过
    private Vector2 leftPos; // 向左移动的起始坐标
    protected bool hasRight; // 是否向右移动过
    private Vector2 rightPos; // 向右移动的起始坐标

    Dictionary<int, float> touchList = new Dictionary<int, float>();


    /*********************************
     * 一级事件(会调用二级事件)
     * 即直接触发时执行的事件
     * 注意重写的时候要先执行原函数
     **********************************/ 

    // 触摸开始事件
    protected virtual void beganEvent(Touch to) {
        touchList.Remove(to.fingerId);
        startEvent(to);
    }

    // 取消触摸事件
    protected virtual void canceledEvent(Touch to) {
        touchList.Remove(to.fingerId);
        endEvent(to);
    }

    // 结束触摸事件
    protected virtual void endedEvent(Touch to) {
        touchList.Remove(to.fingerId);
        endEvent(to);
    }

    // 移动触摸事件
    protected virtual void movedEvent(Touch to) {
        touchList.Remove(to.fingerId);
        float angle = Mathf.Atan2((to.position.y - to.rawPosition.y), (to.position.x - to.rawPosition.x));
        if (Mathf.Abs(angle - Mathf.PI / 2.0f) <= shakeAngle) {
            hasUp = true;
            upPos = to.rawPosition;
            upEvent(to, angle);
        } else if (Mathf.Abs(angle + Mathf.PI / 2.0f) <= shakeAngle) {
            hasDown = true;
            downPos = to.rawPosition;
            downEvent(to, angle);
        }
        if (Mathf.Abs(angle - Mathf.PI) <= shakeAngle) {
            hasLeft = true;
            leftPos = to.rawPosition;
            leftEvent(to, angle);
        } else  if (Mathf.Abs(angle) <= shakeAngle) {
            hasRight = true;
            rightPos = to.rawPosition;
            rightEvent(to, angle);
        }
    }

    // 触摸静止事件
    protected virtual void stationaryEvent(Touch to) {
        if (!touchList.ContainsKey(to.fingerId)) {
            touchList.Add(to.fingerId, Time.fixedDeltaTime);
        } else {
            touchList[to.fingerId] += Time.fixedDeltaTime;
        }
        stationaryEvent(to, touchList[to.fingerId]);
    }

    /*********************************
     * 会调用二级事件
     * 建议非必要,直接重写二级事件即可
     **********************************/

    public virtual void upEvent(Touch to, float angle) {

    }
    public virtual void downEvent(Touch to, float angle) {

    }
    public virtual void leftEvent(Touch to, float angle) {

    }
    public virtual void rightEvent(Touch to, float angle) {

    }
    // 拉伸事件
    public virtual void stretchEvent() {

    }
    // 缩小事件
    public virtual void shrinkEvent() {

    }

    // 触摸静止事件
    protected virtual void stationaryEvent(Touch to, float time) {

    }

    // 触摸开始事件
    protected virtual void startEvent(Touch to) {

    }

    // 触摸结束事件
    protected virtual void endEvent(Touch to) {

    }
    // 触控监听
    void FixedUpdate () {
        Touch[] t = Input.touches;
        bool flag = false;
        foreach(Touch to in t) {
            flag = true;
            switch (to.phase) {
                case TouchPhase.Began: // 刚开始触摸(刚把手指放下去)
                    beganEvent(to);
                    break;
                case TouchPhase.Canceled:
                    // 取消触摸
                    // 这个情况的话,就是系统取消了触摸,非法触摸
                    // 比如超过5个手指头的情况,或者就是整个手掌拍上去
                    canceledEvent(to);
                    break;
                case TouchPhase.Ended: // 结束触摸(已经把手指抬起来)
                    endedEvent(to);
                    break;
                case TouchPhase.Moved: // 移动的
                    movedEvent(to);
                    break;
                case TouchPhase.Stationary: // 静止的
                    stationaryEvent(to);
                    break;
            }
        }
        if (flag) {
            // 判断拉伸状态
            if (hasUp && hasDown) {
                if (upPos.y < downPos.y) {
                    shrinkEvent();
                } else {
                    stretchEvent();
                }
            } else if (hasLeft && hasRight) {
                if (leftPos.x < rightPos.x) {
                    shrinkEvent();
                } else {
                    stretchEvent();
                }
            }
            hasUp = false;
            hasDown = false;
            hasLeft = false;
            hasRight = false;
        }
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值