实现效果
本文最终实现效果:
一,实现思路
1.1 原理解析
做一个实验看一下使用ScrollRect
组件实现摇杆的原理。
-
在
Hierarchy
面板右键UI
->Scroll View
创建一个滚动视图,这个组件经常被应用于排行榜,选角色之类的可滑动的界面。 -
在
Scroll View
->Viewport
->Content
添加一个Image组件 -
运行场景,鼠标点击并拖动中间部分,即可看到如下效果:
看到这里基本了解实现思路了吧,其实就是通过Scroll Rect
组件的Context和Viewport的关系来进行模拟的。
更多关于ScrollRect的使用方法和实战应用,可以查看:Unity 之 UGUI Scroll Rect滚动矩形组件详解
1.2 思路概述
-
随手指落下位置
思路:其实就是根据手指第一次落下的屏幕坐标,修改摇杆的初始位置;手抬起时再将摇杆位置还原
知识点:获取手指按下和抬起的回调,将手指落下坐标转换为屏幕UI坐标 -
摇杆移动
思路:使用Scroll Rect
的移动回调,来控制中间的虚拟摇杆进行位置变化
注意的点:使用OnDrag进行回调,并来控制虚拟摇杆的标移动位置不要超出背景 -
移动回调
思路:当使用摇杆时使用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 实现效果
按钮素材图片:
实现效果:
文章来源:https://www.toymoban.com/news/detail-796342.html
工程下载:源码和步骤都在上面分享过了,若还有什么不明白的,可以 点击链接下载 ,积分不够的童鞋关注下方卡片,回复:“摇杆” 即可获得开篇Demo源码~文章来源地址https://www.toymoban.com/news/detail-796342.html
到了这里,关于Unity 之 使用原生UGUI实现随手移动摇杆功能经典实例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!