-------小基原創,轉載請給我一個面子
現在移動游戲越來越火,大家都拿手機平板玩游戲,沒有鍵盤和手柄輸入,所以就不得不看看虛擬搖桿怎么搞?(小基對於沒有實體反饋不是很喜歡呢)
首先要清楚,鼠標操作輸入,應該在2d的UI平面上做一個虛擬搖桿,如下圖
Hierarchy面板下點Create創建一個UI里面的Image
會自動創建一個Canvas(畫布),UI方面的東西都在這里面顯示
我們再創建一個專門處理UI的攝像機(這個主要處理鼠標點擊時候,獲取屏幕坐標,來處理移動邏輯,如果使用默認的MainCamera的話,正交模式下,沒法體現3D,投影模式下,鼠標點擊輸入坐標處理起來也有點惡心,這些坑我會單獨在另一個技術文章里細說,對於新手來講,先知道這里單做一個UICamera可以避免坑就行。踩坑的方式,花樣可多了)
Hierarchy面板下用Create創建一個UI里面的Camera,改名為UICamera
設置成這樣,記得把AudioListener這個組件移除掉,因為MainCamera上面已經有一個接收聲音的了。紅框內切記,不然待會都找不到你的搖桿Orz
(具體參數細節這里不展開講了,這個系列以實現功能為目標,講原理的話,太枯燥了,怕不是看睡着了)
接下來是制作虛擬搖桿,兩張圖片,大圈里面放個小圈。
在Canvas下創建兩個Image,分別起名,小圓作為大圓的子物體(這樣就可以成為整體,一起移動了)
使用unity自帶的圖片湊合用,一個白色,一個紅色,效果明顯點
最后效果就是這樣,好吧,原諒我的美術是體育老師教的XD
接下來在創建一個空物體Main,用來掛腳本MyInput2(基於上一篇的控制移動,在加點東西就非常實用了)
下面上代碼
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class MyInput2 : MonoBehaviour { 6 //移動方向枚舉 7 enum MoveDir 8 { 9 None = 0, //不動 10 Up = 1, //上8 11 Down = -1, //下2 12 Left = 10, //左4 13 Right = -10, //右6 14 UL = 11, //左上7 15 UR = -9, //右上9 16 DL = 9, //左下1 17 DR = -11, //右下3 18 } 19 20 //輸入按鍵常量(之后走配置) 21 const KeyCode INPUT_UP = KeyCode.W; 22 const KeyCode INPUT_DOWN = KeyCode.S; 23 const KeyCode INPUT_LEFT = KeyCode.A; 24 const KeyCode INPUT_RIGHT = KeyCode.D; 25 26 //默認移動方向 27 private MoveDir moveDir = MoveDir.None; 28 //按壓值 29 private int moveDirValue = 0; 30 //按壓記錄 31 private bool isUpPress = false; 32 private bool isDownPress = false; 33 private bool isLeftPress = false; 34 private bool isRightPress = false; 35 36 //是否可以移動 37 private bool canMove = true; 38 //右移動 39 private Vector3 MOVE_RIGHT = new Vector3(1, 0, 0); 40 //上移動 41 private Vector3 MOVE_UP = new Vector3(0, 1, 0); 42 43 //外部調控速度 44 public float speed = 2f; 45 //移動速度向量 46 private Vector3 move_speed_dir = Vector3.zero; 47 //移動距離 48 private Vector3 move_dis = Vector3.zero; 49 50 //控制目標 51 public Transform target; 52 53 54 //鼠標按下時的坐標 55 private Vector3 mouseStartPos = Vector3.zero; 56 //鼠標是否按下 57 private bool isMousePress = false; 58 //鼠標枚舉 59 const KeyCode INPUT_MOUSE = KeyCode.Mouse0; 60 //鼠標拖動范圍 61 const float MOUSE_RADIUS = 20; 62 //鼠標移動向量 63 private Vector3 mouseDir = Vector3.zero; 64 //鼠標速度衰減 65 private float mouseSpeedRate = 0; 66 //鼠標速度 67 public float mouseSpeed = 2; 68 //搖桿底 69 public RectTransform joyStickDown; 70 //搖桿頂 71 public RectTransform joyStickUp; 72 //攝像機 73 public Camera camera; 74 75 76 // Update is called once per frame 77 void Update () { 78 CheckInputKey(); 79 CheckMoveDir(); 80 CheckMouseDir(); 81 } 82 83 void FixedUpdate() 84 { 85 CheckMove(); 86 } 87 88 //檢測輸入按鍵 89 void CheckInputKey() 90 { 91 //檢測單一輸入 92 foreach (KeyCode kcode in System.Enum.GetValues(typeof(KeyCode))) 93 { 94 if (Input.GetKeyDown(kcode)) 95 { 96 //Debug.Log("Single KeyCode Down: " + kcode); 97 ChangeKeyPressState(kcode, true); 98 } 99 100 if (Input.GetKeyUp(kcode)) 101 { 102 //Debug.Log("Single KeyCode Up: " + kcode); 103 ChangeKeyPressState(kcode, false); 104 } 105 } 106 } 107 108 //記錄按鍵的按壓狀態 109 void ChangeKeyPressState(KeyCode keyCode, bool isPress) 110 { 111 switch(keyCode) 112 { 113 case INPUT_UP: 114 isUpPress = isPress; 115 break; 116 case INPUT_DOWN: 117 isDownPress = isPress; 118 break; 119 case INPUT_LEFT: 120 isLeftPress = isPress; 121 break; 122 case INPUT_RIGHT: 123 isRightPress = isPress; 124 break; 125 case INPUT_MOUSE: 126 MouseStateChange(isPress); 127 break; 128 } 129 } 130 131 //鼠標按鍵輸入 132 void MouseStateChange(bool isPress) 133 { 134 isMousePress = isPress; 135 mouseStartPos = isPress ? Input.mousePosition : Vector3.zero; 136 joyStickDown.gameObject.SetActive(isPress); 137 joyStickDown.position = camera.ScreenToWorldPoint(mouseStartPos); 138 } 139 140 //鼠標移動 141 void CheckMouseDir() 142 { 143 if(isMousePress) 144 { 145 mouseDir = Input.mousePosition - mouseStartPos; 146 mouseSpeedRate = Mathf.Min(mouseDir.magnitude / MOUSE_RADIUS, 1); 147 move_dis = mouseSpeed * mouseSpeedRate * Time.deltaTime * mouseDir.normalized; 148 target.position += move_dis; 149 joyStickUp.localPosition = mouseDir.normalized * mouseSpeedRate * MOUSE_RADIUS; 150 } 151 } 152 153 //確定移動方向 154 void CheckMoveDir() 155 { 156 moveDirValue = 0; 157 //確定方向 158 if(isUpPress) 159 { 160 moveDirValue += (int)MoveDir.Up; 161 } 162 if (isDownPress) 163 { 164 moveDirValue += (int)MoveDir.Down; 165 } 166 if (isLeftPress) 167 { 168 moveDirValue += (int)MoveDir.Left; 169 } 170 if (isRightPress) 171 { 172 moveDirValue += (int)MoveDir.Right; 173 } 174 } 175 176 //檢測是否可以移動 177 void CheckMove() 178 { 179 //某些情況下可能禁止移動,例如暫停,播放CG等 180 if(canMove && moveDirValue != (int)MoveDir.None) 181 { 182 PlayerMove(target, speed); 183 } 184 } 185 186 //移動 187 void PlayerMove(Transform target, float speed) 188 { 189 move_dis = speed * Time.deltaTime * GetSpeedDir(); 190 target.position += move_dis; 191 } 192 193 //速度向量 194 Vector3 GetSpeedDir() 195 { 196 switch(moveDirValue) 197 { 198 case (int)MoveDir.Up: 199 move_speed_dir = MOVE_UP; 200 break; 201 case (int)MoveDir.Down: 202 move_speed_dir = -MOVE_UP; 203 break; 204 case (int)MoveDir.Left: 205 move_speed_dir = -MOVE_RIGHT; 206 break; 207 case (int)MoveDir.Right: 208 move_speed_dir = MOVE_RIGHT; 209 break; 210 case (int)MoveDir.UL: 211 move_speed_dir = MOVE_UP - MOVE_RIGHT; 212 break; 213 case (int)MoveDir.UR: 214 move_speed_dir = MOVE_UP + MOVE_RIGHT; 215 break; 216 case (int)MoveDir.DL: 217 move_speed_dir = -MOVE_UP - MOVE_RIGHT; 218 break; 219 case (int)MoveDir.DR: 220 move_speed_dir = -MOVE_UP + MOVE_RIGHT; 221 break; 222 } 223 return move_speed_dir.normalized; 224 } 225 }
在按鍵輸入控制的基礎上,加上鼠標輸入就ok了
思路就是:按下時候記錄此時坐標,然后拖動后的當前坐標與起始坐標的向量差值,就是物體應該移動的方向
先把變量都定義好
核心就是鼠標左鍵按下的記錄狀態(這里做了個有意思的處理,第一次按下的位置,搖桿就會出現在那個位置,拖動的時候,小圓在大圓內部移動)
接下來把腳本綁定好
運行游戲,類似於這個效果,鼠標移動,紅圈在白圈內移動,移動方向就是白方塊(主角)移動方向
ok,通過兩篇介紹,除了腳本稍稍有點難理解之外,其他應該都能一步一步做出來了,零基礎的你看到自己做的“小游戲”,是不是已經成就感爆棚了?
最基本的控制移動都完成了,不如下篇博客小基介紹一下“打飛機”ლ(╹◡╹ლ)
emmm,小基是說如何發射子彈(¬_¬”)