using UnityEngine;
using System.Collections.Generic;
[ExecuteInEditMode]
public class SmartJoystick : MonoBehaviour
{
public delegate void SmartJoystickEventHandler(SmartJoystick joystick);
public static event SmartJoystickEventHandler OnHoldingHandler;
public static event SmartJoystickEventHandler OnPressDownHandler;
public static event SmartJoystickEventHandler OnPressUpHandler;
public static event SmartJoystickEventHandler OnDragingHandler;
public enum EAlign { TopLeft, Top, TopRight, Left, Center, Right, BottomLeft, Bottom, BottomRight }
public bool IsDisable { get; set; }
public bool IsHolding { get; set; }
public bool IsPressing { get; private set; }
public bool IsDragging { get; private set; }
public int PressedDegree { get; private set; }
public Vector2 CurrentAxis { get; private set; }
public float CurrentRadian { get { return Mathf.Atan2(CurrentAxis.x, CurrentAxis.y); } }
public float CurrentDegree { get { return Mathf.Atan2(CurrentAxis.x, CurrentAxis.y) * Mathf.Rad2Deg; } }
public float CurrentEulerAngles
{
get
{
var a = Mathf.Atan2(CurrentAxis.x, CurrentAxis.y) / Mathf.Deg2Rad;
a = a < 0 ? 360 + a : a;
return -a;
}
}
public Texture Pedestal;
public Texture Thumb;
public int PedestalRadius = 200;
public int ThumbRadius = 80;
public int Depth = 5;//摇杆所在层
public EAlign Align = EAlign.BottomLeft;//设置对齐方式
public bool IsNoReturn = true;//摇杆不返回
public bool IsAttachEdge = true;//磁性吸附
public bool IsCanPressed = false;//可按压受力
public bool IsRebuildThumb = false;//是否重建摇杆
GameObject m_thumb;
UIRoot m_root;
Camera m_camera;
Vector3 m_thumbPosition;//摇杆当前向量
#region 系统函数
void Start()
{
var pedestalDiameter = PedestalRadius * 2;
var thumbDiameter = ThumbRadius * 2;
//挂载到相机
m_root = FindObjectOfType<UIRoot>();
m_camera = m_root.transform.FindChild("Camera").GetComponent<Camera>();
UICamera.currentCamera = m_camera;
transform.SetParent(m_camera.transform);
//半径转直径
transform.rotation = Quaternion.identity;//设置角度
transform.localScale = Vector3.one;//设置尺寸比例
//配置脚本
gameObject.AddMissingComponent<UISprite>();
GetComponent<UISprite>().depth = Depth;//设置游戏分层
GetComponent<UISprite>().spriteName = Pedestal.name;设置基座图集名称
gameObject.AddMissingComponent<BoxCollider>();
GetComponent<BoxCollider>().size = new Vector3(pedestalDiameter, pedestalDiameter);//注意半径和直径的转换
GetComponent<BoxCollider>().isTrigger = true;
//创建摇杆实体
if (IsRebuildThumb)
{
gameObject.transform.DestroyChildren();//清空子物体
m_thumb = new GameObject("thumb");//创建摇杆
m_thumb.transform.SetParent(gameObject.transform);//设置挂载父级
m_thumb.transform.localPosition = Vector3.zero;//重置相对位置
m_thumb.gameObject.AddMissingComponent<UISprite>();
m_thumb.GetComponent<UISprite>().atlas = GetComponent<UISprite>().atlas;//设置图集
m_thumb.GetComponent<UISprite>().spriteName = Thumb.name;//设置摇杆图集名称
m_thumb.GetComponent<UISprite>().depth = Depth;//设置游戏分层
m_thumb.transform.rotation = Quaternion.identity;//设置角度
m_thumb.transform.localScale = Vector3.one;//设置尺寸比例
//设置标签和层
m_thumb.tag = gameObject.tag;
m_thumb.layer = gameObject.layer;
//设置尺寸,注意半径和直径区别
GetComponent<UISprite>().width = pedestalDiameter;//设置宽度
GetComponent<UISprite>().height = pedestalDiameter;//设置高度
m_thumb.GetComponent<UISprite>().width = thumbDiameter;//设置宽度
m_thumb.GetComponent<UISprite>().height = thumbDiameter;//设置高度
}
else
{
m_thumb = gameObject.transform.FindChild("thumb").gameObject;
if (m_thumb == default(GameObject))
{
Debug.LogError(gameObject.name + "`s thumb object not exist!");
}
}
//尺寸调整
GetComponent<UISprite>().width = pedestalDiameter;
GetComponent<UISprite>().height = pedestalDiameter;
m_thumb.GetComponent<UISprite>().width = thumbDiameter;
m_thumb.GetComponent<UISprite>().height = thumbDiameter;
//属性初始化
IsDisable = false;
IsHolding = false;
IsPressing = false;
IsDragging = false;
PressedDegree = 0;//初始化压力
CurrentAxis = Vector2.zero;//初始化向量
//设定初始化
m_thumbPosition = Vector3.zero;//初始化摇杆向量
resetPosition();//调整摇杆位置
}
void FixedUpdate()
{
if (IsDisable)
{
m_thumb.transform.localPosition = Vector3.zero;
CurrentAxis = Vector2.zero;
}
if (IsHolding && OnHoldingHandler != null) OnHoldingHandler(this);//暂停委托处理
resetPosition();//调整摇杆位置
//判断是否启用按压记录
if (IsCanPressed && IsPressing) PressedDegree++;//记录按压力
//判断拖拽: 当拖拽状态且不移动时,则认为已停止拖拽
if (IsDragging && m_thumb.transform.localPosition.Equals(m_thumbPosition)) IsDragging = false;//重置拖拽标志
m_thumbPosition = m_thumb.transform.localPosition;//保存摇杆向量
}
void OnPress(bool isPressed)
{
if (IsDisable) return;//禁用时直接返回
resetThumb();//处理摇杆位置
IsPressing = isPressed;
if (isPressed)
{//按压时
if (OnPressDownHandler != null) OnPressDownHandler(this);//按压委托处理
}
else
{//抬起时
PressedDegree = 0;//重置压力
//摇杆返回处理
if (!IsNoReturn)
{
m_thumb.GetComponent<UISprite>().transform.localPosition = Vector3.zero;
CurrentAxis = Vector2.zero;//重置向量
}
if (OnPressUpHandler != null) OnPressUpHandler(this);//抬起委托处理
}
}
void OnDrag(Vector2 delta)
{
if (IsDisable) return;//禁用时直接返回
resetThumb();//处理摇杆位置
IsDragging = true;
if (OnDragingHandler != null) OnDragingHandler(this);//拖拽委托处理
}
#endregion
#region 计算处理函数
//重置位置
void resetPosition()
{
//计算偏移量
float offset = PedestalRadius;
float xPos, yPos;
//摇杆对齐屏幕
switch (Align)
{
case EAlign.TopRight:
case EAlign.Right:
case EAlign.BottomRight:
xPos = -offset;
break;
case EAlign.TopLeft:
case EAlign.Left:
case EAlign.BottomLeft:
xPos = offset;
break;
default:
xPos = 0;
break;
}
switch (Align)
{
case EAlign.TopLeft:
case EAlign.Top:
case EAlign.TopRight:
yPos = -offset;
break;
case EAlign.BottomLeft:
case EAlign.Bottom:
case EAlign.BottomRight:
yPos = offset;
break;
default:
yPos = 0;
break;
}
alignToScreen(Align, transform, new Vector3(xPos, yPos, 0));
}
//对齐到屏幕
void alignToScreen(EAlign side, Transform trans, Vector2 pixelOffset = default(Vector2), Vector2 relativeOffset = default(Vector2))
{
var uiCamera = NGUITools.FindCameraForLayer(gameObject.layer);
var rect = uiCamera.pixelRect;
var cx = (rect.xMin + rect.xMax) * 0.5f;
var cy = (rect.yMin + rect.yMax) * 0.5f;
var v = new Vector3(cx, cy, 0f);
if (side != EAlign.Center)
{
switch (side)
{
case EAlign.TopRight:
case EAlign.Right:
case EAlign.BottomRight:
v.x = rect.xMax;
break;
case EAlign.Top:
case EAlign.Center:
case EAlign.Bottom:
v.x = cx;
break;
default:
v.x = rect.xMin;
break;
}
switch (side)
{
case EAlign.TopLeft:
case EAlign.Top:
case EAlign.TopRight:
v.y = rect.yMax;
break;
case EAlign.Left:
case EAlign.Center:
case EAlign.Right:
v.y = cy;
break;
default:
v.y = rect.yMin;
break;
}
}
v.x += pixelOffset.x + relativeOffset.x * rect.width;
v.y += pixelOffset.y + relativeOffset.y * rect.height;
if (uiCamera.orthographic)
{
v.x = Mathf.Round(v.x);
v.y = Mathf.Round(v.y);
}
v.z = uiCamera.WorldToScreenPoint(trans.position).z;
v = uiCamera.ScreenToWorldPoint(v);
if (uiCamera.orthographic && trans.parent != default(Transform))
{
v = trans.parent.InverseTransformPoint(v);
v.x = Mathf.RoundToInt(v.x);
v.y = Mathf.RoundToInt(v.y);
if (trans.localPosition != v) trans.localPosition = v;
}
else if (trans.position != v)
{
trans.position = v;
}
}
//重置摇杆位置
void resetThumb()
{
var offset = getPos(UICamera.currentTouch.pos) - transform.localPosition;
var radius = PedestalRadius - ThumbRadius;//基座半径去除摇杆半径
//向量的长度超过半径后规范化
if (offset.magnitude > radius)
{
//按向量为1规范化后重新计算长度,并限定摇杆最大边缘位置
offset = offset.normalized * radius;
}
else if (offset.magnitude > 0 && IsAttachEdge)
{
//当返回向量长度大于0且开启了吸附边缘,则直接将摇杆置于边缘吸附
offset = offset.normalized * radius;
}
m_thumb.transform.localPosition = offset;//设定摇杆位置
CurrentAxis = new Vector2(offset.x / radius, offset.y / radius);//保存向量
}
//获得NGUI坐标
Vector3 getPos(Vector2 pos)
{
var uiPos = m_camera.ScreenToWorldPoint(new Vector3(pos.x, pos.y, 0f));
uiPos = m_camera.transform.InverseTransformPoint(uiPos);
return uiPos;
}
#endregion
#region 激活、禁用处理
readonly List<string> m_keys = new List<string>();
public string DisableSequence()
{
var key = System.Guid.NewGuid().ToString();//生成唯一key
m_keys.Add(key);
IsDisable = true;
return key;
}
public void EnableSequence(string key)
{
if (m_keys.Contains(key)) m_keys.Remove(key);//有钥匙时移除钥匙序列
if (m_keys.Count == 0) IsDisable = false;//当所有钥匙都移除后启动
}
#endregion
}
SmartJoystick.cs
最新推荐文章于 2023-06-15 14:26:10 发布