Unity3d_UGUI虚拟摇杆(简易)

       之前的项目中有用虚拟摇杆来操纵角色移动,但是之前使用的是EasyTouch,属于NGUI下的一个插件,但是本身项目是基于UGUI的,觉得这样掺杂在一起有些不伦不类,就自己用UGUI做了一个简易的虚拟摇杆(可以实现给角色移动脚本发出摇杆的偏移参数类似于EasyTouch),若要实现更加复杂的功能,可以参照EasyTouch自行编写。

       不多说下面开始实现步骤:(写这篇文章的时候离制作有些久了,有些地方可能有遗忘或者错误请见谅)

一、UGUI上接受拖拽事件。

       我们项目基于Android平台,所以要考虑一些点击,拖动什么的能不能得到相应,然后在网上搜到了这篇帖子:

(雨松MOMO:UGUI研究院之控件以及按钮的监听事件系统(五))原文:http://www.xuanyusong.com/archives/3325


这是监听事件的脚本:EventTriggerListener.cs


using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;

public class EventTriggerListener : UnityEngine.EventSystems.EventTrigger
{
	public delegate void VoidDelegate (GameObject go);
	public VoidDelegate onClick;
	public VoidDelegate onDown;
	public VoidDelegate onEnter;
	public VoidDelegate onExit;
	public VoidDelegate onUp;
	public VoidDelegate onSelect;
	public VoidDelegate onUpdateSelect;
	
	static public EventTriggerListener Get (GameObject go)
	{
		EventTriggerListener listener = go.GetComponent<EventTriggerListener>();
		if (listener == null) listener = go.AddComponent<EventTriggerListener>();
			return listener;
	}

	public override void OnPointerClick(PointerEventData eventData)
	{
		if(onClick != null) 	onClick(gameObject);
	}

	public override void OnPointerDown (PointerEventData eventData)
	{
		if(onDown != null) onDown(gameObject);
	}

	public override void OnPointerEnter (PointerEventData eventData)
	{
		if(onEnter != null) onEnter(gameObject);
	}

	public override void OnPointerExit (PointerEventData eventData)
	{
		if(onExit != null) onExit(gameObject);
	}

	public override void OnPointerUp (PointerEventData eventData)
	{
		if(onUp != null) onUp(gameObject);
	}

	public override void OnSelect (BaseEventData eventData)
	{
		if(onSelect != null) onSelect(gameObject);
	}

	public override void OnUpdateSelected (BaseEventData eventData)
	{
		if(onUpdateSelect != null) onUpdateSelect(gameObject);
	}
}


二、虚拟摇杆的实现

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEngine.Events;

public class JoyStick : MonoBehaviour 
{
	public float fJoyTouchRadius;
	public float fJoyAreaRadius;
	
	private Image joyTouchImage;
	private Image jouAreaImage;

	private bool bIsActived;//是否触发
	public bool BIsActived
	{
		get{ return bIsActived; }
	}
	
	private bool bIsLocked = false;//是否上锁
	public bool BIsLocked
	{
		get{ return bIsLocked; }
		set
		{ 
			bIsLocked = value; 
			if(bIsLocked)
			{
				if(joyTouchImage)
				{
					joyTouchImage.transform.position = initPos;
					//将偏移量归零
					JoyStickAxis = Vector2.zero;
					//角色移动函数
					if(joyStickMoveEnd != null)
						joyStickMoveEnd();
				}
			}
		}
	}
	private float fDragRadius;//可拖动的半径
	private Vector3 initPos;//初始位置
	private float fScreenRate;//屏幕比率
	private Vector2 JoyStickAxis;//用来传值给角色控制器
	
	//角色移动代理函数
	public delegate void JoyStickMove(Vector2 joyStickOffset);
	public static event JoyStickMove joyStickMove;
	
	//角色停止移动代理函数
	public delegate void JoyStickMoveEnd();
	public static event JoyStickMoveEnd joyStickMoveEnd;
	
	void Start () 
	{
		//我这边自己做的自适应,后面的GlobalManager.iScreenWitdh是你默认的屏幕宽度,其实可以用UGUI里面的
		//Horizontal Layout Group来控制自适应
		fScreenRate = (float)Screen.width / GlobalManager.iScreenWitdh;
		joyTouchImage = transform.FindChild("JoyTouch").GetComponent<Image>();
		jouAreaImage = transform.FindChild("JoyArea").GetComponent<Image>();
		
		//设置joystick的大小
		joyTouchImage.rectTransform.localScale = new Vector2 (fJoyTouchRadius, fJoyTouchRadius);
		jouAreaImage.rectTransform.localScale = new Vector2 (fJoyAreaRadius, fJoyAreaRadius);
		
		//可拖拽的半径
		fDragRadius = jouAreaImage.rectTransform.rect.width * fJoyAreaRadius * fScreenRate * 0.5f;
		
		initPos = new Vector3 (1, 1, 0) * fDragRadius * 1.2f;//1.2距离侧边的距离放大1.2倍,这边可以自己后面更改
		
		joyTouchImage.transform.position = initPos;
		jouAreaImage.transform.position = initPos;
		
		//给joytouch注册事件
		EventTriggerListener.Get (joyTouchImage.gameObject).onDown = OnJoyTouchDown;
		EventTriggerListener.Get (joyTouchImage.gameObject).onUp = OnJoyTouchUp;
		
		//给joyarea注册事件
		EventTriggerListener.Get (jouAreaImage.gameObject).onDown = OnJoyTouchDown;
		EventTriggerListener.Get (jouAreaImage.gameObject).onUp = OnJoyTouchUp;
	}
	
	void Update()
	{
		#if UNITY_ANDROID
//		if (Input.touchCount > 1)
//			return;
		//这边会有一个bug就是当你在拖拽摇杆的时候,点击屏幕别的地方,摇杆会向点击处偏移
		//我没有找到很好的解决方法,暂时是用多点触控屏蔽的方法
		#endif
		
		if(bIsActived && !bIsLocked)
		{
			//joy世界坐标坐标
			Vector3 wJoyTouchPos = joyTouchImage.transform.position;
			
			//鼠标屏幕坐标
			Vector3 mScreenPosition = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, wJoyTouchPos.z);
			
			//获得鼠标和对象之间的偏移量,拖拽时相机应该保持不动
			Vector3 offset = wJoyTouchPos - mScreenPosition;		
			
			//对象新坐标 
			joyTouchImage.transform.position -= offset;
			
			//判断与初始位置的距离,之所以不用世界坐标是因为本身半径要转化为世界坐标的半径,麻烦
			float fDis = Vector3.Distance(joyTouchImage.transform.position, initPos);
			
			//当相对位置大于可拖动的半径的时候,按比例缩减
			if(fDis > fDragRadius)
			{
				joyTouchImage.transform.position = initPos + 
					(joyTouchImage.transform.position - initPos) * fDragRadius / fDis;
			}
			
			//虚拟摇杆偏移量
			JoyStickAxis.x = (joyTouchImage.transform.position.x - initPos.x) / fDragRadius;
			JoyStickAxis.y = (joyTouchImage.transform.position.y - initPos.y) / fDragRadius;

			//角色移动函数
			if(joyStickMove != null)
				joyStickMove(JoyStickAxis);
		}
	}
	
	//当触碰虚拟摇杆的进入
	private void OnJoyTouchDown(GameObject go)
	{
		if(go == joyTouchImage.gameObject || go == jouAreaImage.gameObject)
		{
			bIsActived = true;
		}
	}
	
	//当触碰虚拟摇杆的退出
	private void OnJoyTouchUp(GameObject go)
	{
		if(go == joyTouchImage.gameObject || go == jouAreaImage.gameObject)
		{
			bIsActived = false;

			//回到原位
			joyTouchImage.transform.position = initPos;
			//将偏移量归零
			JoyStickAxis = Vector2.zero;

			//角色停止移动函数
			if(joyStickMoveEnd != null)
				joyStickMoveEnd();
		}
	}
}
该脚本的核心处就是Update里面,我写的效率不是很高,可以自行改写。


三、具体操作方式

1.在canvas下创建一个空的JoyStick,该joyStick放在canvas的最下面,否则会被其他控件覆盖掉(UGUI就是这点很烦不能更改控件的Depth)。

2.在joystick下创建2个sprite,给两张转为2dSperite的图片(joyTouch在joyArea的下面)输入缩放大小,本来我这边还有参数设置初始位置,但是后面做自适应找到一个比较适中的值就去掉了,需要的可以自行编写。

3.在角色控制移动脚本处

加入:

void OnEnable()  
{  
	JoyStick.joyStickMove += JoystickMove;
	JoyStick.joyStickMoveEnd += JoystickMoveEnd;
} 

void OnDisable()  
{  
	JoyStick.joyStickMove -= JoystickMove;
	JoyStick.joyStickMoveEnd -= JoystickMoveEnd;
} 
还有就是:

public void JoystickMoveEnd()
{
	//摇杆停止移动响应函数
}
public void JoystickMove(Vector2 joyPos)
{
	//摇杆开始移动响应函数,这边的joyPos就是摇杆偏移量
}

差不多就做好了一个UGUI的简易虚拟摇杆,没有什么扩展功能,没有进行什么优化,如果有什么更好的改进方法请私信我,谢谢!



  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值