Unity学习之利用UGUIScrollRect组件制作手游摇杆控件
今天和朋友聊天的时候听说某大厂做手游摇杆是用UGUI实现的,想想自己以前做手游的时候都是用的Easy Tocuh插件,于是很好奇是如何实现的。于是在大佬的协助下缕清了思路,如何用UGUI的ScrollRect组件制作手游的摇杆控件。
首先创建一个空项目,在场景内创建一个Scroll View并移动至Canvas的左下角:
我是将Scroll View的锚点定在Canvas的左下角并给PosX和PosY均赋值为150,如下图:
选中Scroll View,在Inspector面板找到Scroll Rect组件,将HZ喎?/kf/ware/vc/" target="_blank" class="keylink">vcml6b250YWwgU2Nyb2xsYmFyPC9zdHJvbmc+us08c3Ryb25nPlZlcnRpY2FsIFNjcm9sbGJhcjwvc3Ryb25nPs/Cw+a1xDxzdHJvbmc+VmlzaWJsaXR5PC9zdHJvbmc+vvnJ6NbDzqo8c3Ryb25nPkF1dG8gSGlkZTwvc3Ryb25nPjwvcD4NCjxwPjxpbWcgYWx0PQ=="" src="/uploadfile/Collfiles/20180505/20180505091217359.png" title="\" />
选中Viewport,将锚点设置在左上角,给PosX和PosY赋值为0,给Width和Height赋值为200(和Scroll Rect的Width、Height相同),再选中Content,重复操作
顺带一提,我还将右边和下边的拖拽条隐藏掉并且不接收射线,并且去掉了Viewport的Mask组件,具体操作各位道友们可以自行实现。
创建脚本,我命名为MobileRockerController,拖拽脚本给Content,现添加代码如下:
// MobileRockerController.cs written by Fumiki at 2018-05-04 using UnityEngine; using UnityEngine.UI; namespace Com.MobileRocker.Fumiki { public class MobileRockerController : MonoBehaviour { ////// 手机摇杆 /// [SerializeField] private RectTransform rocker; private void Awake() { if (rocker == null) rocker = gameObject.GetComponent(); private void Update() { Debug.Log(rocker.anchoredPosition); } } }
这时已经可以看到有手柄的效果了,Console输出的就是拖拽Content后Update方法中反馈回来的Content的二维锚点坐标值:
为了美化,我还顺手设置了一下Scroll View的Image组件的颜色,也给Content添加了一个Image组件,使用了UGUI的圆形贴图并设置了一下颜色(暂时先不上图了,有点Low)。
删除Content上的MobileRockerController脚本,并将脚本重新绑定给Scroll View,改写脚本如下:
using System; using UnityEngine; using UnityEngine.UI; namespace Com.MobileRocker.Fumiki { public class MobileRockerController : MonoBehaviour { #region 将手机摇杆类设置为单例类 private MobileRockerController() { } private MobileRockerController(ref MobileRockerController reference) { } private static MobileRockerController instance = null; public static MobileRockerController Instance { get { return instance; } } #endregion ////// 手机摇杆基座 /// [SerializeField] private RectTransform rockerBase = null; ////// 手机摇杆 /// [SerializeField] private RectTransform rocker = null; ////// 手机摇杆横纵偏移量 /// [SerializeField] private Vector2 rockerOffset = Vector2.zero; ////// 外部获取手机摇杆横纵偏移量的接口属性[只读] /// public Vector2 RockerOffset { get { return rockerOffset; } } private void Awake() { if (instance == null) instance = this; if (rockerBase == null) rockerBase = gameObject.GetComponent(); if (rocker == null) rocker = gameObject.GetComponent ().content; } private void Update() { SetAnchoredPosToRockerOffset(); } /// /// 将摇杆的锚点坐标转换为偏移量 /// private void SetAnchoredPosToRockerOffset() { // 分别获取摇杆基座宽高的一般用以后面的判断 float halfBaseX = rockerBase.sizeDelta.x / 2.0f; float halfBaseY = rockerBase.sizeDelta.y / 2.0f; // 判断以设定边界 if (rocker.anchoredPosition.x > halfBaseX) { if (rocker.anchoredPosition.y > halfBaseY) rockerOffset = new Vector2(1.0f, 1.0f); else if (rocker.anchoredPosition.y < -halfBaseY) rockerOffset = new Vector2(1.0f, -1.0f); else rockerOffset = new Vector2(1.0f, rocker.anchoredPosition.y / 100.0f); } else if (rocker.anchoredPosition.x < -halfBaseX) { if (rocker.anchoredPosition.y > halfBaseY) rockerOffset = new Vector2(-1.0f, 1.0f); else if (rocker.anchoredPosition.y < -halfBaseY) rockerOffset = new Vector2(-1.0f, -1.0f); else rockerOffset = new Vector2(-1.0f, rocker.anchoredPosition.y / 100.0f); } else { if (rocker.anchoredPosition.y > halfBaseY) rockerOffset = new Vector2(rocker.anchoredPosition.x / 100.0f, 1.0f); else if (rocker.anchoredPosition.y < -halfBaseY) rockerOffset = new Vector2(rocker.anchoredPosition.x / 100.0f, -1.0f); else rockerOffset = new Vector2(rocker.anchoredPosition.x / 100.0f, rocker.anchoredPosition.y / 100.0f); } // 设定偏移量的精度 rockerOffset = new Vector2(Convert.ToSingle(Math.Round(rockerOffset.x, 2)), Convert.ToSingle(Math.Round(rockerOffset.y, 2))); } } }
这样其他需要和摇杆挂钩的GameObject就可以调用MobileRockerController.Instance.RockerOffset获取手柄的偏移量并根据自己的需求编写逻辑了。
最后上一张效果图,庆祝一下我第一次用UGUI做出的简易手柄:
简单介绍一下,这是用通过手柄的偏移量给小球增加扭力使小球滚动的一个小demo,虽然粗糙了一些,不过证明了手柄确实可用。
顺带附上没有注释的小球脚本(小球绑定了刚体):
using UnityEngine; namespace Com.MobileRocker.Fumiki { public class PlayerController : MonoBehaviour { private Vector3 forceOffset = Vector3.zero; void Update() { forceOffset = new Vector3(MobileRockerController.Instance.RockerOffset.y, 0, -MobileRockerController.Instance.RockerOffset.x); gameObject.GetComponent().AddTorque(forceOffset * 50, ForceMode.Force); } } }