当前位置: 首页 > article >正文

Unity3D学习FPS游戏(10)子弹攻击敌人掉血(碰撞检测)

前言:前面最然创造出带有血条的敌人,但子弹打中敌人并没有效果。所以本篇将实现子弹攻击敌人,并让敌人掉血。

子弹攻击敌人掉血

  • 整体思路
    • 目标
    • 补充知识-碰撞检测
  • 准备工作
    • 刚体和碰撞器添加
    • 添加刚体后子弹代码优化
    • 补充知识-标签系统
    • Tag添加
  • 碰撞检测代码编写
    • 敌人受伤
    • 子弹OnCollisionEnter函数
  • 效果

整体思路

目标

子弹碰到敌人后,进行一个碰撞检测。
判断碰敌人到后,子弹会被对象池回收,然后敌人会掉血,敌人血量掉到最低会自动销毁。
判断碰底板到后,子弹会被对象池回收。

补充知识-碰撞检测

Unity中默认生成的GameObject是没有物理也没有碰撞的,transform坐标移到哪里就是哪里。

Unity碰撞检测要求:

  • 两个物体都有碰撞器(Collider)
  • 运动的物体有刚体(Rigidbody)

关于刚体(Rigidbody)和碰撞器(Collider)组件的介绍:

  • 刚体(Rigidbody):使游戏对象在物理系统的控制下来运动,具有力的作用。
  • 碰撞器(Collider):碰撞器是物理组件的一类,它要与刚体一起添加到游戏对象上才能触发碰撞,碰撞器的大小形状规定物体发生碰撞的范围。

为什么碰撞检测不能只有碰撞器没有刚体?
因为判断碰撞就是需要计算力,刚体才能受到力的作用。

碰撞检测方法通常分为两种Collision碰撞和Trigger触发:

  • Collision碰撞
    函数:OnCollisionEnter/OnCollisionStay/OnCollisionExit
    效果:有一个相互作用的力,造成回弹的效果。
    条件:双方都有Collider,至少有一个运动的物体有Rigidbody。如果有Collider勾选了isTrigger或者刚体勾选了Kinematic,则碰撞无效。
  • Trigger触发
    函数:OnTriggerEnter/OnTriggerStay/OnTriggerExit
    效果:不会发生物体碰撞,也不会受到重力等物理作用力的影响,双方会直接穿过。
    条件:双方都有Collider,至少有一个运动的物体有Rigidbody。至少有一个碰撞体勾选IsTrigger。

Collision碰撞和Trigger触发的碰撞检测函数含义:

  • Enter事件表示两个物体接触瞬间,会执行一次事件。
  • Stay事件表示两个物体一直接触,会持续执行这个事件。
  • Exit事件表示两个物体分开瞬间,会执行一次事件。

isTrigger就是碰撞器中的一个属性,勾选之后可以就是触发器,不会发生碰撞,可以用做一些金币检测。
Kinematic是刚体的一个属性,在碰撞期间的行为类似于不可移动的对象,不受力的作用,但是可以进行速度操控。

准备工作

刚体和碰撞器添加

这里使用Collision碰撞,在FPS游戏中,常常会有打中怪的时候,怪往后退的效果,例如以前玩的“穿越火线”。

给子弹还有敌人添加胶囊形状碰撞体(Capsule Collider),不同碰撞体其实就是形状上的不太一样。
在这里插入图片描述
给子弹添加刚体。
在这里插入图片描述
添加新的组件后,子弹预制体如何更新。
在这里插入图片描述
敌人也加上胶囊碰撞体,因为碰撞检测需要碰撞双方都有碰撞体。
在这里插入图片描述

添加刚体后子弹代码优化

之前我们是通过计算transform位移更新子弹位置的,现在我们可以直接调用刚体的速度进行更新子弹位置。射程可以用时间来判断,速度恒定,调整移动时间其实也就规定了射程。

public class BulletController : MonoBehaviour
{
    private Rigidbody bulletRigidbody;// 刚体

    [Header("子弹数值")]
    public float bulletSpeed=100;// 子弹射速
    public float lifeTime = 10;// 子弹生存时间

    public ObjectPool<GameObject> bulletPool;

    private void Start()
    {
        bulletRigidbody = GetComponent<Rigidbody>();
    }

    private void FixedUpdate()
    {
        bulletRigidbody.velocity=transform.forward * bulletSpeed;
        lifeTime -= Time.fixedDeltaTime;
        if (lifeTime <= 0)
        {
            //Destroy(this.gameObject);
            bulletPool.Release(this.gameObject);
        }
    }

    public void BulletReset()
    {
        transform.localPosition = new Vector3(0,0,0);
        lifeTime = 10;
    }
}

补充知识-标签系统

标签 (Tag) 是可分配给一个或多个游戏对象的参考词。

标签有助于识别游戏对象以便于编写脚本。例如,可为玩家控制的角色定义“Player”标签,并为非玩家控制的角色定义“Enemy”标签。

标签对碰撞体控制脚本中的触发器很有用;例如,需要通过标签确定玩家是否与敌人、道具或可收集物进行交互。

Tag添加

给建筑物体添加Plane标签;玩家添加Player标签;敌人添加Enemy标签。

标签添加方式如下:
在这里插入图片描述
在这里插入图片描述

碰撞检测代码编写

有了前面的准备,现在要做的事情就很简单了,主要是把OnCollisionEnter函数部分编写好,以及敌人受伤。

敌人受伤

创建一个新的代码命名为EnemyController。

敌人血条的逻辑联动和之前武器的弹夹数量是一样的,初始化的时候设置好Slider大小和当前大小,每次血量减少的时候就更新血条。
设置好敌人的血量,编写一个Damage函数,让子弹碰撞的时候调用,进行血量的更新操作。

public class EnemyController : MonoBehaviour
{
    [Header("血量数值")]
    public Slider HPSlider;// 血量Slider UI
    public float HP = 100;// 血量
    void Start()
    {
        if (HPSlider)
        {
            HPSlider.maxValue = HP;
            HPSlider.value = HP;
        }
    }
    public void Damage(float damage)
    {
        if (HP > 0)// 有血量
        {
            HP -= damage;
            if(HPSlider)// 更新血条
                HPSlider.value = HP;
        }
        if (HP <= 0)// 敌人无血量则销毁
            Destroy(this.gameObject);
    }
}

子弹OnCollisionEnter函数

子弹主要是添加OnCollisionEnter函数,碰撞检测时候,如果碰到是敌人,调用敌人的Damge函数,再销毁子弹。

public float attackNum = 20;// 子弹攻击力
private void OnCollisionEnter(Collision collision)
{
    if (collision.gameObject.CompareTag("Enemy"))// 通过Tag判断是不是敌人
    {
        collision.gameObject.GetComponent<EnemyController>().Damage(attackNum);// 调用敌人攻击代码
    }
    Destroy(this.gameObject);// 碰到别的碰撞体就销毁
}

效果

在这里插入图片描述


http://www.kler.cn/a/382725.html

相关文章:

  • 6堆(超级重点)
  • 【C++】踏上C++学习之旅(五):auto、范围for以及nullptr的精彩时刻(C++11)
  • Vue.js 组件开发:构建高效、可重用的用户界面
  • DolphinScheduler告警通知
  • [论文][环境]3DGS+Colmap环境搭建_WSL2_Ubuntu22.04 - 副本
  • [signal] void QComboBox::currentTextChanged(const QString text)
  • 【数据结构】线性表——顺序表
  • 基于Python的校园爱心帮扶管理系统
  • Python 学习完基础语法知识后,如何进一步提高?
  • 【系统面试篇】进程与线程类(2)(笔记)——进程调度、中断、异常、用户态、核心态
  • 树莓派Linux 安装 EtherCat Igh
  • 谷歌浏览器安装 Vue.js devtools 插件
  • 讲解JVM日志的查看及解决系统频繁GC问题
  • 链表拆分与快慢指针相关算法题
  • 算法时间复杂度和真实时间测算
  • 枚举,联合(共用体)
  • 前后端跨域联调
  • SpringBooot之事务失效的场景
  • 护肤品类电商代运营的公司介绍与分析
  • 【Docker】X-DOC:使用WSL在Windows中体验Linux发行版安装桌面版Docker
  • 在 MacOS 上跑 kaldi
  • Java+控制台 商城销售系统
  • 【动态规划 数学】2745. 构造最长的新字符串|1607
  • Web Workers 学习笔记
  • 【QT】Qt文件和多线程
  • SSLHandshakeException错误解决方案