2013-02-27 21:55:56 OnInit 阅读数 1110


 

using UnityEngine;
using System.Collections;

public class CcJoystick : MonoBehaviour
{
    public Transform m_Bg;//背景框框
    public Transform m_Icon;//小球
    float m_fRadius = 100f;//大圆半径

    private bool IsDown = false;
    private bool IsIn = false;

    void Awake()
    {
        onTouchEnd();
    }

    void OnPress(bool pressed)
    {

        if (enabled && gameObject.activeSelf && m_Icon && m_Bg)
        {
            IsDown = true;
            if (pressed)
            {
                m_Icon.parent.gameObject.SetActive(true);
                Vector2 clickPos = Input.mousePosition;
                m_Icon.localPosition = new Vector3(clickPos.x, clickPos.y, m_Icon.localPosition.z);
                m_Bg.localPosition = new Vector3(clickPos.x, clickPos.y, m_Icon.localPosition.z);
              
                OnDrag(Vector2.zero);
            }
            else
            {
               onTouchEnd();
            }
        }
    }
    float m_fMoveSpeed = 50f;
    public void OnDrag(Vector2 delta)
    {
        if (enabled && gameObject.activeSelf && m_Icon && m_Bg)
        {
            Vector2 clickPos = Input.mousePosition;
            m_Icon.localPosition = new Vector3(clickPos.x, clickPos.y, m_Icon.localPosition.z);

            if (GetRadius() <= m_fRadius)
            {
                IsIn = true;
            }
            if (GetRadius() > m_fRadius)
            {
                //*(大圆半径-小圆半径)
                Vector3 toPos = new Vector3((Mathf.Cos(GetRockerDir()) * (m_fRadius - 20)), 
                    (Mathf.Sin(GetRockerDir()) * (m_fRadius - 20)), 0);

                m_Bg.localPosition = toPos;//Vector3.Lerp(m_Bg.localPosition, toPos, m_fMoveSpeed); 
            }
            UpdatePlayerMove();
          
        }
    }
 
   void UpdatePlayerMove() 
   {
       if (!IsIn || !IsDown || null == m_Bg || null == m_Icon)
        return;

       fX = (Mathf.Cos(GetRockerDir()) * GetRadius());
       fY = (Mathf.Sin(GetRockerDir()) * GetRadius());
       //在此处更新玩家位置<span style="font-family: Arial, Helvetica, sans-serif;">即可</span>fX fY 如player.x = fX;
    }     
      private void onTouchEnd()
      {
          if (null == m_Icon || null == m_Bg)
              return;

           m_Icon.parent.gameObject.SetActive(false);
           IsIn = IsDown = false;
           m_Icon.localPosition = m_Bg.localPosition = Vector3.zero;
           
      }
      private float GetRockerDir()
      {
          return Mathf.Atan2(m_Icon.localPosition.y - m_Bg.localPosition.y, m_Icon.localPosition.x - m_Bg.localPosition.x);
      }
      private float GetRadius()
      {
          return Mathf.Sqrt(Mathf.Pow((m_Icon.localPosition.x - m_Bg.localPosition.x), 2) +
              Mathf.Pow((m_Icon.localPosition.y - m_Bg.localPosition.y), 2));
      }
      void OnDestroy()
      {
          onTouchEnd();
      }
}



2017-10-17 12:19:14 m0_37998140 阅读数 1344

虚拟摇杆在移动游戏开发中,是很常见的需求,今天我们在Unity中,使用UGUI来实现一个简单的虚拟摇杆功能。

1.打开Unity,新创建一个UIJoystick.cs脚本,代码如下:

using UnityEngine;
using UnityEngine.EventSystems;

public class UIJoystick : MonoBehaviour, IDragHandler, IEndDragHandler
{   
    /// <summary>
	/// 被用户拖动的操纵杆
    /// </summary>
    public Transform target;

    /// <summary>
	/// 操纵杆可移动的最大半径
    /// </summary>
    public float radius = 50f;
    
    /// <summary>
	/// 当前操纵杆在2D空间的x,y位置
    /// 摇杆按钮的值【-1,1】之间
    /// </summary>
    public Vector2 position;
        
	//操纵杆的RectTransform组件
	private RectTransform thumb;

	void Start()
	{
		thumb = target.GetComponent<RectTransform>();
	}
		
    /// <summary>
	/// 当操纵杆被拖动时触发
    /// </summary>
    public void OnDrag(PointerEventData data)
	{
		//获取摇杆的RectTransform组件,以检测操纵杆是否在摇杆内移动
		RectTransform draggingPlane = transform as RectTransform;
		Vector3 mousePos;

		//检查拖动的位置是否在拖动rect内,
		//然后设置全局鼠标位置并将其分配给操纵杆
		if (RectTransformUtility.ScreenPointToWorldPointInRectangle (draggingPlane, data.position, data.pressEventCamera, out mousePos)) {
			thumb.position = mousePos;
		}
			
		//触摸向量的长度(大小)
		//计算操作杆的相对位置
		float length = target.localPosition.magnitude;

		//如果操纵杆超过了摇杆的范围,则将操纵杆设置为最大半径
		if (length > radius) {
			target.localPosition = Vector3.ClampMagnitude (target.localPosition, radius);
		}
			
		//在Inspector显示操纵杆位置
		position = target.localPosition;
		//将操纵杆相对位置映射到【-1,1】之间
		position = position / radius * Mathf.InverseLerp (radius, 2, 1);
	}
    /// <summary>
	/// 当操纵杆结束拖动时触发
    /// </summary>
    public void OnEndDrag(PointerEventData data)
	{
		//拖拽结束,将操纵杆恢复到默认位置
		position = Vector2.zero;
		target.position = transform.position;
	}
}

2.如图创建UGUI,所用资源可在网上自行下载。


效果图如下:

3.打包运行即可。得意这样一个简单的虚拟摇杆就实现了。

下面是对以上虚拟摇杆代码的扩展(ps:只是多了一些事件,便于其他脚本访问使用)废话不多说来代码了偷笑

using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;


// 
// Joystick component for controlling player movement and actions using Unity UI events.
// There can be multiple joysticks on the screen at the same time, implementing different callbacks.
// 
public class UIJoystick : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
   /// 
   /// Callback triggered when joystick starts moving by user input.
   /// 
   public event Action onDragBegin;
   
   /// 
   /// Callback triggered when joystick is moving or hold down.
   /// 
   public event Action onDrag;
   
   /// 
   /// Callback triggered when joystick input is being released.
   /// 
   public event Action onDragEnd;
  
   /// 
   /// The target object i.e. jostick thumb being dragged by the user.
   /// 
   public Transform target;

   /// 
   /// Maximum radius for the target object to be moved in distance from the center.
   /// 
   public float radius = 50f;
   
   /// 
   /// Current position of the target object on the x and y axis in 2D space.
   /// Values are calculated in the range of [-1, 1] translated to left/down right/up.
   /// 
   public Vector2 position;
   
   //keeping track of current drag state
   private bool isDragging = false;
   
   //reference to thumb being dragged around
	private RectTransform thumb;

   //initialize variables
	void Start()
	{
		thumb = target.GetComponent();

		//in the editor, disable input received by joystick graphics:
       //we want them to be visible but not receive or block any input
		#if UNITY_EDITOR
			Graphic[] graphics = GetComponentsInChildren();
		//	for(int i = 0; i < graphics.Length; i++)
		//		graphics[i].raycastTarget = false;
		#endif
	}

   /// 
   /// Event fired by UI Eventsystem on drag start.
   /// 
   public void OnBeginDrag(PointerEventData data)
   {
       isDragging = true;
       if(onDragBegin != null)
           onDragBegin();
   }

   /// 
   /// Event fired by UI Eventsystem on drag.
   /// 
   public void OnDrag(PointerEventData data)
   {
       //get RectTransforms of involved components
       RectTransform draggingPlane = transform as RectTransform;
       Vector3 mousePos;

       //check whether the dragged position is inside the dragging rect,
       //then set global mouse position and assign it to the joystick thumb
       if (RectTransformUtility.ScreenPointToWorldPointInRectangle(draggingPlane, data.position, data.pressEventCamera, out mousePos))
       {
           thumb.position = mousePos;
       }

       //length of the touch vector (magnitude)
       //calculated from the relative position of the joystick thumb
       float length = target.localPosition.magnitude;

       //if the thumb leaves the joystick's boundaries,
       //clamp it to the max radius
       if (length > radius)
       {
           target.localPosition = Vector3.ClampMagnitude(target.localPosition, radius);
       }

       //set the Vector2 thumb position based on the actual sprite position
       position = target.localPosition;
       //smoothly lerps the Vector2 thumb position based on the old positions
       position = position / radius * Mathf.InverseLerp(radius, 2, 1);
   }
   
   //set joystick thumb position to drag position each frame
   void Update()
   {
       //in the editor the joystick position does not move, we have to simulate it
		//mirror player input to joystick position and calculate thumb position from that
		#if UNITY_EDITOR
			target.localPosition =  position * radius;
			target.localPosition = Vector3.ClampMagnitude(target.localPosition, radius);
		#endif

       //check for actual drag state and fire callback. We are doing this in Update(),
       //not OnDrag, because OnDrag is only called when the joystick is moving. But we
       //actually want to keep moving the player even though the jostick is being hold down
       if(isDragging && onDrag != null)
           onDrag(position);
   }

   /// 
   /// Event fired by UI Eventsystem on drag end.
   /// 
   public void OnEndDrag(PointerEventData data)
   {
       //we aren't dragging anymore, reset to default position
       position = Vector2.zero;
       target.position = transform.position;
       
       //set dragging to false and fire callback
       isDragging = false;
       if (onDragEnd != null)
           onDragEnd();
   }
}

2015-06-26 16:10:41 lfh719852029 阅读数 2614

       之前的项目中有用虚拟摇杆来操纵角色移动,但是之前使用的是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的简易虚拟摇杆,没有什么扩展功能,没有进行什么优化,如果有什么更好的改进方法请私信我,谢谢!



2017-08-26 19:42:36 yy763496668 阅读数 1875

设置摇杆的背景图片的锚点如下:
这里写图片描述

设置摇杆的锚点为背景图片的中心点。
并给摇杆绑定脚本如下:

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

public class JoyStickController : MonoBehaviour,IDragHandler,IEndDragHandler {
    //最大的拖动距离
    public float maxDragDistance = 50f;
    //虚拟摇杆的方向
    public Vector3 direction;
    //玩家
    public GameObject player;
    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        //屏幕上的y轴分量 当作游戏世界里的z分量
        //设置玩家的朝向
        player.transform.forward = new Vector3(direction.x,0,direction.y);
        int flag = Vector3.Distance(Vector3.zero, this.transform.localPosition) <1f ? 0 : 1;
        player.transform.Translate(Vector3.forward * flag * Time.deltaTime,Space.Self);

    }
    //拖拽中的时候
    public void OnDrag(PointerEventData eventData)
    {
        this.transform.position = Input.mousePosition;
        if (Vector3.Distance(Vector3.zero,this.transform.localPosition) > maxDragDistance)
        {
            direction = this.transform.position - Vector3.zero;
            this.transform.localPosition = direction.normalized * maxDragDistance;
        }
    }
    //拖拽结束的时候
    public void OnEndDrag(PointerEventData eventData)
    {
        this.transform.localPosition = Vector3.zero;
    }
}

这里写图片描述

2017-12-06 20:38:52 hiramtan 阅读数 877

源代码链接https://github.com/hiramtan/HiJoystick_unity

如何使用

可以从此链接下载最新的unity package: Github Releases

完成功能

  • 2D虚拟摇杆
  • 3D虚拟摇杆

截屏

2D虚拟摇杆:

3D虚拟摇杆:

示例

使用 _joystick.State 获取拖拽状态:
- Start,
- Dragging,
- End,

使用 _joystick.DraggingHandler 摇杆偏移量.

public class Example : MonoBehaviour
{
    [SerializeField]
    private Joystick _joystick;
    // Update is called once per frame
    void Update()
    {
        Debug.Log(_joystick.State);
    }
    void OnEnable()
    {
        _joystick.DraggingHandler += OnDragging;
    }
    void OnDisable()
    {
        _joystick.DraggingHandler -= OnDragging;
    }
    void OnDragging(Vector3 v)
    {
        Debug.LogWarning(v);
    }
}
没有更多推荐了,返回首页