雨松MOMO原创文章如转载,请注明:转载自雨松MOMO的博客原文地址:http://blog.csdn.net/xys289187120/article/details/6941061

     移动开发游戏中使用到的触摸游戏摇杆在iPhone上是非常普遍的,毕竟是全触摸屏手机,今天MOMO 通过一个小例子和大家讨论Unity3D 中如何自定义一个漂亮的全触摸游戏摇杆。

       值得高兴的是,Unity3D 游戏引擎的标准资源中已经帮助我们封装了一个游戏摇杆脚本,所以实现部分的代码可以完全借助它的,具体调用需要我们自己来。

Joystick.js是官方提供的脚本,具体代码如下,有兴趣的朋友可以仔细研究研究,MOMO就不多说啦。

  1. //////////////////////////////////////////////////////////////
  2. // Joystick.js
  3. // Penelope iPhone Tutorial
  4. //
  5. // Joystick creates a movable joystick (via GUITexture) that
  6. // handles touch input, taps, and phases. Dead zones can control
  7. // where the joystick input gets picked up and can be normalized.
  8. //
  9. // Optionally, you can enable the touchPad property from the editor
  10. // to treat this Joystick as a TouchPad. A TouchPad allows the finger
  11. // to touch down at any point and it tracks the movement relatively
  12. // without moving the graphic
  13. //////////////////////////////////////////////////////////////

  14. @script RequireComponent( GUITexture )

  15. // A simple class for bounding how far the GUITexture will move
  16. class Boundary
  17. {
  18.         var min : Vector2 = Vector2.zero;
  19.         var max : Vector2 = Vector2.zero;
  20. }

  21. static private var joysticks : Joystick[];                                        // A static collection of all joysticks
  22. static private var enumeratedJoysticks : boolean = false;
  23. static private var tapTimeDelta : float = 0.3;                                // Time allowed between taps

  24. var touchPad : boolean;                                                                         // Is this a TouchPad?
  25. var touchZone : Rect;
  26. var deadZone : Vector2 = Vector2.zero;                                                // Control when position is output
  27. var normalize : boolean = false;                                                         // Normalize output after the dead-zone?
  28. var position : Vector2;                                                                         // [-1, 1] in x,y
  29. var tapCount : int;                                                                                        // Current tap count

  30. private var lastFingerId = -1;                                                                // Finger last used for this joystick
  31. private var tapTimeWindow : float;                                                        // How much time there is left for a tap to occur
  32. private var fingerDownPos : Vector2;
  33. private var fingerDownTime : float;
  34. private var firstDeltaTime : float = 0.5;

  35. private var gui : GUITexture;                                                                // Joystick graphic
  36. private var defaultRect : Rect;                                                                // Default position / extents of the joystick graphic
  37. private var guiBoundary : Boundary = Boundary();                        // Boundary for joystick graphic
  38. private var guiTouchOffset : Vector2;                                                // Offset to apply to touch input
  39. private var guiCenter : Vector2;                                                        // Center of joystick

  40. function Start()
  41. {
  42.         // Cache this component at startup instead of looking up every frame       
  43.         gui = GetComponent( GUITexture );
  44.        
  45.         // Store the default rect for the gui, so we can snap back to it
  46.         defaultRect = gui.pixelInset;       
  47.    
  48.     defaultRect.x += transform.position.x * Screen.width;// + gui.pixelInset.x; // -  Screen.width * 0.5;
  49.     defaultRect.y += transform.position.y * Screen.height;// - Screen.height * 0.5;
  50.    
  51.     transform.position.x = 0.0;
  52.     transform.position.y = 0.0;
  53.         
  54.         if ( touchPad )
  55.         {
  56.                 // If a texture has been assigned, then use the rect ferom the gui as our touchZone
  57.                 if ( gui.texture )
  58.                         touchZone = defaultRect;
  59.         }
  60.         else
  61.         {                               
  62.                 // This is an offset for touch input to match with the top left
  63.                 // corner of the GUI
  64.                 guiTouchOffset.x = defaultRect.width * 0.5;
  65.                 guiTouchOffset.y = defaultRect.height * 0.5;
  66.                
  67.                 // Cache the center of the GUI, since it doesn't change
  68.                 guiCenter.x = defaultRect.x + guiTouchOffset.x;
  69.                 guiCenter.y = defaultRect.y + guiTouchOffset.y;
  70.                
  71.                 // Let's build the GUI boundary, so we can clamp joystick movement
  72.                 guiBoundary.min.x = defaultRect.x - guiTouchOffset.x;
  73.                 guiBoundary.max.x = defaultRect.x + guiTouchOffset.x;
  74.                 guiBoundary.min.y = defaultRect.y - guiTouchOffset.y;
  75.                 guiBoundary.max.y = defaultRect.y + guiTouchOffset.y;
  76.         }
  77. }

  78. function Disable()
  79. {
  80.         gameObject.active = false;
  81.         enumeratedJoysticks = false;
  82. }

  83. function ResetJoystick()
  84. {
  85.         // Release the finger control and set the joystick back to the default position
  86.         gui.pixelInset = defaultRect;
  87.         lastFingerId = -1;
  88.         position = Vector2.zero;
  89.         fingerDownPosition = Vector2.zero;
  90.        
  91.         if ( touchPad )
  92.                 gui.color.a = 0.025;       
  93. }

  94. function IsFingerDown() : boolean
  95. {
  96.         return (lastFingerId != -1);
  97. }
  98.        
  99. function LatchedFinger( fingerId : int )
  100. {
  101.         // If another joystick has latched this finger, then we must release it
  102.         if ( lastFingerId == fingerId )
  103.                 ResetJoystick();
  104. }

  105. function Update()
  106. {       
  107.         if ( !enumeratedJoysticks )
  108.         {
  109.                 // Collect all joysticks in the game, so we can relay finger latching messages
  110.                 joysticks = FindObjectsOfType( Joystick );
  111.                 enumeratedJoysticks = true;
  112.         }       
  113.                
  114.         var count = Input.touchCount;
  115.        
  116.         // Adjust the tap time window while it still available
  117.         if ( tapTimeWindow > 0 )
  118.                 tapTimeWindow -= Time.deltaTime;
  119.         else
  120.                 tapCount = 0;
  121.        
  122.         if ( count == 0 )
  123.                 ResetJoystick();
  124.         else
  125.         {
  126.                 for(var i : int = 0;i < count; i++)
  127.                 {
  128.                         var touch : Touch = Input.GetTouch(i);                       
  129.                         var guiTouchPos : Vector2 = touch.position - guiTouchOffset;
  130.        
  131.                         var shouldLatchFinger = false;
  132.                         if ( touchPad )
  133.                         {                               
  134.                                 if ( touchZone.Contains( touch.position ) )
  135.                                         shouldLatchFinger = true;
  136.                         }
  137.                         else if ( gui.HitTest( touch.position ) )
  138.                         {
  139.                                 shouldLatchFinger = true;
  140.                         }               
  141.        
  142.                         // Latch the finger if this is a new touch
  143.                         if ( shouldLatchFinger && ( lastFingerId == -1 || lastFingerId != touch.fingerId ) )
  144.                         {
  145.                                
  146.                                 if ( touchPad )
  147.                                 {
  148.                                         gui.color.a = 0.15;
  149.                                        
  150.                                         lastFingerId = touch.fingerId;
  151.                                         fingerDownPos = touch.position;
  152.                                         fingerDownTime = Time.time;
  153.                                 }
  154.                                
  155.                                 lastFingerId = touch.fingerId;
  156.                                
  157.                                 // Accumulate taps if it is within the time window
  158.                                 if ( tapTimeWindow > 0 )
  159.                                         tapCount++;
  160.                                 else
  161.                                 {
  162.                                         tapCount = 1;
  163.                                         tapTimeWindow = tapTimeDelta;
  164.                                 }
  165.                                                                                        
  166.                                 // Tell other joysticks we've latched this finger
  167.                                 for ( var j : Joystick in joysticks )
  168.                                 {
  169.                                         if ( j != this )
  170.                                                 j.LatchedFinger( touch.fingerId );
  171.                                 }                                               
  172.                         }                               
  173.        
  174.                         if ( lastFingerId == touch.fingerId )
  175.                         {       
  176.                                 // Override the tap count with what the iPhone SDK reports if it is greater
  177.                                 // This is a workaround, since the iPhone SDK does not currently track taps
  178.                                 // for multiple touches
  179.                                 if ( touch.tapCount > tapCount )
  180.                                         tapCount = touch.tapCount;
  181.                                
  182.                                 if ( touchPad )
  183.                                 {       
  184.                                         // For a touchpad, let's just set the position directly based on distance from initial touchdown
  185.                                         position.x = Mathf.Clamp( ( touch.position.x - fingerDownPos.x ) / ( touchZone.width / 2 ), -1, 1 );
  186.                                         position.y = Mathf.Clamp( ( touch.position.y - fingerDownPos.y ) / ( touchZone.height / 2 ), -1, 1 );
  187.                                 }
  188.                                 else
  189.                                 {                                       
  190.                                         // Change the location of the joystick graphic to match where the touch is
  191.                                         gui.pixelInset.x =  Mathf.Clamp( guiTouchPos.x, guiBoundary.min.x, guiBoundary.max.x );
  192.                                         gui.pixelInset.y =  Mathf.Clamp( guiTouchPos.y, guiBoundary.min.y, guiBoundary.max.y );               
  193.                                 }
  194.                                
  195.                                 if ( touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled )
  196.                                         ResetJoystick();                                       
  197.                         }                       
  198.                 }
  199.         }
  200.        
  201.         if ( !touchPad )
  202.         {
  203.                 // Get a value between -1 and 1 based on the joystick graphic location
  204.                 position.x = ( gui.pixelInset.x + guiTouchOffset.x - guiCenter.x ) / guiTouchOffset.x;
  205.                 position.y = ( gui.pixelInset.y + guiTouchOffset.y - guiCenter.y ) / guiTouchOffset.y;
  206.         }
  207.        
  208.         // Adjust for dead zone       
  209.         var absoluteX = Mathf.Abs( position.x );
  210.         var absoluteY = Mathf.Abs( position.y );
  211.        
  212.         if ( absoluteX < deadZone.x )
  213.         {
  214.                 // Report the joystick as being at the center if it is within the dead zone
  215.                 position.x = 0;
  216.         }
  217.         else if ( normalize )
  218.         {
  219.                 // Rescale the output after taking the dead zone into account
  220.                 position.x = Mathf.Sign( position.x ) * ( absoluteX - deadZone.x ) / ( 1 - deadZone.x );
  221.         }
  222.                
  223.         if ( absoluteY < deadZone.y )
  224.         {
  225.                 // Report the joystick as being at the center if it is within the dead zone
  226.                 position.y = 0;
  227.         }
  228.         else if ( normalize )
  229.         {
  230.                 // Rescale the output after taking the dead zone into account
  231.                 position.y = Mathf.Sign( position.y ) * ( absoluteY - deadZone.y ) / ( 1 - deadZone.y );
  232.         }
  233. }
复制代码


单击Create 创建一个GUI Texture,命名为Joy ,它用来显示游戏摇杆,如下图所示将摇杆的图片资源,与摇杆的脚本连线赋值给Joy.  Pixel Inset 中可以设置摇杆的显示位置与显示宽高。
11.gif
到这一步 build and run 就可以在iPhone上看到这个游戏摇杆,并且可以通过触摸它,360度平滑过度。

在屏幕中绘制一个飞机,通过游戏摇杆去控制飞机的移动。

创建一个脚本,命名为Main.js 如下图所示  将 Main.js 、joy、plan 分别 绑定在Main Camera 上。
22.gif
moveJoystick.position.x;
moveJoystick.position.y;

这两个值是非常重要的两个信息,它们的取值范围是 -1 到 +1 ,表示 用户触摸摇杆的位置, 上 下 左 右 的信息。

  1. //游戏摇杆对象
  2. var moveJoystick : Joystick;

  3. //飞机的贴图
  4. var plan : Texture;

  5. //飞机在屏幕中的坐标
  6. var x = 0;
  7. var y = 0;

  8. //避免飞机飞出屏幕,分别是X、Y最大坐标,最小坐标是0、0
  9. var cross_x = 0;
  10. var cross_y = 0;

  11. //飞机移动的速度
  12. var planSpeed = 20;

  13. function Start() {
  14.         //初始化赋值
  15.         x = 100;
  16.         y = 100;
  17.         cross_x = Screen.width -  plan.width;
  18.         cross_y = Screen.height -  plan.height;
  19.        
  20. }

  21. function Update () {
  22.         //得到游戏摇杆的反馈信息,得到的值是 -1 到 +1 之间
  23.        
  24.         var touchKey_x =  moveJoystick.position.x;
  25.         var touchKey_y =  moveJoystick.position.y;
  26.        
  27.         //摇杆向左
  28.         if(touchKey_x == -1){
  29.                 x -= planSpeed;
  30.                
  31.         }
  32.         //摇杆向右
  33.         else if(touchKey_x == 1){
  34.                 x += planSpeed;
  35.                
  36.         }
  37.         //摇杆向上
  38.           if(touchKey_y == -1){
  39.                 y += planSpeed;
  40.                
  41.         }
  42.         //摇杆向下
  43.         else if(touchKey_y == 1){
  44.                 y -= planSpeed;
  45.                
  46.         }
  47.        
  48.         //防止飞机飞出屏幕,出界检测
  49.         if(x < 0){
  50.                 x = 0;
  51.         }else if(x > cross_x){
  52.                 x = cross_x;
  53.         }
  54.        
  55.           if(y < 0){
  56.                 y = 0;
  57.         }else if(y > cross_y){
  58.                 y = cross_y;
  59.         }
  60. }




  61. function OnGUI () {


  62.   //将飞机绘制在屏幕中
  63.   GUI.DrawTexture(Rect(x,y,128,128),plan);  

  64. }
复制代码


导出 build and run  看看在iPhone 上的效果,通过触摸游戏摇杆可以控制飞机的移动啦,不错吧~~

33.gif 44.gif
最后欢迎各位盆友可以和MOMO一起讨论Unity3D游戏开发,最近感冒的盆友越来越多,大家要多多注意身体健康噢~~~ 附上Unity3D工程的下载地址,Xcode项目我就不上传了,须要的自己导出。

下载地址:http://download.csdn.net/detail/xys289187120/3762265