unity零基础开始学习做游戏(四)biu~biu~biu发射子弹打飞机
-------小基原创,转载请给我一个面子
主角都能移动了,那不得做点什么伸张正义,守护世界和平的事嘛,拿起家伙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
不过,这个敌人为啥打不死呢?!哦,因为他没有血条啊!那咋整啊?下一篇介绍制作通用进度条(血条)(= ̄ω ̄=)
转载于:https://www.cnblogs.com/agamer/p/9003622.html
unity零基础开始学习做游戏(四)biu~biu~biu发射子弹打飞机相关推荐
- unity零基础开始学习做游戏(五)看看你的完成度,进度条了解一下?
-------小基原创,转载请给我一个面子 上回书说道,英雄和魔王都做完了,子弹也能发射了,就是不知道啥时候能干死魔王.那小基得做个血条来展示一下,他离死不远了(•౪• ) 其实血条也可以看作是进度条 ...
- 零基础如何学习3DMax游戏建模?看完你又了解多少呢?
什么是游戏3D建模 在大型的游戏研发公司,3D建模是一个非常大的职能,分为4个岗位:3D角色低模手绘,3D场景低模手绘,次世代角色高模,次世代场景高模.通常我们所说的3D建模是指低模手绘. 零基础可以 ...
- SQL零基础入门学习(十四)
上篇:SQL零基础入门学习(十三) SQL NULL 值 NULL 值代表遗漏的未知数据. 默认地,表的列可以存放 NULL 值. 如果表中的某个列是可选的,那么我们可以在不向该列添加值的情况下插入新 ...
- 零基础怎样学习3d游戏建模,职业前景怎么样?
在确定要入行学习时,要确定你需要进入哪个行业,像我当初学习的时候就选择了游戏次时代建模一样. 有不少人说学3D建模直接去购买书籍学就可以了,其实学任何技术就好比建筑打地基,如果你地基不打扎实,那是不可 ...
- Innovus零基础lab学习全面复盘总
Innovus零基础lab学习全面复盘总结(附完整版pdf) 文章右侧广告为官方硬广告,与吾爱IC社区无关,用户勿点.点击进去后出现任何损失与社区无关. 为了让各位训练营学员更快入门数字 IC 后端, ...
- 学习次世代游戏建模需要了解什么?零基础成为次世代游戏设计师需要哪些阶段
次世代这个名词一直伴随着游戏机产业.从字面上看,次世代游戏就是"下一个游戏"的日文字面内容.如今众多的游戏都被冠以"次世代",但是"次世代" ...
- 零基础如何学习游戏3D建模,要学些什么内容?学多久?
一.什么是游戏3D建模在大型的游戏研发公司,3D建模是一个非常大的职能,分为4个岗位:3D角色低模手绘,3D场景低模手绘,次世代角色高模,次世代场景高模.通常我们所说的3D建模是指低模手绘. 二.零基 ...
- SQL零基础入门学习(四)
SQL零基础入门学习(三) SQL INSERT INTO 语句 INSERT INTO 语句用于向表中插入新记录. SQL INSERT INTO 语法 INSERT INTO 语句可以有两种编写形 ...
- python新手教程 从零开始-Python零基础从零开始学习Python十分钟快速入门
原标题:Python零基础从零开始学习Python十分钟快速入门 学习Python的,都知道Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言.Python是一种动态解释型的 ...
最新文章
- Modus串行链路系统电气特性:2线-Modus、4线-Modus、RS232-Modus和RS485-Modus的特性
- 【 Linux 】创建一个文件夹并在此文件下创建一个c源文件
- git拉取单个文件_Git拿来就用
- 【算法竞赛学习】金融风控之贷款违约预测-数据分析
- 在 ASP.NET Core 中使用 Serilog 使用 Fluentd 将日志写入 Elasticsearch
- wow工程修理机器人图纸_工程的修理机器人图纸是哪里弄来的……
- 亚马逊的新Linux发行版对红帽造成了威胁
- 代码逻辑分析_双十一模块 79.34% 的代码是怎样智能生成的
- wamp2.2c集成环境搭建网站问题总结
- 6.2016年国赛A题“系泊系统的设计”
- c#元胞自动机_元胞自动机+生命游戏
- UE高级性能剖析技术(三)-- Android内存分布和优化
- 等保备案和通信网络单元定级备案的五大区别讲解
- 阿里云centos环境之vsftpd安装(十五)
- 单核cpu多核cpu如何执行多线程
- html背景渲染原理(body透明渐变)
- find -perm 里的 + -的含义
- anaconda 代码提示,Anaconda安装OpenCV没有自动代码补全
- java调用其他java项目的Https接口
- 关于对《Spring Security3》翻译 (第一章 - 第三章)