SmartJoystick.cs

using UnityEngine;
using System.Collections.Generic;

[ExecuteInEditMode]
public class SmartJoystick : MonoBehaviour
{
    public delegate void SmartJoystickEventHandler(SmartJoystick joystick);
    public static event SmartJoystickEventHandler OnHoldingHandler;
    public static event SmartJoystickEventHandler OnPressDownHandler;
    public static event SmartJoystickEventHandler OnPressUpHandler;
    public static event SmartJoystickEventHandler OnDragingHandler;

    public enum EAlign { TopLeft, Top, TopRight, Left, Center, Right, BottomLeft, Bottom, BottomRight }

    public bool IsDisable { get; set; }
    public bool IsHolding { get; set; }
    public bool IsPressing { get; private set; }
    public bool IsDragging { get; private set; }
    public int PressedDegree { get; private set; }
    public Vector2 CurrentAxis { get; private set; }
    public float CurrentRadian { get { return Mathf.Atan2(CurrentAxis.x, CurrentAxis.y); } }
    public float CurrentDegree { get { return Mathf.Atan2(CurrentAxis.x, CurrentAxis.y) * Mathf.Rad2Deg; } }
    public float CurrentEulerAngles
    {
        get
        {
            var a = Mathf.Atan2(CurrentAxis.x, CurrentAxis.y) / Mathf.Deg2Rad;
            a = a < 0 ? 360 + a : a;
            return -a;
        }
    }

    public Texture Pedestal;
    public Texture Thumb;
    public int PedestalRadius = 200;
    public int ThumbRadius = 80;
    public int Depth = 5;//摇杆所在层
    public EAlign Align = EAlign.BottomLeft;//设置对齐方式
    public bool IsNoReturn = true;//摇杆不返回
    public bool IsAttachEdge = true;//磁性吸附
    public bool IsCanPressed = false;//可按压受力
    public bool IsRebuildThumb = false;//是否重建摇杆

    GameObject m_thumb;
    UIRoot m_root;
    Camera m_camera;
    Vector3 m_thumbPosition;//摇杆当前向量

    #region 系统函数
    void Start()
    {
        var pedestalDiameter = PedestalRadius * 2;
        var thumbDiameter = ThumbRadius * 2;
        //挂载到相机
        m_root = FindObjectOfType<UIRoot>();
        m_camera = m_root.transform.FindChild("Camera").GetComponent<Camera>();
        UICamera.currentCamera = m_camera;
        transform.SetParent(m_camera.transform);
        //半径转直径
        transform.rotation = Quaternion.identity;//设置角度
        transform.localScale = Vector3.one;//设置尺寸比例
        //配置脚本
        gameObject.AddMissingComponent<UISprite>();
        GetComponent<UISprite>().depth = Depth;//设置游戏分层
        GetComponent<UISprite>().spriteName = Pedestal.name;设置基座图集名称
        gameObject.AddMissingComponent<BoxCollider>();
        GetComponent<BoxCollider>().size = new Vector3(pedestalDiameter, pedestalDiameter);//注意半径和直径的转换
        GetComponent<BoxCollider>().isTrigger = true;
        //创建摇杆实体
        if (IsRebuildThumb)
        {
            gameObject.transform.DestroyChildren();//清空子物体
            m_thumb = new GameObject("thumb");//创建摇杆
            m_thumb.transform.SetParent(gameObject.transform);//设置挂载父级
            m_thumb.transform.localPosition = Vector3.zero;//重置相对位置
            m_thumb.gameObject.AddMissingComponent<UISprite>();
            m_thumb.GetComponent<UISprite>().atlas = GetComponent<UISprite>().atlas;//设置图集
            m_thumb.GetComponent<UISprite>().spriteName = Thumb.name;//设置摇杆图集名称
            m_thumb.GetComponent<UISprite>().depth = Depth;//设置游戏分层
            m_thumb.transform.rotation = Quaternion.identity;//设置角度
            m_thumb.transform.localScale = Vector3.one;//设置尺寸比例
            //设置标签和层                                         
            m_thumb.tag = gameObject.tag;
            m_thumb.layer = gameObject.layer;
            //设置尺寸,注意半径和直径区别
            GetComponent<UISprite>().width = pedestalDiameter;//设置宽度
            GetComponent<UISprite>().height = pedestalDiameter;//设置高度
            m_thumb.GetComponent<UISprite>().width = thumbDiameter;//设置宽度
            m_thumb.GetComponent<UISprite>().height = thumbDiameter;//设置高度
        }
        else
        {
            m_thumb = gameObject.transform.FindChild("thumb").gameObject;
            if (m_thumb == default(GameObject))
            {
                Debug.LogError(gameObject.name + "`s thumb object not exist!");
            }
        }
        //尺寸调整
        GetComponent<UISprite>().width = pedestalDiameter;
        GetComponent<UISprite>().height = pedestalDiameter;
        m_thumb.GetComponent<UISprite>().width = thumbDiameter;
        m_thumb.GetComponent<UISprite>().height = thumbDiameter;
        //属性初始化
        IsDisable = false;
        IsHolding = false;
        IsPressing = false;
        IsDragging = false;
        PressedDegree = 0;//初始化压力
        CurrentAxis = Vector2.zero;//初始化向量
        //设定初始化
        m_thumbPosition = Vector3.zero;//初始化摇杆向量
        resetPosition();//调整摇杆位置
    }

    void FixedUpdate()
    {
        if (IsDisable)
        {
            m_thumb.transform.localPosition = Vector3.zero;
            CurrentAxis = Vector2.zero;
        }
        if (IsHolding && OnHoldingHandler != null) OnHoldingHandler(this);//暂停委托处理
        resetPosition();//调整摇杆位置
        //判断是否启用按压记录
        if (IsCanPressed && IsPressing) PressedDegree++;//记录按压力
        //判断拖拽: 当拖拽状态且不移动时,则认为已停止拖拽
        if (IsDragging && m_thumb.transform.localPosition.Equals(m_thumbPosition)) IsDragging = false;//重置拖拽标志
        m_thumbPosition = m_thumb.transform.localPosition;//保存摇杆向量
    }

    void OnPress(bool isPressed)
    {
        if (IsDisable) return;//禁用时直接返回
        resetThumb();//处理摇杆位置
        IsPressing = isPressed;
        if (isPressed)
        {//按压时
            if (OnPressDownHandler != null) OnPressDownHandler(this);//按压委托处理
        }
        else
        {//抬起时
            PressedDegree = 0;//重置压力
            //摇杆返回处理
            if (!IsNoReturn)
            {
                m_thumb.GetComponent<UISprite>().transform.localPosition = Vector3.zero;
                CurrentAxis = Vector2.zero;//重置向量
            }
            if (OnPressUpHandler != null) OnPressUpHandler(this);//抬起委托处理
        }
    }

    void OnDrag(Vector2 delta)
    {
        if (IsDisable) return;//禁用时直接返回
        resetThumb();//处理摇杆位置
        IsDragging = true;
        if (OnDragingHandler != null) OnDragingHandler(this);//拖拽委托处理
    }

    #endregion

    #region 计算处理函数
    //重置位置
    void resetPosition()
    {
        //计算偏移量
        float offset = PedestalRadius;
        float xPos, yPos;
        //摇杆对齐屏幕
        switch (Align)
        {
            case EAlign.TopRight:
            case EAlign.Right:
            case EAlign.BottomRight:
                xPos = -offset;
                break;
            case EAlign.TopLeft:
            case EAlign.Left:
            case EAlign.BottomLeft:
                xPos = offset;
                break;
            default:
                xPos = 0;
                break;
        }
        switch (Align)
        {
            case EAlign.TopLeft:
            case EAlign.Top:
            case EAlign.TopRight:
                yPos = -offset;
                break;
            case EAlign.BottomLeft:
            case EAlign.Bottom:
            case EAlign.BottomRight:
                yPos = offset;
                break;
            default:
                yPos = 0;
                break;
        }
        alignToScreen(Align, transform, new Vector3(xPos, yPos, 0));
    }

    //对齐到屏幕
    void alignToScreen(EAlign side, Transform trans, Vector2 pixelOffset = default(Vector2), Vector2 relativeOffset = default(Vector2))
    {
        var uiCamera = NGUITools.FindCameraForLayer(gameObject.layer);
        var rect = uiCamera.pixelRect;
        var cx = (rect.xMin + rect.xMax) * 0.5f;
        var cy = (rect.yMin + rect.yMax) * 0.5f;
        var v = new Vector3(cx, cy, 0f);
        if (side != EAlign.Center)
        {
            switch (side)
            {
                case EAlign.TopRight:
                case EAlign.Right:
                case EAlign.BottomRight:
                    v.x = rect.xMax;
                    break;
                case EAlign.Top:
                case EAlign.Center:
                case EAlign.Bottom:
                    v.x = cx;
                    break;
                default:
                    v.x = rect.xMin;
                    break;
            }
            switch (side)
            {
                case EAlign.TopLeft:
                case EAlign.Top:
                case EAlign.TopRight:
                    v.y = rect.yMax;
                    break;
                case EAlign.Left:
                case EAlign.Center:
                case EAlign.Right:
                    v.y = cy;
                    break;
                default:
                    v.y = rect.yMin;
                    break;
            }
        }
        v.x += pixelOffset.x + relativeOffset.x * rect.width;
        v.y += pixelOffset.y + relativeOffset.y * rect.height;
        if (uiCamera.orthographic)
        {
            v.x = Mathf.Round(v.x);
            v.y = Mathf.Round(v.y);
        }
        v.z = uiCamera.WorldToScreenPoint(trans.position).z;
        v = uiCamera.ScreenToWorldPoint(v);
        if (uiCamera.orthographic && trans.parent != default(Transform))
        {
            v = trans.parent.InverseTransformPoint(v);
            v.x = Mathf.RoundToInt(v.x);
            v.y = Mathf.RoundToInt(v.y);
            if (trans.localPosition != v) trans.localPosition = v;
        }
        else if (trans.position != v)
        {
            trans.position = v;
        }
    }

    //重置摇杆位置
    void resetThumb()
    {
        var offset = getPos(UICamera.currentTouch.pos) - transform.localPosition;
        var radius = PedestalRadius - ThumbRadius;//基座半径去除摇杆半径
        //向量的长度超过半径后规范化
        if (offset.magnitude > radius)
        {
            //按向量为1规范化后重新计算长度,并限定摇杆最大边缘位置
            offset = offset.normalized * radius;
        }
        else if (offset.magnitude > 0 && IsAttachEdge)
        {
            //当返回向量长度大于0且开启了吸附边缘,则直接将摇杆置于边缘吸附
            offset = offset.normalized * radius;
        }
        m_thumb.transform.localPosition = offset;//设定摇杆位置
        CurrentAxis = new Vector2(offset.x / radius, offset.y / radius);//保存向量
    }

    //获得NGUI坐标
    Vector3 getPos(Vector2 pos)
    {
        var uiPos = m_camera.ScreenToWorldPoint(new Vector3(pos.x, pos.y, 0f));
        uiPos = m_camera.transform.InverseTransformPoint(uiPos);
        return uiPos;
    }

    #endregion

    #region 激活、禁用处理  
    readonly List<string> m_keys = new List<string>();
    public string DisableSequence()
    {
        var key = System.Guid.NewGuid().ToString();//生成唯一key  
        m_keys.Add(key);
        IsDisable = true;
        return key;
    }

    public void EnableSequence(string key)
    {
        if (m_keys.Contains(key)) m_keys.Remove(key);//有钥匙时移除钥匙序列  
        if (m_keys.Count == 0) IsDisable = false;//当所有钥匙都移除后启动  
    }

    #endregion

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值