Unity简单实现JoyStick摇杆,小学生能看懂系列

嘿欢迎点开小熊的博客,让我们继续前行吧!
40行实现主要内容。

*提供工程样例,在本文最后。

效果图片:

请添加图片描述

原理解析:

布局思路:

在这里插入图片描述
Canvas:是整个屏幕的图层,其中这个Canvas会设置“按照屏幕大小缩放”。*
JoyBac:是一张图片,一个背景图。(使用PS作图)

*在后文还会提及。
————
请将这三个物体对应的拖拽到后文的代码Inspection中以此初始化。(您可以看完后面的再来看这里)
在这里插入图片描述
而Handle就是我们传说的摇杆,也是一张图片。
Handle:
在这里插入图片描述
注意:真实的图片中是png格式,周围或圈内是透明的,这里为了演示将图片染色。

触发思路:

判断用户的点击,是不是在上面的”JoyBac“里面。如果用户在这个区域进行点击,那么就将图片的Handle移动到那个位置。以此好像是,我们拖动了摇杆的感觉一样。

当我们停止触控的话,那么就立马将Handle设置为原点。

这里面还需要注意一个坑点,那就是,小心Canvas的缩放。这会导致在拖动的时候,感觉Handle好像不跟手一样。

您应该掌握的知识有EventSystems(不是事件驱动系统,在这里指的是UGUI的那一套EventSystems)。

同时您也应该明白“将脚本拖拽到物体上面”的这个行为,这里的行为是使得这个物体拥有了脚本所能处理到的能力。也就是,脚本的this.gameObject(注意,这里的gameObject是小写代表一个变量,而大写的GameObject则代表着一个类。)指的是被拖拽的这个物体。

好的,说完了前面的这些,我们来看看代码。其实很简单。

代码分析:

将代码放在JoyBac上面*(正如我们前面所述,这些接口需要在被点击的物体生效)

首先,由于我们需要处理一些触摸操作,比如按下,抬起,拖拽,所以我们需要集成这些接口。

IPointerDownHandler, IDragHandler, IPointerUpHandler

然后我们需要实现这些接口,当我们“按下”的时候,之间执行我们“拖拽”时候执行的代码:
(注意,为什么是OnPointerDown这些是接口要求的东西,您可以复习一下您手头的计算机教材。)

    public void OnPointerDown(PointerEventData eventData) {
        OnDrag(eventData);
    }

当我们在移动的时候:

    public void OnDrag(PointerEventData eventData) {
        Vector2 to = ((Vector2)eventData.position - (Vector2)background.position) / canvas.scaleFactor;
        if (to.magnitude <= radious)
            handle.anchoredPosition = to;
        else {
            Vector2 to2;
            to2 = (Vector2)to / (float)(to.magnitude / radious);
            handle.anchoredPosition = to2;
        }
    }

这里就是核心的部分了。
to代表着Handle的中心点(anchoredPosition)在哪里。
而eventData是EventSystems返回给我们的事件数据,其中包含了触摸的位置,是否在托转dragged等参数。
background是我们的背景图片。
canvas.scaleFactor是图层的缩放尺度,请务必考虑在内,因为这会使得滑动屏幕的时候,Handle不跟手指。您可以移步至UGUI教程学习。

其实就一个to就是所有的核心内容啦!
通过to,我们就能知道相对于background中心点的偏移了。

然后,if (to.magnitude <= radious)一个逻辑分支判断,判断我们的触摸点是否已经被拖拽到了别的地方去了(超出了bac)

如果超出去了,那么就通过简单的数学运算:to2 = (Vector2)to / (float)(to.magnitude / radious);将to的长度改回最长的限制。

然后最后更正Handle的位置handle.anchoredPosition = to2;

当我们抬起手指的时候:

    public void OnPointerUp(PointerEventData eventData) {
        handle.anchoredPosition = Vector2.zero;
    }

将Handle更正,至此,您的简单代码已经全部实现完成啦!

那么,我们该怎么去,判断方向呢。

其实根据to向量就可以了,这部分留给读者思考。

本熊代码:

最近在写一款小游戏,只需要上下左右四个维度。

所以我的判断方法如下:
在这里插入图片描述
通过Handle靠近哪个点,那么就是用户想往哪个方向移动。

完整代码如下:

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

public class JoyStickControl: MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler {
    enum Mode { None, Up, Down, Left, Right };
    Mode mode;
    public Vector2 input = Vector2.zero;
    public RectTransform background = null;
    public RectTransform handle = null;
    public Canvas canvas;
    float radious;
    Vector2 up, down, left, right;
    void Start() {
        mode = Mode.None;
        radious = background.rect.width / 2.0f;
        up = new Vector2(0, radious);
        down = new Vector2(0, -radious);
        left = new Vector2(-radious, 0);
        right = new Vector2(radious, 0);
    }
    void Update() {
        MessageSend();
    }
    public void OnDrag(PointerEventData eventData) {
        Vector2 to = ((Vector2)eventData.position - (Vector2)background.position) / canvas.scaleFactor;
        if (to.magnitude <= radious)
            handle.anchoredPosition = to;
        else {
            Vector2 to2;
            to2 = (Vector2)to / (float)(to.magnitude / radious);
            handle.anchoredPosition = to2;
            CalcDis();
        }
    }
    void MessageSend() {
        switch (mode) {
            case Mode.None:
                break;
            case Mode.Up:
                break;
            case Mode.Left:
                break;
            case Mode.Down:
                break;
        }
    }
    void CalcDis() {
        float dis = 0f;
        if (Vector2.Distance(up, handle.anchoredPosition) < dis || dis == 0) {
            dis = Vector2.Distance(up, handle.anchoredPosition);
            mode = Mode.Up;
        }
        if (Vector2.Distance(down, handle.anchoredPosition) < dis) {
            dis = Vector2.Distance(down, handle.anchoredPosition);
            mode = Mode.Down;
        }
        if (Vector2.Distance(left, handle.anchoredPosition) < dis) {
            dis = Vector2.Distance(left, handle.anchoredPosition);
            mode = Mode.Left;
        }
        if (Vector2.Distance(right, handle.anchoredPosition) < dis) {
            dis = Vector2.Distance(right, handle.anchoredPosition);
            mode = Mode.Right;
        }
    }

    void EventSender(int mes) {

    }

    public void OnPointerDown(PointerEventData eventData) {
        OnDrag(eventData);
    }

    public void OnPointerUp(PointerEventData eventData) {
        handle.anchoredPosition = Vector2.zero;
        mode = Mode.None;
    }

    void OnGUI() {
        //The Label shows the current Rect settings on the screen
        GUI.Label(new Rect(20, 20, 150, 80), "Mode : " + mode);
    }
}

项目工程链接下载:

https://download.csdn.net/download/qq_34013247/81949365

免积分。

参考资料:

【推荐阅读,有实现其他效果的摇杆】
https://zhuanlan.zhihu.com/p/266077243

【亮点之间距离计算】
https://blog.csdn.net/moonlightpeng/article/details/89949615

小广告:

本熊写了一个小游戏,正在进行手机端适配,到时候请给位CSDN友来捧场哦!!!

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是实现JoyStick摇杆功能的Unity代码: using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; public class JoyStick : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler { private Image bgImg; private Image joystickImg; private Vector3 inputVector; private void Start() { bgImg = GetComponent<Image>(); joystickImg = transform.GetChild(0).GetComponent<Image>(); } public virtual void OnDrag(PointerEventData ped) { Vector2 pos; if (RectTransformUtility.ScreenPointToLocalPointInRectangle(bgImg.rectTransform, ped.position, ped.pressEventCamera, out pos)) { pos.x = (pos.x / bgImg.rectTransform.sizeDelta.x); pos.y = (pos.y / bgImg.rectTransform.sizeDelta.y); inputVector = new Vector3(pos.x * 2 + 1, 0, pos.y * 2 - 1); inputVector = (inputVector.magnitude > 1.0f) ? inputVector.normalized : inputVector; joystickImg.rectTransform.anchoredPosition = new Vector3(inputVector.x * (bgImg.rectTransform.sizeDelta.x / 3), inputVector.z * (bgImg.rectTransform.sizeDelta.y / 3)); } } public virtual void OnPointerDown(PointerEventData ped) { OnDrag(ped); } public virtual void OnPointerUp(PointerEventData ped) { inputVector = Vector3.zero; joystickImg.rectTransform.anchoredPosition = Vector3.zero; } public float Horizontal() { if (inputVector.x != 0) return inputVector.x; else return Input.GetAxis("Horizontal"); } public float Vertical() { if (inputVector.z != 0) return inputVector.z; else return Input.GetAxis("Vertical"); } } 希望能对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值