现在移动游戏越来越火,大家都拿手机平板玩游戏,没有键盘和手柄输入,所以就不得不看看虚拟摇杆怎么搞?(小基对于没有实体反馈不是很喜欢呢)
首先要清楚,鼠标操作输入,应该在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,小基是说如何发射子弹(¬_¬”)