今天学习案例项目时,需要制作摇杆,我 就把这个摇杆制作过程记录一下,以便以后忘记了可以查看。
摇杆分为三个部分,
1.摇杆可以出现的区域
2.摇杆背景图
3.摇杆中心可以拖动的圆点
----------------------代码部分-----------------
创建PEListener(UI事件监听插件类):用于监听摇杆的点击、拖拽等事件,通过代码挂载在摇杆获取区域(imgTouch)物体上
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class PEListener : MonoBehaviour,IPointerDownHandler ,IPointerUpHandler ,IDragHandler {
public Action<PointerEventData> onClickDown;
public Action<PointerEventData> onClickUp;
public Action<PointerEventData> onDrag;
public void OnPointerDown(PointerEventData eventData)
{
if(onClickDown !=null )
{
onClickDown(eventData);
}
}
public void OnPointerUp(PointerEventData eventData)
{
if (onClickUp != null)
{
onClickUp(eventData);
}
}
public void OnDrag(PointerEventData eventData)
{
if (onDrag != null)
{
onDrag(eventData);
}
}
}
在WindowRoot(UI窗口基类)中定义需要监听的事件
//判断物体是否有某个组件 如果没有给这物体添加这个组件
protected T GetOrAddComponect<T>(GameObject go) where T:Component
{
T t = go.GetComponent<T>();
if(t==null )
{
t= go.AddComponent<T>();
}
return t;
}
#region ClickEvts
protected void OnClickDown(GameObject go,Action<PointerEventData>cb)
{
PEListener listener = GetOrAddComponect<PEListener>(go);
listener.onClickDown = cb;
}
protected void OnClickUp(GameObject go, Action<PointerEventData> cb)
{
PEListener listener = GetOrAddComponect<PEListener>(go);
listener.onClickUp = cb;
}
protected void OnDrag(GameObject go, Action<PointerEventData> cb)
{
PEListener listener = GetOrAddComponect<PEListener>(go);
listener.onDrag = cb;
}
#endregion
在MainCityWnd(主城UI界面)类中获取摇杆,继承WindowRoot类,脚本挂载在主城UI界面的根物体并编写监听的具体事件,然后把位置信息传递给主角就OK了,
public void RegisterTouchEvts()
{
OnClickDown(imgTouch.gameObject, (PointerEventData evt) =>
{
startPos = evt.position;
SetActive(imgDirPoint, true);
imgDirBg.transform.position = evt.position;
});
OnClickUp(imgTouch.gameObject, (PointerEventData evt) =>
{
SetActive(imgDirPoint, false);
imgDirBg.transform.position = defaultPos;
imgDirPoint.transform.localPosition = Vector2.zero;
//方向信息传递给主角
MainCitySys.Instance.SetMoveDir(Vector2.zero );
});
OnDrag(imgTouch.gameObject, (PointerEventData evt) =>
{
Vector2 dir= evt.position - startPos;
float len = dir.magnitude;
if(len>pointDis )
{
Vector2 clampDir = Vector2.ClampMagnitude(dir, pointDis );
imgDirPoint.transform.position = startPos + clampDir;
}
else
{
imgDirPoint.transform.position = evt.position;
}
//方向信息传递给主角
MainCitySys.Instance.SetMoveDir(dir.normalized);
});
}
MainCitySys(主城系统),加载主角模型,打开主城UI界面,播放背景音乐
//获取坐标位置
public void SetMoveDir(Vector2 dir)
{
if(dir ==Vector2.zero )
{
playerCtrl.SetBlend(Constants.BlendIdle);
}
else
{
playerCtrl.SetBlend(Constants.BlendWald );
}
//把坐标位置传递给主角(这个坐标使用Vector2.SignedAngle(),可以得出自身坐标与世界坐标的之间的角度,继而主角进行方向旋转)
playerCtrl.Dir = dir;
}
第二种写法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class UIJointed : MonoBehaviour, IPointerDownHandler,IPointerUpHandler ,IDragHandler
{
public Image IconImage;//摇杆内的小圆
private Vector3 startPos;//小圆的初始化位置
public int radius=5;//半径
[HideInInspector]
public bool isMove = false;//是否移动
[HideInInspector]
public Vector3 mdaltc;//摇杆控制的方向信息,
//方向
[HideInInspector]
public float angle=0;//摇杆控制的旋转角度信息
public RectTransform Jointed;//摇杆
RectTransform rect;//摇杆的矩形背景,显示的区域
private Vector2 thisPos;//摇杆初始位置
void Start()
{
Jointed.gameObject.SetActive(false);//隐藏摇杆
rect = GetComponent<RectTransform>();
//获取初始化位置
startPos = IconImage.transform.localPosition;
thisPos = Jointed. transform.localPosition;
}
/// <summary>
/// 拖拽中
/// </summary>
/// <param name="eventData"></param>
public void OnDrag(PointerEventData eventData)
{
// Debug.Log("This is Drag");
Vector2 uiPoint;//获取鼠标在摇杆背景上的位置
//将一个屏幕空间坐标转换到RectTransform本地空间位于矩形上的一个位置
RectTransformUtility.ScreenPointToLocalPointInRectangle(Jointed as RectTransform, Input.mousePosition, eventData.pressEventCamera, out uiPoint);
Range(uiPoint);
}
//小圆是否超出范围
void Range(Vector3 uiPoint)
{
isMove = true;
Vector2 delta = uiPoint - startPos;//方向
if ((uiPoint - startPos).magnitude < radius)//移动时向量的长度小于半径,即在范围内
{
//拖拽时 小圆在摇杆上的位置
IconImage.transform.localPosition = uiPoint;
}
else//超出范围
{
Vector3 v= Vector3.ClampMagnitude(delta, radius);//现在一个方向的最大长度
//delta.Normalize();//向量归一化
//delta *= radius;//最大
IconImage.transform.localPosition = v + startPos;
}
mdaltc = IconImage.transform.localPosition - startPos;
#region 摇杆控制的角度信息
float dotValue = Vector2.Dot(Vector2.up.normalized, mdaltc.normalized);//两个向量夹角的余弦值
angle= Mathf.Acos(dotValue)*Mathf.Rad2Deg;//通过余弦值获得弧度角,转换为角度
if(delta .x>0)
{
angle = -angle;
}
#endregion
}
/// <summary>
/// 按下
/// </summary>
/// <param name="eventData"></param>
public void OnPointerDown(PointerEventData eventData)
{
Jointed.gameObject.SetActive(true);//显示摇杆
Vector2 uiPoint;
//将一个屏幕上的位置转换到一个矩形上的位置
RectTransformUtility.ScreenPointToLocalPointInRectangle(transform as RectTransform, Input.mousePosition, eventData.pressEventCamera, out uiPoint);
Jointed.localPosition = uiPoint;//设置摇杆出现的位置
}
/// <summary>
/// 抬起
/// </summary>
/// <param name="eventData"></param>
public void OnPointerUp(PointerEventData eventData)
{
Jointed.gameObject.SetActive(false);
Jointed.localPosition = thisPos ;//摇杆恢复初始位置
IconImage.transform.localPosition = startPos;//小球恢复到原来位置
isMove = false;//不能移动
mdaltc = Vector3.zero;//方向置空
angle = 0;//角度置零
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//挂载需要用摇杆控制的物体上,
public class JointedMove : MonoBehaviour
{
UIJointed ui;
public float Speed = 10;//移动 速度
void Awake()
{
ui = GameObject.FindObjectOfType<UIJointed>();
}
void Update()
{
Debug.Log(ui.name);
if (ui.isMove )
{
//移动
transform.localPosition += ui.mdaltc * Speed * Time.deltaTime;
//旋转
transform.localEulerAngles =new Vector3 (0,0,ui.angle );
}
}
}