qq534575060 发表于 2015-5-27 17:15

UGUI实现unity摇杆

本帖最后由 qq534575060 于 2015-5-27 17:17 编辑


[*]本文固定链接: http://www.winig.cc/archives/348
[*]转载请注明: 威恩 2015年05月27日 于 威恩IG.CC 发表
好久没有写文章了,最近在做项目是用的unity最新的ui系统UGUI,项目需要做一个摇杆,网上大部分都是用的插件和NGUI做的摇杆,unity自带的摇杆也不怎么好用,而最新的unity4.6.x来了,加入了最新的UI系统“UGUI”,那我们怎么用UGUI来制作摇杆呢~大神勿喷,本人是技术渣渣。比较出色的摇杆插件《Easy Touch》(很强大)还是主要讲讲我们自己怎么做。


[*]首先在unity场景里面新建一个空物体和两个Image,把空物体放在创建Image自动生成的Canvas里面,再把两个Image放在空物体里Image建立方式:GameObject->UI->Image   或者直接在“Hierarchy”右键然后UI->Image,看喜好。空物体和两个Image的命名看个人喜好。威恩的节点是这样的:节点中的joystack是刚刚建立的空节点。Backgound是摇杆的背景。JoystackControl是真实的可以拖动的摇杆。
[*]把Backgound和JoystackControl的SourceImage替换成自己喜欢的图片,并且把JoystackControl的图片缩小点,这里我就用系统自带的图片了,威恩这两个节点的inspector如下(我修改过得地方用红框标注了,其他都没改):最终样子如下:
[*]那么样子有了就需要让他动起来,需要三个类“EventTriggerListener”、“JoystackCc”、“PlayerMoveControl”。
EventTriggerListener:在NGUI开发的时候处理事件都会用到UIEventListener,我们已经用的习惯的不得了,而UGUI则不是这种机制,并且我觉得这种是最合理的方式,所以自己写一套类似的。只是一个帮助类,不需要挂在任何的游戏对象上。JoystackCc:这是主要来控制摇杆的。挂在JoystackControl节点上PlayerMoveControl:这是主要来通过摇杆来控制角色的。挂在你想控制的物体上
直接上代码,写了注释,就不哔哔了。EventTriggerListener.csusing UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using System.Collections.Generic;

/// <summary>
/// UGUI事件监听类
/// </summary>
public class EventTriggerListener : UnityEngine.EventSystems.EventTrigger{
    public delegate void VoidDelegate (GameObject go);
    public delegate void VectorDelegate(GameObject go, Vector2 delta);
    public VoidDelegate onClick;
    public VoidDelegate onDown;
    public VoidDelegate onEnter;
    public VoidDelegate onExit;
    public VoidDelegate onUp;
    public VoidDelegate onSelect;
    public VoidDelegate onUpdateSelect;
      
    public VectorDelegate onDrag;
    public VoidDelegate onDragOut;
      
      
    static public EventTriggerListener Get (GameObject go)
    {
      if(go==null){
            Debug.LogError("EventTriggerListener_go_is_NULL");
            return null;
      }
      else{
            EventTriggerListener listener = go.GetComponent<EventTriggerListener>();
            if (listener == null) listener = go.AddComponent<EventTriggerListener>();
            return listener;
      }
    }
      
    public override void OnDrag(PointerEventData eventData)
    {
      if (onDrag != null) onDrag(gameObject, eventData.delta);
    }
      
    public override void OnEndDrag(PointerEventData eventData)
    {
      if (onDragOut != null) onDragOut(gameObject);
    }
      
    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);
    }
}JoystackCc.csusing UnityEngine;
using System.Collections;

public class JoystackCc : MonoBehaviour {
    private Vector3 Origin;

    Transform mTrans;

    private Vector3 _deltaPos;
    private bool _drag = false;

    private Vector3 deltaPosition;

    float dis;
   
    private float MoveMaxDistance = 80;             //最大拖动距离

   
    public Vector3 FiexdMovePosiNorm; //固定8个角度移动的距离

   
    public Vector3 MovePosiNorm;//标准化移动的距离
   
    private float ActiveMoveDistance = 1;               //激活移动的最低距离
    void Awake()
    {
      EventTriggerListener.Get(gameObject).onDrag = OnDrag;
      EventTriggerListener.Get(gameObject).onDragOut = OnDragOut;

      EventTriggerListener.Get(gameObject).onDown = OnMoveStart;
    }


    // Use this for initialization
    void Start () {
      Origin = transform.localPosition; //设置原点
      mTrans = transform;
    }
      
    // Update is called once per frame
    void Update()
    {
      dis = Vector3.Distance(transform.localPosition, Origin); //拖动距离,这不是最大的拖动距离,是根据触摸位置算出来的
      if (dis >= MoveMaxDistance)       //如果大于可拖动的最大距离
      {
            Vector3 vec = Origin + (transform.localPosition - Origin) * MoveMaxDistance / dis;   //求圆上的一点:(目标点-原点) * 半径/原点到目标点的距离
            transform.localPosition = vec;
      }
      if (Vector3.Distance(transform.localPosition, Origin) > ActiveMoveDistance)//距离大于激活移动的距离
      {
            MovePosiNorm = (transform.localPosition - Origin).normalized;
            MovePosiNorm = new Vector3(MovePosiNorm.x, 0, MovePosiNorm.y);
      }
      else
            MovePosiNorm = Vector3.zero;
    }
    void MiouseDown()
    {
      if ((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved))
      {
      }
      else
            mTrans.localPosition = Origin;
    }
    Vector3 result;
    private Vector3 _checkPosition(Vector3 movePos, Vector3 _offsetPos)
    {
      result = movePos + _offsetPos;
      return result;
    }

    void OnDrag(GameObject go, Vector2 delta)
    {
      if (!_drag)
      {
            _drag = true;
      }
      _deltaPos = delta;

      mTrans.localPosition += new Vector3(_deltaPos.x, _deltaPos.y, 0);
    }

    void OnDragOut(GameObject go)
    {
      _drag = false;
      mTrans.localPosition = Origin;
      if (PlayerMoveControl.moveEnd != null) PlayerMoveControl.moveEnd();
    }

    void OnMoveStart(GameObject go)
    {
      if (PlayerMoveControl.moveStart != null) PlayerMoveControl.moveStart();
    }
}PlayerMoveControl.csusing UnityEngine;
using System.Collections;

public class PlayerMoveControl : MonoBehaviour {
    private Transform _mTransform;
    public JoystackCc _mJoystackCc;

    public float moveSpeed = 50;

    public delegate void MoveDelegate();
    public static MoveDelegate moveEnd;
    public static MoveDelegate moveStart;
    public static PlayerMoveControl Instance;
    // Use this for initialization
    void Awake()
    {
      Instance = this;
      _mTransform = transform;

      moveEnd = OnMoveEnd;
      moveStart = OnMoveStart;
    }
    void Start () {

    }
    void OnMoveEnd()
    {
      _turnBase = false;
    }

    void OnMoveStart()
    {
      _turnBase = true;
    }
            
    // Update is called once per frame
    private float angle;
    private bool _turnBase = false;
    void Update()
    {
      if (_turnBase)
      {
            Vector3 vecMove = _mJoystackCc.MovePosiNorm*Time.deltaTime*moveSpeed/10;
            _mTransform.localPosition+=vecMove;
            angle = Mathf.Atan2 (_mJoystackCc.MovePosiNorm.x, _mJoystackCc.MovePosiNorm.z) * Mathf.Rad2Deg - 10;
            _mTransform.localRotation = Quaternion.Euler(Vector3.up*angle);
      }
    }
}建好这三个类之后,把他们绑定到相应的节点上。都挂在哪,代码上面有写
[*]测试一下,威恩新建了一个cube来作为测试对象,加了个plane作为“伪”地面,太黑了再打个灯….下面是测试效果:
如果有任何问题直接留言~尽自己所能帮忙解决~

selfcom 发表于 2016-7-19 09:57

感谢分享!!:)

reginald 发表于 2016-7-19 10:02


感谢楼主的无私分享!

monkqq 发表于 2016-8-1 11:16


不错 不错 不错

fubo8533121 发表于 2016-8-18 00:38

好的一天

714806858 发表于 2017-3-7 15:33

楼主是超人

15579126707 发表于 2017-3-7 16:08

好帖就是要顶

shenyg28 发表于 2017-3-7 15:59

真心顶

sunjunfa001 发表于 2017-3-7 16:19

难得一见的好帖

yangjingchi 发表于 2017-3-7 15:42

不错不错
页: [1]
查看完整版本: UGUI实现unity摇杆