Unity之简单射击游戏案例

家电修理 2023-07-16 19:17www.caominkang.com电器维修

PS该案例来自学习的课本和我自己的理解。文章创作,还请多多支持呀各位美女、帅哥们!!!

废话不多说先上游戏实机操作视频

射击游戏实机操作_Trim

游戏内容大致如下

(1)完全使用键盘控制,由W、A、S、D键控制角色的方向移动,J键控制射击。(这样做主要是为了简化游戏输入部分的逻辑。)
(2)玩家具有多种武器,如手枪、霞弹枪和自动步枪,每种武器可以按Q键切换。
(3)场景上除了玩家角色还有若干敌人。敌人会向玩家方向移动并射击玩家。
(4)玩家角色和敌人都有生命值,中弹后生命值减少,减为零时则死亡。

那么接下来就看看实现过程吧!文末有游戏半成品分享,不嫌弃就玩玩看哈。

目录

1.角色脚本

2.跟随摄像机

3.武器系统 

武器

子弹

4.射击的实现

5.游戏全局管理器


场景中,平台平面设为20x20的Plane

1.角色脚本

我们要创建出游戏玩家和敌人,包含(生命、移速等)属性,并给予他们特定的移动机制如下

玩家自由移动,但活动限制在平台区域。

敌人始终朝向敌人移动,但速度相对较慢。

 玩家脚本(Player)代码如下

//移动速度
 public float c_speed;

 //最大血量
 public float m_maxHp ;

 //输入方向变量
 Vector3  c_input;

 //判断是否死亡
 bool LifeState=true;

 //当前血量
 private float c_Hp;
 void Start()
 {
  //刚开始满血
  c_Hp = m_maxHp;
  }
 void Update()
 {
  //将键盘的横向、纵向输入,保存在input中
  c_input = ne Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

  bool fireKeyDon = Input.GetKeyDon(KeyCode.J);
  bool fireKeyPressed = Input.GetKey(KeyCode.J);
  bool changeWeapon = Input.GetKeyDon(KeyCode.Q);


  //判断是否dead,还活着就可以动

  Debug.Log("现在还剩血量" + c_Hp);
 void Move()
  {
   //先归一化输入变量,让输入更直接,避免斜向移动时速度超过最大值
   c_input =c_input.normalized;
   transform.position += c_input  c_speed  Time.deltaTime;
   //令角色前方与移动方向一致
   if (c_input.magnitude > 0.1f)
   {
    transform.forard = c_input;
   }

   //限制移动范围
   Vector3 c_VectorTemp=transform.position ;
   const float m_border = 20f;
   if(c_VectorTemp.x < -m_border)
   {
    c_VectorTemp.x = -m_border;

   }
   if (c_VectorTemp.x > m_border)
   {
    c_VectorTemp.x = m_border;

   }
   if (c_VectorTemp.z < -m_border)
   {
    c_VectorTemp.z = -m_border;

   }
   if (c_VectorTemp.z > m_border)
   {
    c_VectorTemp.z = m_border;

   }

   transform.position = c_VectorTemp;

  }
 }

敌人脚本(Enemy)代码如下

 public float speed = 6;
 public float maxHp=4;
 Vector3 input;
 Transform player;
 float hp;
  bool lifeState = true;

  void Start()
 {
player = GameObject.Find("Player").transform;
hp = maxHp;
   }
 void Update()
 {
  

  EnemyMove();
 Debug.Log("敌人还剩血量" + hp);
   }
 //敌人的移动机制
 void EnemyMove()
 {
  //敌人的移动是始终朝向玩家的,他想干掉我们
  input = player.position - transform.position;
  input = input.normalized;

  transform.position += input  speed  Time.deltaTime;
  if (input.magnitude > 0.1f)
  {
   transform.forard = input;
  }
 }

2.跟随摄像机

将摄像机调整至合适位置后,利用三维向量的差值,以玩家为原点为摄像机变换位置

赋予主摄像机如下脚本(FolloPlayer)代码

public Transform folloTaeget;
 Vector3 offset;

 
 void Start()
 {
  //设置偏移量
  offset = transform.position - folloTaeget.position;
 }

   
 void LateUpdate()
 {
  
  transform.position =  folloTaeget.position + offset;
  
 }

上面代码中,摄像机的移动放在LateUpdate事件中,避免了帧数问题引起的游戏视角界面卡顿。

3.武器系统 

敲黑板了!!!!!!  这一块灰常的重要哦。武器系统是玩家和敌人公用的一块。

武器

0.手枪单射,有射击间隔 ,我感觉没啥用的一把枪。

1.霰弹枪单射且射出五发子弹,射程短的可怜!

2.自动步枪连射,用起来挺爽的!

子弹

创建两个预制体分为PlayerBullet和EnemyBullet

属性具有生命周期

这里先实现武器系统组件脚本,代码如下

public class Weapon : MonoBehaviour
{

 //子弹的预制体
 public GameObject prefabBullet;

 //几种武器的CD长度
 public float pistolFireCD = 0.2f;
 public float shotgunFireCD = 0.5f;
 public float rifleFireCD = 0.1f;

 //上次开火时间
 float lastFireTime;

 //当前的武器
 public int curGun //  0:手枪,1霰弹枪,2自动步枪
 {
  get;
  private set;
 }

 //设置开火函数
 //keyDon指代单射,keyPressed指代连射
 public void Fire(bool keyDon,bool keyPressed)
 {
  sitch (curGun)
  {
   case 0:
   if (keyDon)
    {
     PistolFire();
    }
    break;
   case 1:
    if (keyDon)
    {
     ShotgunFire();
    }
    break;
   case 2:
    if(keyPressed)
    {
     RifleFire();
    }
    break;

  }

 }

 //更换武器
 public int Change()
 {
  if (curGun != 3)
  {
   curGun++;
  }
  else
  {
   curGun = 0;
  }
  return curGun;
 }

 //手枪射击专用函数
 public void PistolFire()
 {
  if (lastFireTime + pistolFireCD > Time.time)
   return;
  lastFireTime = Time.time;

  GameObject bullet = Instantiate(prefabBullet, null);
  bullet.transform.position = transform.position + transform.forard  1f;
  bullet.transform.forard = transform.forard;
 }
 //霰弹射击专用函数
 public void ShotgunFire()
 {
  if (lastFireTime + shotgunFireCD > Time.time)
   return;
  lastFireTime = Time.time;

    //创建5颗子弹,相互间间隔10度,分布于前方扇形区域
    for(int i = -2; i <= 2; i++)
  {
   GameObject bullet = Instantiate(prefabBullet, null);
   Vector3 dir = Quaternion.Euler(0, i  10, 0)  transform.forard;

   bullet.transform.position = transform.position + dir  1f;
   bullet.transform.forard = dir;

   //霰弹枪的子弹射击距离很短,修改子弹的生命周期
   Bullet b = bullet.GetComponent();
   b.lifeTime = 0.3f;
  }
 }
 //自动步枪射击专用函数
 public void RifleFire()
 {
  if (lastFireTime + rifleFireCD > Time.time)
   return;
  lastFireTime = Time.time;

  GameObject bullet = Instantiate(prefabBullet, null);
  bullet.transform.position = transform.position + transform.forard  1.2f;
  bullet.transform.forard = transform.forard;
 }
 void Start()
 {
  
 }

   
 void Update()
 {
  
 }
}

接下是为子弹创建脚本,代码如下

public class Bullet : MonoBehaviour
{
 public float c_bulletSpeed = 10f;
 //设置子弹的生命周期
 public float lifeTime = 2;
 //子弹生成的时间
 float startTime;
   
 void Start()
 {
  startTime = Time.time;
 }

   
 void Update()
 {
  //子弹移动
  transform.position+= c_bulletSpeed  transform.forard  Time.deltaTime;
  //自毁装置
  if (startTime + lifeTime < Time.time)
   Destroy(gameObject);
 }

 //中弹事件
 private void OnTriggerEnter(Collider other)
 {
  //同类子弹碰撞不销毁
  if (CompareTag(other.tag))
   return;

  Destroy(gameObject);
 }
}

上面的“中弹事件”在后文的射击的实现会用到滴! 

4.射击的实现

有了武器,那么敌人和玩家的脚本都可以进行更新了,运用武器系统实例对象实现攻击。,在相互射击的过程中,如果一方中弹,则扣一滴血。

己方子弹射中自己不造成伤害,子弹击中对方后消失,子弹相互碰撞也消失。

子弹碰撞逻辑

碰撞事件是相对的,子弹碰撞的逻辑可以写在 Bullet 脚本、Player脚本或 Enemy 脚本中。在制作时最好单独考虑碰撞问题,然后统一编写。要制作的效果如下。
1、玩家角色的子弹击中敌人角色,会让敌人角色掉血。
2、敌人角色的子弹击中玩家角色,会让玩家角色掉血。
3、玩家角色的子弹不会击中玩家角色,敌人角色的子弹也不会击中敌人角色。
4、玩家角色的子弹与敌人角色的子弹可以相互抵消,同类子弹不能抵消。这一设计可以根据读者的偏好添加或取消。
从以上分析可以看出,“敌人角色的子弹”与“玩家角色的子弹”是截然不同的,最好用某种机制区分出二者。课本作者采用的方法是把这两种子弹做成两个不同的预制体,一个命名为PlayerBullet,另一个命名为EnemyBullet。然后利用标签(Tag)做出区分,前者的Tag是PlayerBullet,后者的Tag是EnemyBullet。

那么,请在之前的Player脚本中添加如下代码

 Weapon eapon;
 
 void Start()
 {
    //给武器类对象变量引用脚本
  eapon = GetComponent();
 }

  void Update()
 {
 if (LifeState==true )
  {


   Move();
   eapon.Fire(fireKeyDon, fireKeyPressed);
   if (changeWeapon)
   {
    eapon.Change();
   }
   

  }
  else { Time.timeScale = 0; }


 private void OnTriggerEnter(Collider other)
 {
  if (other.CompareTag("EnemyBullet"))
  {
   if (c_Hp <= 0) { return; }
   c_Hp-=1;
   if (c_Hp == 0) { LifeState = false; }
  }
 }

 相应的,对敌人的脚本(Enemy)也添加如下代码

  public float fireTime = 1f;
  float m_time ;

 Weapon eapon;
 void Start()
 {
 eapon = gameObject.GetComponent();
 m_time = Time.time;
 }
   void Update()
 {
  

  EnemyMove();
  endFire();
  Debug.Log("敌人还剩血量" + hp);
  if (hp <= 0)
  {
     // Instantiate(prefabBoomEffect, transform.position, transform.rotation);
   Destroy(gameObject);
     
    Debug.Log("恭喜你赢了!重要的事情说三遍");
    Debug.Log("恭喜你赢了!重要的事情说三遍");
    Debug.Log("恭喜你赢了!重要的事情说三遍");
    
     
  }

    
 }

   //控制攻击间隔
 void endFire()
 {
  if (m_time + fireTime < Time.time)
  {
   Fire();
   m_time = Time.time;
  }

 }

 //敌人的攻击机制
 void Fire()
 {
  eapon.Fire(true, true);
 }

 private void OnTriggerEnter(Collider other)
 {
  if (other.CompareTag("PlayerBullet"))
  {
   if (hp <= 0) { return; }
   hp--;
   if (hp == 0) { lifeState = false; }
  }
 }

5.游戏全局管理器

我还不会这一部分,那咱们就一下吧!【doge】

游戏的脚本一共是涉及下面六个

涉及的必要游戏物体有Player、Enemy、Plane

游戏半成品下载地址https://pan.baidu./s/1FtJMS23XGMH4FB2TKnuXDA 
提取码PZPZ 

PS终于写完了,睡觉了,困死了!!!!!!! 

Copyright © 2016-2025 www.caominkang.com 曹敏电脑维修网 版权所有 Power by