unity2D学习(12)角色发射子弹

您所在的位置:网站首页 unity发射炮弹教案 unity2D学习(12)角色发射子弹

unity2D学习(12)角色发射子弹

2023-08-01 08:22| 来源: 网络整理| 查看: 265

1 思路

效果的想法:按下“Fire1”就可以切换为shoot射击状态,角色就会自动连续发射子弹,在shoot模式下再按下“Fire1”就可以切换回上一个状态。

代码的思路:用一个Empty GameObject作为枪口,然后一个PreFab预制体作为子弹。

2 子弹

新建一个Sprite,并命名为Bullet(子弹)。

然后为Bullet添加Rigidbody 2D(刚体)、Box Collider 2D(碰撞器)、Script(脚本)。其中Rigidbody 2D(刚体)注意Gravity Scale(重力)设置为0,这样可以直线发射子弹,然后勾选掉Freeze Rotation(自由旋转)。Box Collider 2D(碰撞器)里面要勾选is Trigger(扳机),后面代码要用到OnTriggerEnter2D(和OnCollisionEnter2D的区别在上一个文章里面提到过)。

子弹代码:

using System.Collections; using System.Collections.Generic; using UnityEngine; public class BulletController : MonoBehaviour { [SerializeField] private float speed = 5f;//子弹的速度 public Rigidbody2D rig; void Start () { rig = GetComponent();//获取子弹刚体组件 rig.velocity = transform.right * speed;//移动 Destroy(gameObject, 2);//2秒后销毁子弹,不然子弹会无限多 } private void OnTriggerEnter2D(Collider2D collision)//触碰到别的碰撞器的时候 { if (collision.gameObject.tag == "Enemy")//如果碰撞对象是敌人 { collision.gameObject.GetComponent().Hurt();//调用敌人的受伤函数,新加入到敌人的里面函数用来扣敌人血量,方便查看效果,不然太快了 } Destroy(gameObject);//只要碰撞到碰撞体就摧毁子弹本身 } }

上面的敌人新加的受伤函数会在下面Instantiate函数介绍给出。

3 Prefab介绍

Prefab(预制件):一种资源类型,用来存储在项目视图中反复使用的对象。

如何生成Prefab(以上面的Bullet子弹为例子):只需要把GameObject拖拽到Assert里对应的文件夹,就会在该文件夹下生成对应GameObject 的Prefab。方便后面枪口发射子弹调用创建实例。

如果Prefab拖拽回SampleScene里面,相当于创建了一个实例。

4 Instantiate函数介绍

Instantiate函数:在unity中进行实例化的函数,返回克隆,可以用于GameObject或Component。

重载(overloaded):

public static Object Instantiate(Object original);public static Object Instantiate(Object original, Transform parent);public static Object Instantiate(Object original, Transform parent, bool instantiateInWorldSpace);public static Object Instantiate(Object original, Vector3 position, Quaternion rotation);public static Object Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent);

参数介绍:

original复制的现有对象position复制到那个位置rotation朝向parent分配新父对象instantiateInWorldSpace分配父对象时,传递为true可将新对象直接放置在空间中,传递为false以设置对象相对于其新父对象的位置

使用范例:在CrabController代码里添加敌人新加的受伤函数,给子弹碰撞到敌人调用

变量 public GameObject ExplodePrefab;//爆炸效果的预制体 private float Hp = 100f;//敌人的hp一开始的为100f 函数 public void Hurt() { Hp -= 25f;//每次受伤扣除25f if (Hp Artwork->Sprites->FX->enemy-death的动画图片组(动画添加就不详细写了,在unity2D学习(5)为角色添加动画里面有),记得保持单位像素统一为16。

代码:

using System.Collections; using System.Collections.Generic; using UnityEngine; public class Explode : MonoBehaviour { //就是设置一下销毁时间 void Start () { Destroy(gameObject, 0.2f);//0.2秒后销毁爆炸效果,0.2秒也是我设置的爆炸动画完整一次的时间 } }

然后把Explode拖到对应文件夹形成预制体,再把预制体拖拽到CrabConttroller对应的explodePrefabe变量去。

6 枪口

在Player下面新建一个Empty GameObject并取名为Gun(枪)。

把Player的Shoot动画弄出来,然后把Gun的位置调整到角色枪口的地方,因为在Player地下,所以Gun的位置会跟随Player移动。

然后枪口不会跟随角色翻转而反转,要修改一下之前Player的控制代码里面的Flip函数。把原先的transform.localScale = new Vector2(face, 1)改为transform.Rotate(0f,180f,0f),这样枪口也会跟着反转。

void Flip() { face = (face == 1) ? -1 : 1; //transform.localScale = new Vector2(face, 1);//原来的反转代码 transform.Rotate(0f,180f,0f);//这样枪口也会一起转向 }

枪口代码:

using System.Collections; using System.Collections.Generic; using UnityEngine; public class Weapon : MonoBehaviour { public GameObject bulletPrefab; public float fireRate = 0.5F;//0.5秒实例化一个子弹 private float nextFire = 0.0F; public void Shoot() { if(Time.time > nextFire)//让子弹发射有间隔 { nextFire = Time.time + fireRate;//Time.time表示从游戏开发到现在的时间,会随着游戏的暂停而停止计算。 Instantiate(bulletPrefab, transform.position, transform.rotation); } } }

7 动画转换

添加了新的参数fire(Bool)来判断是否处于射击状态。

为动画转移添加runShoot和Shoot,站立射击和跑动射击。

动画转移参数:

idle->shoot:fire为trueshoot->idle:fire为falserunShoot->shoot:speed小于0.01fshoot->runShoot:speed大于0.01frun->runShoot:fire为truerunShoot->run:fire为false

8 Player控制的总代码

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class PlayerController : MonoBehaviour { private Rigidbody2D rig;//刚体 private Animator Anim;//角色的Animator [Header("Layers")] public LayerMask groundLayer;//用来开启layer [Space] [Header("Speed")] private float moveSpeed=360f;//移动速度 private float climbSpeed=100f;//爬行速度 [Space] [Header("Force")] private float moveForce=150f;//移动力 private float jumpForce=575f;//跳跃力 [Space] [Header("Frequency")] private int jumpMax=2;//跳跃次数的上线 private int jumpNum=0;//当前跳跃的次数 [Space] [Header("Booleans")] private bool falling = false;//用来标记是否是下落状态 private bool onWall;//是否在墙上 private bool onJumping;//是否正在跳跃中 private bool onGround;//是否正在地上 private bool onHurt;//是否受伤 private bool onShooting;//是否开枪 [Space] [Header("Collision")] private float collisionRadius = 0.15f;//碰撞半径 private Vector2 bottomOffset, rightOffset, leftOffset;//下左右相对于角色中心的二维向量 private Collider2D coll;//角色的碰撞器 [Space] [Header("UI")] private Text HpNumberText; [Space] private float face = 1;//角色朝向,初始朝向向右边 private float HP=100f;//角色血量 public GameObject weapon;//调用武器 //初始化 void Start() { rig = GetComponent();//获取主角刚体组件 Anim = GetComponent();//获取主角动画组件 coll = GetComponent();//获取角色碰撞器 weapon= GameObject.Find("Gun");//获取枪 HpNumberText = GameObject.Find("HpNumber").GetComponent();//获取ui对于的text groundLayer = 1 0)//是否有爬墙的行为,按向上键 { onGround = false; onWall = true; Climb(verticalMove); } } if (Input.GetButtonDown("Jump")) { onGround = false; onJumping = true; Jump(); } } else if (onJumping)//在空中跳跃 { if (touchWall())//可以爬墙 { onJumping = false;//关闭现在状态 onWall = true;//开启下一个状态 Climb(verticalMove);//爬行 jumpNum = 0;//跳跃次数清零 } else if (Input.GetButtonDown("Jump"))//二段跳 { Jump(); } } else if (onWall)//在墙上 { if(Input.GetButtonDown("Jump")) { onWall = false; onJumping = true; Flip(); Jump(); } else if (touchWall())//如果碰到墙,就说明还在爬 { Climb(verticalMove); } else//如果说爬到了末端,就可以有跳跃行为,不然的话难爬到地面 { onWall = false; onJumping = true; Jump(); } } } void Flip()//反转 { face = (face == 1) ? -1 : 1;//在墙上跳出的话,动画要和原来相反 transform.Rotate(0f,180f,0f);//这样枪口也会一起转向 } bool isGround()//判断是否碰地 { return Physics2D.OverlapCircle((Vector2)transform.position + bottomOffset, collisionRadius, groundLayer);//判断是否碰到地面 } bool isShooting()//判断是否射击 { if (Input.GetButtonDown("Fire1")) { onShooting=(onShooting == true)? false : true ; Debug.Log(onShooting); } return onShooting; } void shoot(float moveMultiple, float faceDirection) { weapon.GetComponent().Shoot(); move(moveMultiple, faceDirection);//左右移动 } bool touchWall()//判断是否碰到墙 { return Physics2D.OverlapCircle((Vector2)transform.position + rightOffset, collisionRadius, groundLayer) || Physics2D.OverlapCircle((Vector2)transform.position + leftOffset, collisionRadius, groundLayer); } void move(float moveMultiple,float faceDirection)//移动代码 { //角色左右移动 if (moveMultiple != 0) { //velocity表示速度,Vector表示向量 rig.velocity = new Vector2(moveMultiple * moveSpeed * Time.deltaTime, rig.velocity.y);//输入x,y向量,数值*方向 } //角色朝向修改 if (faceDirection != 0&&face!=faceDirection) { Flip(); } } void Jump()//跳跃代码 { if(jumpNum < jumpMax) { rig.velocity = new Vector2(face*moveForce*Time.deltaTime, jumpForce * Time.deltaTime); jumpNum++; } } void Hurt(Collision2D collision)//受伤代码 { onHurt = true; AccordingDirectionFlip(collision); rig.velocity = new Vector2(face * moveForce * Time.deltaTime, jumpForce * Time.deltaTime); } void AccordingDirectionFlip(Collision2D collision)//根据敌人方向,安排玩家转向 { if (collision != null)//如果玩家出现视野中 { int direction; if (collision.transform.position.x < transform.position.x) { direction = -1;//玩家在敌人的左边 } else { direction = 1;//玩家在敌人的右边 } if (direction != face)//表示方向不一致 { //Debug.Log(direction); Flip(); } } } void Climb(float verticalMove)//爬墙代码 { rig.velocity = new Vector2(rig.velocity.x,climbSpeed * verticalMove* Time.deltaTime);//输入x,y向量,数值*方向 } void changeAnimator()//动画切换 { if (onGround)//如果在地上 { Anim.SetFloat("speed", Mathf.Abs(rig.velocity.x));//速度是向量 if (onHurt) { Anim.SetBool("injured", true); onGround = false; } if (onShooting) { Anim.SetBool("fire", true); } else { Anim.SetBool("fire", false); } } if (onWall)//如果在墙上 { Anim.SetBool("wall", true); if (Anim.GetBool("ground") == false) { Anim.SetBool("ground", true); } } else { Anim.SetBool("wall", false); } if (onJumping)//如果在跳跃状态 { if (onHurt) { Anim.SetBool("injured", true); jumpNum = 0;//当前跳跃次数清零 falling = false; onJumping = false; } else if (Anim.GetBool("ground")) { falling = false; Anim.SetBool("ground", false); } else { if (falling&&isGround()) { Anim.SetBool("ground", true); jumpNum = 0;//落地的话,当前跳跃次数清零 falling = false; onJumping = false; onGround = true; } else if(rig.velocity.y < 0) { falling = true; } } } if (onHurt)//如果在受伤状态 { if (falling && isGround()) { Anim.SetBool("injured", false); Anim.SetBool("ground", true); falling = false; onGround = true; onHurt = false; } else if (rig.velocity.y < 0) { falling = true; } } } void OnDrawGizmos()//绘制辅助线 { Gizmos.color = Color.red;//辅助线颜色 //绘制圆形辅助线 Gizmos.DrawWireSphere((Vector2)transform.position + bottomOffset, collisionRadius); Gizmos.DrawWireSphere((Vector2)transform.position + rightOffset, collisionRadius); Gizmos.DrawWireSphere((Vector2)transform.position + leftOffset, collisionRadius); } void OnCollisionEnter2D(Collision2D collision) { if (collision.gameObject.tag == "Enemy") { HP -= 25f;//碰到一次敌人减去25血量 HpNumberText.text = HP.ToString();//显示HP Hurt(collision); } } }

9 游戏效果



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3