zoukankan      html  css  js  c++  java
  • 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

    不过,这个敌人为啥打不死呢?!哦,因为他没有血条啊!那咋整啊?下一篇介绍制作通用进度条(血条)(= ̄ω ̄=)

    做游戏,一定要有爱
  • 相关阅读:
    二叉树之求叶子结点个数
    求二叉树的深度
    二叉树的基本操作
    二叉树之求结点个数
    数组面试
    数组之求子数组的最大乘积
    字符串之子串
    最近遇到的几个纯C编程的陷阱
    Ubuntu 16.04 64位安装YouCompleteMe
    Linux和Windows的遍历目录下所有文件的方法对比
  • 原文地址:https://www.cnblogs.com/agamer/p/9003622.html
Copyright © 2011-2022 走看看