写点什么

Unity 之 使用原生 UGUI 实现随手移动摇杆功能经典实例

作者:陈言必行
  • 2023-04-14
    辽宁
  • 本文字数:3413 字

    阅读完需:约 11 分钟

Unity 之 使用原生UGUI实现随手移动摇杆功能经典实例

一,实现思路

1.1 原理解析

做一个实验看一下使用ScrollRect组件实现摇杆的原理。


  1. Hierarchy面板右键 UI -> Scroll View 创建一个滚动视图,这个组件经常被应用于排行榜,选角色之类的可滑动的界面。

  2. Scroll View -> Viewport -> Content 添加一个 Image 组件

  3. 运行场景,鼠标点击并拖动中间部分,即可看到如下效果:


看到这里基本了解实现思路了吧,其实就是通过Scroll Rect组件的 Context 和 Viewport 的关系来进行模拟的。



更多关于 ScrollRect 的使用方法和实战应用,可以查看:Unity 之 UGUI Scroll Rect滚动矩形组件详解



1.2 思路概述

  1. 随手指落下位置 思路:其实就是根据手指第一次落下的屏幕坐标,修改摇杆的初始位置;手抬起时再将摇杆位置还原 知识点:获取手指按下和抬起的回调,将手指落下坐标转换为屏幕 UI 坐标

  2. 摇杆移动 思路:使用Scroll Rect的移动回调,来控制中间的虚拟摇杆进行位置变化 注意的点:使用 OnDrag 进行回调,并来控制虚拟摇杆的标移动位置不要超出背景

  3. 移动回调 思路:当使用摇杆时使用 Update 进行实时回调 注意的点:使用 OnEndDrag 进行回调,还原要个位置



二,实现代码

2.1 随手落下

通过锚点和RectTransformUtility坐标转换方法进行位置设置。


using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.UI;
[RequireComponent(typeof(EventTrigger))]public class JoystickTouch : ScrollRect{ protected override void Start() { EventTrigger trigger = GetComponent<EventTrigger>(); EventTrigger.Entry entryPointerUp = new EventTrigger.Entry(); entryPointerUp.eventID = EventTriggerType.PointerUp; entryPointerUp.callback.AddListener((data) => { OnPointerUp((PointerEventData)data); }); trigger.triggers.Add(entryPointerUp);
EventTrigger.Entry entryPointerDown = new EventTrigger.Entry(); entryPointerDown.eventID = EventTriggerType.PointerDown; entryPointerDown.callback.AddListener((data) => { OnPointerDown((PointerEventData)data); }); trigger.triggers.Add(entryPointerDown); } // 随手落下设置摇杆位置 private void OnPointerDown(PointerEventData eventData) { Vector2 LocalPosition; RectTransformUtility.ScreenPointToLocalPointInRectangle(this.GetComponent<RectTransform>(), eventData.position, eventData.pressEventCamera, out LocalPosition); this.viewport.localPosition = LocalPosition; }
// 抬起还原位置 private void OnPointerUp(PointerEventData eventData) { this.viewport.anchoredPosition3D = Vector3.zero; }
}
复制代码

2.2 摇杆转动

还是在上面的类中重写OnDrag方法,进行虚拟摇杆中间位置的控制。


public class JoystickTouch : ScrollRect{        // 半径 -- 控制拖拽区域    private float mRadius;        protected override void Start()    {        mRadius = this.content.sizeDelta.x * 0.5f;    }        public override void OnDrag(PointerEventData eventData)    {        base.OnDrag(eventData);        joyIsCanUse = true;        //虚拟摇杆移动        Vector3 contentPosition = this.content.anchoredPosition;        if (contentPosition.magnitude > mRadius)        {            contentPosition = contentPosition.normalized * mRadius;            SetContentAnchoredPosition(contentPosition);        }
// 摇杆内部按钮旋转 //if (content.anchoredPosition.y != 0) //{ // content.eulerAngles = new Vector3(0, 0, // Vector3.Angle(Vector3.right, content.anchoredPosition) * content.anchoredPosition.y / // Mathf.Abs(content.anchoredPosition.y) - 90); //} }}
复制代码



三,源码分享

3.1 场景搭建

创建三个 Image 一个作为一个的子物体,依次为:接收点击背景面积,摇杆背景板,摇杆中的虚拟按钮。 第一个 Image 挂载新建脚本JoystickTouch 场景搭建如下:




3.2 完整代码

using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.UI;
[RequireComponent(typeof(EventTrigger))]public class JoystickTouch : ScrollRect{ /// <summary> /// 拖动差值 /// </summary> public Vector2 offsetValue; // 半径 -- 控制拖拽区域 private float mRadius; /// <summary> /// 移动中回调 /// </summary> public System.Action<RectTransform> JoystickMoveHandle; /// <summary> /// 移动结束回调 /// </summary> public System.Action<RectTransform> JoystickEndHandle;
/// <summary> /// 摇杆是否处于可用状态 /// </summary> public bool joyIsCanUse = false; protected override void Start() { mRadius = this.content.sizeDelta.x * 0.5f; EventTrigger trigger = GetComponent<EventTrigger>(); EventTrigger.Entry entryPointerUp = new EventTrigger.Entry(); entryPointerUp.eventID = EventTriggerType.PointerUp; entryPointerUp.callback.AddListener((data) => { OnPointerUp((PointerEventData)data); }); trigger.triggers.Add(entryPointerUp);
EventTrigger.Entry entryPointerDown = new EventTrigger.Entry(); entryPointerDown.eventID = EventTriggerType.PointerDown; entryPointerDown.callback.AddListener((data) => { OnPointerDown((PointerEventData)data); }); trigger.triggers.Add(entryPointerDown); } protected override void OnEnable() { joyIsCanUse = false; offsetValue = Vector2.zero; } public override void OnDrag(PointerEventData eventData) { base.OnDrag(eventData); joyIsCanUse = true; //虚拟摇杆移动 Vector3 contentPosition = this.content.anchoredPosition; if (contentPosition.magnitude > mRadius) { contentPosition = contentPosition.normalized * mRadius; SetContentAnchoredPosition(contentPosition); }
// 摇杆内部按钮旋转 //if (content.anchoredPosition.y != 0) //{ // content.eulerAngles = new Vector3(0, 0, // Vector3.Angle(Vector3.right, content.anchoredPosition) * content.anchoredPosition.y / // Mathf.Abs(content.anchoredPosition.y) - 90); //} }
private void FixedUpdate() { if (joyIsCanUse) { JoystickMoveHandle?.Invoke(this.content); offsetValue = this.content.anchoredPosition3D; } }
public override void OnEndDrag(PointerEventData eventData) { base.OnEndDrag(eventData); joyIsCanUse = false; offsetValue = Vector2.zero; JoystickEndHandle?.Invoke(this.content); } // 随手落下设置摇杆位置 private void OnPointerDown(PointerEventData eventData) { Vector2 LocalPosition; RectTransformUtility.ScreenPointToLocalPointInRectangle(this.GetComponent<RectTransform>(), eventData.position, eventData.pressEventCamera, out LocalPosition); this.viewport.localPosition = LocalPosition; }
// 抬起还原位置 private void OnPointerUp(PointerEventData eventData) { this.viewport.anchoredPosition3D = Vector3.zero; }
}
复制代码



3.3 实现效果

按钮素材图片:




实现效果:





源码和步骤都在上面分享过了,若还有什么不明白的,可以留言评论哦。


发布于: 刚刚阅读数: 2
用户头像

陈言必行

关注

公号:开发同学留步 2019-03-12 加入

我是一个从事Unity游戏开发攻城狮,InfoQ&阿里云签约博主,CSDN博客专家,U3D论坛版主,6年开发经验,助你日常不加班。⽂章皆为从零到⼀的⼊⻔级教程,也有很多⼯作中遇到的问题解析。

评论

发布
暂无评论
Unity 之 使用原生UGUI实现随手移动摇杆功能经典实例_Unity_陈言必行_InfoQ写作社区