-------小基原創,轉載請給我一個面子
主角都能移動了,那不得做點什么伸張正義,守護世界和平的事嘛,拿起家伙biu~biu~biu~
首先得做一個好人和一個壞人
老規矩,Canvas下創建兩個Image,一個叫做player,一個叫做enemy1好了
一個紅色,一個藍色(自古紅藍出CP,不好意思,走錯片場了●﹏●)
新知識:要加BoxCollider2D
子彈打到別人,其實是碰撞檢測的過程
一種是根據位置坐標,判斷子彈有沒有打中,另一種是使用物理碰撞系統(小基這里使用后者)
兩個物體物理碰撞檢測條件
1.物體A,物體B,必須都有Collider
2.運動的一方要有剛體(本例對應的是子彈,后面介紹)
最終效果是這樣的。
下面開始制作子彈
Canvas下創建一個Image,修改名字叫做Bullet,使用自帶的圓形圖片湊合用吧
同樣添加BoxCollider2D,最后切記添加RigidBody,不然沒法碰撞成功
額外提一句,重力調成0吧,不然子彈拋物線飛=_=
現在看起來是這樣的。
接下來想想怎么讓子彈動起來,上代碼(創建一個腳本Bullet),給那個子彈掛上
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class Bullet : MonoBehaviour { 6 7 public float speed = 15; 8 public Vector2 dir = new Vector2(1, 0); 9 public float lifeTime = 5f; 10 11 public float damage = 1; 12 // Use this for initialization 13 void Start () { 14 DestroySelf(lifeTime); 15 } 16 17 // Update is called once per frame 18 void Update () { 19 this.transform.Translate(dir * speed * Time.deltaTime, Space.World); 20 } 21 22 void DestroySelf(float time) 23 { 24 Destroy(this.gameObject, time); 25 } 26 27 void OnTriggerEnter2D(Collider2D other) 28 { 29 //Debug.Log("enter"); 30 if (other.gameObject.tag == "Enemy") 31 {
33 Destroy(this.gameObject); 34 } 35 } 36 }
start()里面調用DestroySelf(),意思是子彈存活lifeTime 時間后,自動消失。不然“讓子彈飛”飛到啥時候是個頭啊,飛出屏幕外就沒有意義了。存活時間可以自己控制
Update()方法里面,每幀都在按照指定的dir方向移動,你想讓子彈怎么飛,朝哪飛,就自行設計吧,螺旋升天都沒有問題~
OnTriggerEnter2D這個方法是Unity自帶的,用處就是當進入碰撞盒Collider時調用,小基的內容是銷毀自己,不是~意思是銷毀掉子彈
這里加了一個if的判斷,判斷tag是不是Enemy,畢竟打到友軍可是會被噴豬隊友的
Tag一般默認是Untagged的,點擊一下后有彈出AddTag這個選項,然后
點擊加號,可以自己創建需要的tag,這樣可以給不同類別的物體做區分。
下面考慮怎么讓主角射出子彈,這個就需要代碼控制了
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 = 100; 68 //搖桿底 69 public RectTransform joyStickDown; 70 //搖桿頂 71 public RectTransform joyStickUp; 72 //攝像機 73 public Camera camera; 74 75 //子彈prefab 76 GameObject prefabBullet; 77 //是否開火 78 bool isFire = false; 79 // Use this for initialization 80 void Start () { 81 prefabBullet = (GameObject)Resources.Load("Prefab/Bullet"); 82 //Debug.Log("bullet:" + prefabBullet); 83 } 84 85 // Update is called once per frame 86 void Update () { 87 CheckInputKey(); 88 CheckMoveDir(); 89 CheckMouseDir(); 90 } 91 92 void FixedUpdate() 93 { 94 CheckMove(); 95 CheckFire(); 96 } 97 98 //檢測輸入按鍵 99 void CheckInputKey() 100 { 101 //檢測單一輸入 102 foreach (KeyCode kcode in System.Enum.GetValues(typeof(KeyCode))) 103 { 104 if (Input.GetKeyDown(kcode)) 105 { 106 //Debug.Log("Single KeyCode Down: " + kcode); 107 ChangeKeyPressState(kcode, true); 108 } 109 110 if (Input.GetKeyUp(kcode)) 111 { 112 //Debug.Log("Single KeyCode Up: " + kcode); 113 ChangeKeyPressState(kcode, false); 114 } 115 } 116 } 117 118 //記錄按鍵的按壓狀態 119 void ChangeKeyPressState(KeyCode keyCode, bool isPress) 120 { 121 switch(keyCode) 122 { 123 case INPUT_UP: 124 isUpPress = isPress; 125 break; 126 case INPUT_DOWN: 127 isDownPress = isPress; 128 break; 129 case INPUT_LEFT: 130 isLeftPress = isPress; 131 break; 132 case INPUT_RIGHT: 133 isRightPress = isPress; 134 break; 135 case INPUT_MOUSE: 136 MouseStateChange(isPress); 137 break; 138 case INPUT_FIRE: 139 isFire = isPress; 140 break; 141 } 142 } 143 144 //鼠標按鍵輸入 145 void MouseStateChange(bool isPress) 146 { 147 isMousePress = isPress; 148 mouseStartPos = isPress ? Input.mousePosition : Vector3.zero; 149 joyStickDown.gameObject.SetActive(isPress); 150 joyStickDown.position = camera.ScreenToWorldPoint(mouseStartPos); 151 } 152 153 //鼠標移動 154 void CheckMouseDir() 155 { 156 if(isMousePress) 157 { 158 mouseDir = Input.mousePosition - mouseStartPos; 159 mouseSpeedRate = Mathf.Min(mouseDir.magnitude / MOUSE_RADIUS, 1); 160 move_dis = mouseSpeed * mouseSpeedRate * Time.deltaTime * mouseDir.normalized; 161 target.position += move_dis; 162 joyStickUp.localPosition = mouseDir.normalized * mouseSpeedRate * MOUSE_RADIUS; 163 } 164 } 165 166 //確定移動方向 167 void CheckMoveDir() 168 { 169 moveDirValue = 0; 170 //確定方向 171 if(isUpPress) 172 { 173 moveDirValue += (int)MoveDir.Up; 174 } 175 if (isDownPress) 176 { 177 moveDirValue += (int)MoveDir.Down; 178 } 179 if (isLeftPress) 180 { 181 moveDirValue += (int)MoveDir.Left; 182 } 183 if (isRightPress) 184 { 185 moveDirValue += (int)MoveDir.Right; 186 } 187 } 188 189 //檢測是否可以移動 190 void CheckMove() 191 { 192 //某些情況下可能禁止移動,例如暫停,播放CG等 193 if(canMove && moveDirValue != (int)MoveDir.None) 194 { 195 PlayerMove(target, speed); 196 } 197 } 198 199 //移動 200 void PlayerMove(Transform target, float speed) 201 { 202 move_dis = speed * Time.deltaTime * GetSpeedDir(); 203 target.position += move_dis; 204 } 205 206 //速度向量 207 Vector3 GetSpeedDir() 208 { 209 switch(moveDirValue) 210 { 211 case (int)MoveDir.Up: 212 move_speed_dir = MOVE_UP; 213 break; 214 case (int)MoveDir.Down: 215 move_speed_dir = -MOVE_UP; 216 break; 217 case (int)MoveDir.Left: 218 move_speed_dir = -MOVE_RIGHT; 219 break; 220 case (int)MoveDir.Right: 221 move_speed_dir = MOVE_RIGHT; 222 break; 223 case (int)MoveDir.UL: 224 move_speed_dir = MOVE_UP - MOVE_RIGHT; 225 break; 226 case (int)MoveDir.UR: 227 move_speed_dir = MOVE_UP + MOVE_RIGHT; 228 break; 229 case (int)MoveDir.DL: 230 move_speed_dir = -MOVE_UP - MOVE_RIGHT; 231 break; 232 case (int)MoveDir.DR: 233 move_speed_dir = -MOVE_UP + MOVE_RIGHT; 234 break; 235 } 236 return move_speed_dir.normalized; 237 } 238 239 //開火 240 public const KeyCode INPUT_FIRE = KeyCode.Space; 241 //開火時間cd 242 public float fireCD = 0.5f; 243 //上次開火時間 244 float lastTime = 0; 245 //當前時間 246 float curTime = 0; 247 248 void CheckFire() 249 { 250 if(isFire) 251 { 252 Fire(); 253 } 254 } 255 256 void Fire() 257 { 258 curTime = Time.time; 259 if(curTime - lastTime > fireCD) 260 { 261 //創建子彈 262 CreateBullet(); 263 lastTime = curTime; 264 } 265 } 266 267 //畫布 268 public Canvas canvas; 269 //創建子彈 270 void CreateBullet() 271 { 272 GameObject bullet = Instantiate(prefabBullet, target.localPosition, target.rotation); 273 bullet.transform.SetParent(canvas.transform, false); 274 } 275 }
還是之前的移動代碼,增加了
這里是需要先把Bullet制作成Prefab預制體,使用Resources.Load方法載入子彈prefab
在Project下創建文件夾Resources(必須用這個才可以載入)下面Prefab里面都是做好的預制體,做法就是把Hierarchy下的對象直接拖到Prefab文件夾下(請無視與本例無關的東西)
ChangeKeyPressState()方法里面增加判斷開火的按鍵,FixedUpdate里面檢測是不是開火,if里面可以加很多條件,比如CG時候不能開火,沒有子彈不能開火等等。
Fire()這個方法里面記錄了開火的當前時間,下次開火的時候判斷是不是已經過了CD時長,不然按住按鍵,每幀都會開火,火力太猛沒法玩了,氪金大佬專屬。
CreateBullet()這里面使用了Instantiate這個自帶的方法,通過前面載入的子彈預設體prefab可以克隆出bullet(就是通過模版復制的過程)
切記要把bullet的父物體設置成Canvas,就是通過代碼把bullet放到canvas下面,不然你子彈可能不在UI里面哦~
SetParent()方法的第二個參數用false,這樣可以保證bullet的size不會因為父節點變化而變化。好奇的話,你可以寫成true試試
來試試發射子彈,打到敵人就消失了。
不過這敵人木頭人太愣了,給他點反應吧,enemy1上添加腳本enemy1(腳本名字你隨便起)
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class Enemy : MonoBehaviour { 6 void ByHit() 7 { 8 Debug.Log("byHit"); 9 this.transform.Translate(Vector2.one); 10 } 11 }
就寫一個方法,被揍了,效果就是朝着vector2.one也就是(1,1)這個方向移動。你想讓有啥反映就在這里寫就可以,想變大變小變色都沒問題
那么怎么才能被調用呢?
1 void OnTriggerEnter2D(Collider2D other) 2 { 3 Debug.Log("enter"); 4 if (other.gameObject.tag == "Enemy") 5 { 6 other.gameObject.SendMessage("ByHit"); 7 Destroy(this.gameObject); 8 } 9 }
剛才子彈的碰撞里面,增加sendMessage這個方法,參數是被調用方法的名字。這樣就可以調用到碰撞的對方身上的腳本里面的"ByHit"這個方法
雖然敵人暫時還不能反擊,不過起碼不那么木訥了∠( ᐛ 」∠)_
敵人怎么反擊的話,大家自己發揮想象力去做就好了,讓他發出散彈打你也是可以的哦~
但願你可以不用參考這個工程就能自己做出來https://pan.baidu.com/s/1e9rQIJt8AYDgHVPvbyJEuQ