Unity 利用NGUI实现一个简单摇杆

目录

前言

1.实现原理

2.实现过程

UI设置:

完整代码:

 效果:

3.拓展:

UI设置

完整代码:

效果:


前言

unity现在有很多成熟的摇杆插件,比如easyTouch,功能很完善,使用也很方便,而我们使用工具的时候也要清楚最基本的工具原理。基于此,我尝试着实现了一个简单的摇杆,并利用此摇杆控制人物的移动。

1.实现原理

我们最常见的摇杆无非是两个圆套在一起,外边一个大圆,内部一个小圆,小圆在大圆内部移动,且不超出大圆。
整个摇杆的关键在于怎么让小圆在大圆内部移动且不超出去。

我的做法是尝试以小圆为原点,给一个最大移动半径, 在拖拽的时候检测鼠标/手指接触屏幕的位置 和 最大移动半径之间的大小 如果鼠标/手指触点没有超出最大半径就把触点的位置赋值给小圆 否则 就把小圆最初位置和触点方向上最大半径的点位置赋值给小圆

2.实现过程

首先尝试获取当前触点的ui位置。
注:触点的位置是屏幕坐标位置 。
屏幕坐标:左下角为原点 右上角为最大点。
ui坐标:以屏幕中心为原点, 左下角为最小点(负值),右上角为最大点。

代码如下:

Vector2 GetCurTouchUIPos() {
        //获取触点的屏幕坐标
        Vector2 touchPos = UICamera.currentTouch.pos;
        //获取当前设备屏幕大小和铆定屏幕大小的缩放比例
        float screenRate = sceneWidget / Screen.width;
        //按照当前实际屏幕比例 获取1280情况下的高度
        float hight = sceneWidget * Screen.height / Screen.width;
        //touchPos * screenRate 把位置从screen大小换算到1280大小上
        // - new Vector2(1280 / 2f, hight / 2f) 把坐标从左下角移到中心
        touchPos = touchPos * screenRate - new Vector2(sceneWidget / 2f, hight / 2f);
        return touchPos;
    }


铆定屏幕大小指的是UIRoot上做的适配的大小


Screen.width和Screen.height 是当前实际的屏幕大小


当屏幕按照长适配之后 可能根据实际的屏幕比例从而影响到 适配的高
比如我现在的是按照长做的适配 适配的大小时1280:720 当我的设备屏幕分辨率为1600:1000的时候
游戏中的屏幕的长度还是1280像素 但是高度会变成 1280/1600/1000=800像素
所以:

 //获取设备屏幕大小和铆定屏幕大小的缩放比例
        float screenRate = sceneWidget / Screen.width;
        //按照当前实际屏幕比例 获取1280情况下的高度
        float hight = sceneWidget * Screen.height / Screen.width;

这是为了求出当前设备的实际游戏中的屏幕高度像素

下面从屏幕坐标转到ui坐标

touchPos = touchPos * screenRate - new Vector2(sceneWidget / 2f, hight / 2f);

 找到坐标之后直接在拖拽的时候判断一下

public void Moving() {
        Debug.Log("移动中");
        isMoving = true;
        Vector2 touchPos = GetCurTouchUIPos();
        Vector2 touchMove = touchPos - startPos;
        //方向*距离得出最后位置
        Vector2 addPos = startPos + touchMove.normalized * Mathf.Min(touchMove.magnitude, maxRadius);

        float addX = addPos.x;
        float addY = addPos.y;

        forwardPos.localPosition = new Vector3(addX, addY, 0);
    }

此时 其中startPos就是小圆的初始位置 forwardPos 就是小圆的tranform 把求出的值赋给小圆就得到了小圆位置

UI设置:

 

 

完整代码:

using UnityEngine;

public class LudwigTouch : MonoBehaviour {
    public float maxRadius;
    public Vector2 startPos;


    public Transform forwardPos;
    public Transform backPos;


    const float sceneWidget = 1280f;

    private void Start() {
        startPos = forwardPos.localPosition;
    }

    Vector2 GetCurTouchUIPos() {
        //像素坐标就是铆定的大小的坐标
        //屏幕坐标(获取的是铆定的屏幕下的)
        Vector2 touchPos = UICamera.currentTouch.pos;
        //获取当前屏幕大小和铆定屏幕大小的缩放比例
        float screenRate = sceneWidget / Screen.width;
        //按照当前实际屏幕比例 获取1280情况下的高度
        float hight = sceneWidget * Screen.height / Screen.width;
        //touchPos * screenRate 把位置从screen大小换算到1280大小上
        // - new Vector2(1280 / 2f, hight / 2f) 把坐标从左下角移到中心
        touchPos = touchPos * screenRate - new Vector2(sceneWidget / 2f, hight / 2f);
        return touchPos;
    }

    public void Moving() {
        Debug.Log("移动中");
        Vector2 touchPos = GetCurTouchUIPos();
        Vector2 touchMove = touchPos - startPos;
        //方向*距离得出最后位置
        Vector2 addPos = startPos + touchMove.normalized * Mathf.Min(touchMove.magnitude, maxRadius);

        float addX = addPos.x;
        float addY = addPos.y;

        forwardPos.localPosition = new Vector3(addX, addY, 0);

        Vector3 move = new Vector3(touchMove.normalized.x, 0, touchMove.normalized.y);
        move = Camera.main.transform.TransformDirection(move);
        move.y = 0.0f;

        InputManager.Instance.inputMoveDis = move.normalized;

        InputManager.Instance.input = true;
    }

    public void MoveEnd() {
        Debug.Log("移动结束");
        forwardPos.localPosition = startPos;
    }
}

 效果:

 

3.拓展:

我想让这个摇杆出现在我点击的地方 其他时间隐藏

注:点击的有效范围由touch的BoxCollider大小确认 当前我的touch的BoxCollider 在屏幕的左下占大概四分之一屏幕

1.首先需要在Start方法中隐藏touch

 private void Start() {
        forwardPos.gameObject.SetActive(false);
        backPos.gameObject.SetActive(false);
    }

 2.点击时出现并把位置设置到点击的位置 并考虑屏幕的边界问题(不要让touch有一部分出现在屏幕外)

public void MoveStart() {
        if(!isMoving) {
            startPos = GetCurTouchUIPos();
            startPos = BoundaryDetection(startPos);
            forwardPos.gameObject.SetActive(true);
            backPos.gameObject.SetActive(true);
            localBackPos = startPos;
            localForwardPos = startPos;

            backPos.localPosition = startPos;
            forwardPos.localPosition = startPos;
        }
    }

Vector2 BoundaryDetection(Vector3 startPos) {
        Vector2 realPos = startPos;
        //获取当前屏幕大小和铆定屏幕大小的缩放比例
        float screenRate = sceneWidget / Screen.width;
        //按照当前实际屏幕比例 获取1280情况下的高度
        float hight = sceneWidget * Screen.height / Screen.width;

        if(startPos.x - maxRadius - boundaryDetectionAddValue < -sceneWidget / 2) {
            realPos.x = -sceneWidget / 2 + maxRadius + boundaryDetectionAddValue;
        }
        if(startPos.y - maxRadius - boundaryDetectionAddValue < -hight / 2)
            realPos.y = -hight / 2 + maxRadius + boundaryDetectionAddValue;

        return realPos;
    }

UI设置

在touch的EvenTrigger中加上

完整代码:

using UnityEngine;

public class LudwigTouch : MonoBehaviour {
    public float maxRadius;
    public Vector2 startPos;


    public Transform forwardPos;
    public Transform backPos;

    private Vector2 localForwardPos;
    private Vector2 localBackPos;

    bool isMoving;

    const float sceneWidget = 1280f;

    public float boundaryDetectionAddValue = 20f;

    private void Start() {
        forwardPos.gameObject.SetActive(false);
        backPos.gameObject.SetActive(false);
    }

    Vector2 GetCurTouchUIPos() {
        //像素坐标就是铆定的大小的坐标
        //屏幕坐标(获取的是铆定的屏幕下的)
        Vector2 touchPos = UICamera.currentTouch.pos;
        //获取当前屏幕大小和铆定屏幕大小的缩放比例
        float screenRate = sceneWidget / Screen.width;
        //按照当前实际屏幕比例 获取1280情况下的高度
        float hight = sceneWidget * Screen.height / Screen.width;
        //touchPos * screenRate 把位置从screen大小换算到1280大小上
        // - new Vector2(1280 / 2f, hight / 2f) 把坐标从左下角移到中心
        touchPos = touchPos * screenRate - new Vector2(sceneWidget / 2f, hight / 2f);
        return touchPos;
    }

    Vector2 BoundaryDetection(Vector3 startPos) {
        Vector2 realPos = startPos;
        //获取当前屏幕大小和铆定屏幕大小的缩放比例
        float screenRate = sceneWidget / Screen.width;
        //按照当前实际屏幕比例 获取1280情况下的高度
        float hight = sceneWidget * Screen.height / Screen.width;

        if(startPos.x - maxRadius - boundaryDetectionAddValue < -sceneWidget / 2) {
            realPos.x = -sceneWidget / 2 + maxRadius + boundaryDetectionAddValue;
        }
        if(startPos.y - maxRadius - boundaryDetectionAddValue < -hight / 2)
            realPos.y = -hight / 2 + maxRadius + boundaryDetectionAddValue;

        return realPos;
    }

    public void MoveStart() {
        if(!isMoving) {
            startPos = GetCurTouchUIPos();
            startPos = BoundaryDetection(startPos);
            forwardPos.gameObject.SetActive(true);
            backPos.gameObject.SetActive(true);
            localBackPos = startPos;
            localForwardPos = startPos;

            backPos.localPosition = startPos;
            forwardPos.localPosition = startPos;
        }
    }

    public void Moving() {
        Debug.Log("移动中");
        isMoving = true;
        Vector2 touchPos = GetCurTouchUIPos();
        Vector2 touchMove = touchPos - startPos;
        //方向*距离得出最后位置
        Vector2 addPos = startPos + touchMove.normalized * Mathf.Min(touchMove.magnitude, maxRadius);

        float addX = addPos.x;
        float addY = addPos.y;

        forwardPos.localPosition = new Vector3(addX, addY, 0);

        Vector3 move = new Vector3(touchMove.normalized.x, 0, touchMove.normalized.y);
        move = Camera.main.transform.TransformDirection(move);
        move.y = 0.0f;
    }

    public void MoveEnd() {
        Debug.Log("移动结束");
        isMoving = false;
        forwardPos.localPosition = localForwardPos;
        backPos.localPosition = localBackPos;
        forwardPos.gameObject.SetActive(false);
        backPos.gameObject.SetActive(false);
    }
}


效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一梭键盘任平生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值