【Unity】3D功能开发入门系列(五)

发布于:2024-08-08 ⋅ 阅读:(105) ⋅ 点赞:(0)

一、预制体

(一)预制体

预制体 Prefab,即预先制作好的物体。使用预制体,可以快速创建物体,提高开发效率。

演示:导出 RacingCar 资源包

  • 在 Prefab 目录下,是预制体资源,* .prefab
  • 用预制体来构造物体
    在这里插入图片描述

在 Prefab 中,多级节点 / 父子关系,是常见的情况

(二)预制体的创建

  1. 先制作好一个样本节点
  2. 做好以后,直接拖到 Assets 窗口,则自动生成一个 *.prefab 资源
  3. 原始物体不再需要,可以删除
    在这里插入图片描述

导出 prefab 资源时,应将依赖文件一并导出prefab 只是记录了节点信息,文件中不包含材质、贴图数据,仅包含引用在这里插入图片描述

(三)预制体实例

1. prefab Instance,由预制体创建得到的对象
特征: 在 Hierarchy 中,节点图标不同、右键菜单 | Prefab、上下文工具 | Prefab
在这里插入图片描述
在这里插入图片描述
2. Prefab Instance 和原 Prefab 之间存在关联
右键菜单 Prefab | Unpack,则解除关联,成为普通物体
在这里插入图片描述

在这里插入图片描述

(四)预制体的编辑

*.prefab 相当于是一个模板,可以再次编辑(其实例也会同步改变)

1. 单独编辑

  • 双击 Prefab,进入 单独编辑 模式
  • 编辑节点和组件
  • 退出,完成编辑
    在这里插入图片描述

2. 原位编辑

  • 选择 Prefab Instance
  • 在检查器中 Open
  • Context 显示:Normal / Gray / Hidden (此时,仅选中的物体被编辑,其余物体是陪衬
  • 编辑节点
  • 退出,完成编辑
    在这里插入图片描述
    在这里插入图片描述

3. 覆盖编辑

  • 选择 Prefab Instance
  • 直接在场景中编辑
  • 编辑完后 Override | Apply 应用编辑、Override | Revert 取消编辑
    在这里插入图片描述

二、动态创建实例

(一)动态创建实例

创建 Prefab 之后,用 API 动态创建实例

Object.Instance(original,parent);

演示:

  1. 准备子弹 prefab
  2. 添加火控脚本 FireLogic
  • 添加变量
public GameObject bulletPrefab;
  • 克隆实例
GameObject node = Instance(bulletPrefab,null);
node.transform.position = Vector3.zero;
node.tansform.localEulerAngles = Vector3.zero;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FireLogic : MonoBehaviour
{
    // 对子弹 prefab 资源的引用
    public GameObject bulletPrefab;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            TestFire();
        }
    }

    private void TestFire()
    {
        Debug.Log("* 创建子弹的实例 ..");
        GameObject node = Object.Instantiate(bulletPrefab, null);
        node.transform.position = Vector3.zero;
        node.transform.localEulerAngles = Vector3.zero;
    }
}

在这里插入图片描述

(二)实例的初始化

创建 Prefab Instance 之后,应做初始化:
1. parent,设置父节点。 为便于节点的管理,应单独创建一个父节点
在这里插入图片描述

2. position / localPosition,出生节点。 为便于操作,应显示标记一个出生点
在这里插入图片描述
3. eulerAngles / localEulerAngles / rotation 旋转。 对子弹来说,子弹角度应与炮塔旋转角度一致
在这里插入图片描述

4. Script,自带的控制脚本。 子弹自带了 BulletLogic,可以控制其飞行速度
在这里插入图片描述

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletLogic : MonoBehaviour
{
    public float speed;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(0, 0, speed, Space.Self);
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FireLogic : MonoBehaviour
{
    // 对子弹 prefab 资源的引用
    public GameObject bulletPrefab;
    // 父子关系靠 Transform 维持,后面创建实例要找父级
    public Transform bulletFolder;
    // 出生点位置的指定
    public Transform firePoint;
    // 得到炮塔的旋转角度
    public Transform cannon;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            TestFire();
        }
    }

    private void TestFire()
    {
        Debug.Log("* 创建子弹的实例 ..");
        GameObject node = Object.Instantiate(bulletPrefab, bulletFolder);
        node.transform.position = this.firePoint.position; //Vector3.zero;
        node.transform.localEulerAngles = this.cannon.eulerAngles; //Vector3.zero;
        // node.transform.rotation = this.cannon.rotation;

        BulletLogic script = node.GetComponent<BulletLogic>();
        script.speed = 0.5f;
    }
}

  • 一般引用 Transform,而 GameObject 是没有存在感的
  • 可以使用空物体,标记一个空间位置

(三)实例的销毁

一般的,创建实例之后,也要负责销毁。

对于子弹来说

  • 飞出屏幕时,销毁 X
  • 射程 / 飞行时间 V
  • 击中目标时,销毁 V

Object.Destroy( obj ),用于销毁一个实例

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletLogic : MonoBehaviour
{
    public float speed;

    public float maxDistance;
    // Start is called before the first frame update
    void Start()
    {
        float lifetime = 1;
        if(speed > 0)
        {
            lifetime = maxDistance / speed;
        }
        Invoke("SelfDestroy", lifetime);
    }

    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(0, 0, speed, Space.Self);
    }

    private void SelfDestroy()
    {
        Debug.Log("* 自毁 !");
        Object.Destroy(this.gameObject);
    }
}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FireLogic : MonoBehaviour
{
    // 对子弹 prefab 资源的引用
    public GameObject bulletPrefab;
    // 父子关系靠 Transform 维持,后面创建实例要找父级
    public Transform bulletFolder;
    // 出生点位置的指定
    public Transform firePoint;
    // 得到炮塔的旋转角度
    public Transform cannon;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            TestFire();
        }
    }

    private void TestFire()
    {
        Debug.Log("* 创建子弹的实例 ..");
        GameObject node = Object.Instantiate(bulletPrefab, bulletFolder);
        node.transform.position = this.firePoint.position; //Vector3.zero;
        node.transform.localEulerAngles = this.cannon.eulerAngles; //Vector3.zero;
        // node.transform.rotation = this.cannon.rotation;

        // 指定初始飞行速度
        BulletLogic script = node.GetComponent<BulletLogic>();
        script.speed = 0.5f;

        script.maxDistance = script.speed * 10;
    }
}

在这里插入图片描述

  • Destroy( this ) 这样写是错误的,我们要销毁物体,而不是组件
  • Destroy( ) 不会立即执行,而是在本轮 Update 之后才执行

(四)练习:火控参数&按键控制

练习1:火控参数的完善

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FireLogic : MonoBehaviour
{
    // 对子弹 prefab 资源的引用
    public GameObject bulletPrefab;
    // 父子关系靠 Transform 维持,后面创建实例要找父级
    public Transform bulletFolder;
    // 出生点位置的指定
    public Transform firePoint;
    // 得到炮塔的旋转角度
    public Transform cannon;
    // 实现火控参数的动态管理
    public float bulletSpeed;
    public float bulletLifetime;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetMouseButtonDown(0))
        {
            TestFire();
        }
    }

    private void TestFire()
    {
        Debug.Log("* 创建子弹的实例 ..");
        GameObject node = Object.Instantiate(bulletPrefab, bulletFolder);
        node.transform.position = this.firePoint.position; //Vector3.zero;
        node.transform.localEulerAngles = this.cannon.eulerAngles; //Vector3.zero;
        // node.transform.rotation = this.cannon.rotation;

        // 指定初始飞行速度
        BulletLogic script = node.GetComponent<BulletLogic>();
        script.speed = this.bulletSpeed;
        script.maxDistance = script.speed * this.bulletLifetime;
    }
}

在这里插入图片描述

练习2:添加按键控制,旋转炮塔方向
官方文档:https://docs.unity.cn/cn/2022.3/ScriptReference/Transform-localEulerAngles.html,不建议使用rotate
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FireLogic : MonoBehaviour
{
    // 对子弹 prefab 资源的引用
    public GameObject bulletPrefab;
    // 父子关系靠 Transform 维持,后面创建实例要找父级
    [Tooltip("子弹节点管理")]
    public Transform bulletFolder;
    [Tooltip("子弹出生点")]
    public Transform firePoint;
    // 得到炮塔的旋转角度
    [Tooltip("炮塔")]
    public Transform cannon;
    // 实现火控参数的动态管理
    [Tooltip("子弹飞行速度")]
    public float bulletSpeed;
    [Tooltip("子弹飞行时长")]
    public float bulletLifetime;
    // 实现连发 + 方向控制
    [Tooltip("子弹发射间隔")]
    public float bulletInterval;
    [Tooltip("炮塔转速")]
    public float rotateSpeed;

    // 当前转角
    private Vector3 m_eulerAngles;

    void Start()
    {
        StartFire();
    }

    void Update()
    {
        float delta = rotateSpeed * Time.deltaTime;

        // 左右是绕 y 轴旋转,上下是绕 x 轴旋转(上左负)
        if(Input.GetKey(KeyCode.A))
        {
            //左转
            if (m_eulerAngles.y > -75)
                m_eulerAngles.y -= delta;
        }
        if(Input.GetKey(KeyCode.D))
        {
            //右转
            if (m_eulerAngles.y < 75)
                m_eulerAngles.y += delta;
        }
        if(Input.GetKey(KeyCode.W))
        {
            //上转
            if(m_eulerAngles.x > -60)
                m_eulerAngles.x -= delta;
        }
        if(Input.GetKey(KeyCode.S))
        {
            if(m_eulerAngles.x < 10)
                m_eulerAngles.x += delta;
        }

        cannon.transform.localEulerAngles = m_eulerAngles;
    }

    private void TestFire()
    {
        // 指定父节点
        GameObject node = Object.Instantiate(bulletPrefab, bulletFolder);
        // 指定出生点
        node.transform.position = this.firePoint.position; 
        // 与炮塔角度一致
        node.transform.localEulerAngles = this.cannon.eulerAngles; 
        
        // 指定初始飞行速度
        BulletLogic script = node.GetComponent<BulletLogic>();
        script.speed = this.bulletSpeed;
        script.maxDistance = script.speed * this.bulletLifetime;
    }

    // 开火
    public void StartFire()
    {
        if(!IsInvoking("TestFire"))
        {
            InvokeRepeating("TestFire", bulletInterval, bulletInterval);
        }
    }
    public void StopFire()
    {
        CancelInvoke("TestFire");
    }
}

在这里插入图片描述


三、物理系统

(一)物理系统

  1. 物理系统 Physics,即由物理规律起作用的系统,确切的说,是牛顿运动定律(力、质量、速度)
    演示:布置一个场景,添加 ‘地面’,‘苹果’,运行游戏,‘苹果’ 悬空,这很不牛顿!

  2. 刚体组件 Rigidbody,物理学中的物体,当添加 Rigidbody 后,由 物理引擎负责刚体运动(物理引擎会根据它的质量、力、速度之间的关系自动做出运算,使其运动)

给 ‘苹果’ 添加一个 Rigidbody 组件:Physics | Rigidbody,运行游戏
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(二)物理碰撞

物理系统,不仅接管了刚体的运动,也接管了碰撞
碰撞体 Collider,描述了物体的碰撞范围。其中 Box Collider 长方碰撞体、Sphere Collider 球形碰撞体
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
绿框与绿框相碰,会被物理引擎捕捉到
在这里插入图片描述

(三)反射与摩擦

钢铁的反弹与摩擦,也归物理系统负责。
演示:

  • 新建 Physical Material,添加给小球
    在这里插入图片描述
    在这里插入图片描述
  • 设置 Friction、Bounciness
  • 观察小球的反弹
    在这里插入图片描述

四、碰撞检测

(一)运动学刚体

运动学刚体 Kinematic,即质量为 0 的刚体。由于质量为 0,所以此刚体不受牛顿约束。
在这里插入图片描述
此时,需要使用脚本使运动

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SimpleLogic : MonoBehaviour
{
    public Vector3 speed;
    
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(speed * Time.deltaTime, Space.Self);
    }
}

(二)碰撞检测

对于运动学刚体,也支持碰撞检测。由 物理引擎 负责检测。
在这里插入图片描述
演示:

  1. 勾上 Rigidbody | Is Kinematic、Collider | Is Trigger(触发器)
  2. 挂一个脚本,添加消息函数
void OnTriggerEnter(Collider other){}

其中,Collider other 对方碰撞体、other.gameObject 对方节点、other.name 对方节点的名字

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SimpleLogic : MonoBehaviour
{
    public Vector3 speed;
    
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(speed * Time.deltaTime, Space.Self);
    }

    private void OnTriggerEnter(Collider other)
    {
        Debug.Log("* 发生了碰撞,other=" + other.name);
    }
}

在这里插入图片描述

  1. 物理引擎 只负责探测 ( Trigger ) ,不会阻止物体或者反弹
  2. 物体引擎 计算的是 Collider 之间的碰撞,和物体自身形状无关
  3. 当检测到碰撞时,会调用 当前节点脚本中的 OnTriggerEnter 消息

(三)碰撞体的编辑

碰撞体 Collider 的形状,规定了碰撞的边界。其形状是可以编辑的:

  • Box Collider 盒形:
    Center 中心位置,相当于物体的轴心点;Size 长宽高。点 Edit Collider,可以直接编辑绿色框
  • Sphere Collider 球形:
    Center 中心位置,相当于物体的轴心点;Radius 半径大小。点 Edit Collider,可以直接编辑绿色框

练习:添加子弹物体

  1. 检查原先有没有碰撞体,如果有,则先移除
  2. 根据体型,选择合适形状的碰撞体:此处,添加一个 Box Collider
  3. 编辑碰撞体,调整边界:一般无需调整,Unity会自动创建合适的尺寸
    在这里插入图片描述

碰撞体的范围,不用太精确,大致覆盖物体即可

(四)练习:击毁目标

练习:发射一发子弹,击毁目标

  1. 运动学刚体设置 Rigidbody | Is Kinematic
  2. 触发器模式设置 Collider | Is Trigger
  3. 消息函数 void OnTriggerEnter()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletLogicDistruct : MonoBehaviour
{
    public Vector3 speed;
    
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        this.transform.Translate(speed * Time.deltaTime, Space.Self);
    }

    private void OnTriggerEnter(Collider other)
    {
        if(other.name.Equals("目标"))
        {
            Debug.Log("* 子弹发生碰撞,other=" + other.name);
            Object.Destroy(other.gameObject);
            Object.Destroy(this.gameObject);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MainLogic : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Application.targetFrameRate = 60;
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

在这里插入图片描述

碰撞的双方,只需一方设置为运动学刚体即可


五、游戏项目实战 — 射击小游戏

制作一个射击游戏
海空背景、玩家、子弹(无限数量)、怪兽(蛇皮走位,无限数量)、子弹特效(爆炸特效)、背景音乐

(1) 添加两个角色(预制体)玩家、敌人

在这里插入图片描述

(2)天空盒 Skybox,即游戏的背景
Windows | Rendering | Lighting,光照设置 —> Environment | Skybox Material,天空盒材质
在这里插入图片描述
在这里插入图片描述

调整摄像头视角
在这里插入图片描述
在这里插入图片描述

(3) 子弹和碰撞
添加子弹、子弹脚本、碰撞检测
在这里插入图片描述
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LiBulletLogic : MonoBehaviour
{
    [Tooltip("子弹飞行速度")]
    public float speed = 1;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, 0, speed * Time.deltaTime, Space.Self);
    }
}

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LiBulletLogic : MonoBehaviour
{
    [Tooltip("子弹飞行速度")]
    public float speed = 1;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, 0, speed * Time.deltaTime, Space.Self);
    }

    private void OnTriggerEnter(Collider other)
    {
        Debug.Log("* 子弹碰撞,other=" + other.name);
    }
}

  1. 怪兽是一个空物体,其碰撞体要手动编辑
    在这里插入图片描述

在这里插入图片描述

  1. 主控脚本中帧率的设置(让CPU压力小一点)
    在这里插入图片描述
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LiMainLogic : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Application.targetFrameRate = 60;
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

(4)连续发射

1. 子弹

  • 增加自毁时间 lifetime
  • 把子弹做成 prefab
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LiBulletLogic : MonoBehaviour
{
    [Tooltip("子弹飞行速度")]
    public float speed = 1;
    [Tooltip("子弹生命时长")]
    public float lifetime = 3;

    // Start is called before the first frame update
    void Start()
    {
        Invoke("SelfDestroy", lifetime);
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, 0, speed * Time.deltaTime, Space.Self);
    }

    private void OnTriggerEnter(Collider other)
    {
        Debug.Log("* 子弹碰撞,other=" + other.name);

        if (!other.name.StartsWith("怪兽")) return;

        Destroy(this.gameObject);
        Destroy(other.gameObject);
    }

    private void SelfDestroy()
    {
        Object.Destroy(this.gameObject);
    }
}

在这里插入图片描述

2. 玩家

  • 定义发射点 fire point
  • 定义子弹目录 bullet folder
  • 使用定时器,子弹连发

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LiPlayerLogic : MonoBehaviour
{
    [Tooltip("子弹节点的预制体")]
    public GameObject bulletPrefab;
    [Tooltip("子弹节点的父节点")]
    public Transform bulletFolder;
    [Tooltip("子弹出生点")]
    public Transform firePoint;
    [Tooltip("开火间隔")]
    public float fireInterval = 0.5f;
    
    // Start is called before the first frame update
    void Start()
    {
        InvokeRepeating("Fire", fireInterval, fireInterval);
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void Fire()
    {
        // 实例化一个子弹节点
        GameObject node = Instantiate(bulletPrefab, bulletFolder);
        // 调整子弹发射点位置
        node.transform.position = firePoint.position;
    }
}

(5)按键控制:添加按键控制,让玩家左右移动

using System.Collections;
using System.Collections.Generic;
using System.Data.SqlTypes;
using UnityEngine;

public class LiPlayerLogic : MonoBehaviour
{
    [Tooltip("子弹节点的预制体")]
    public GameObject bulletPrefab;
    [Tooltip("子弹节点的父节点")]
    public Transform bulletFolder;
    [Tooltip("子弹出生点")]
    public Transform firePoint;
    [Tooltip("开火间隔")]
    public float fireInterval = 0.5f;
    [Tooltip("平移速度")]
    public float moveSpeed = 0.3f;
    
    // Start is called before the first frame update
    void Start()
    {
        InvokeRepeating("Fire", fireInterval, fireInterval);
    }

    // Update is called once per frame
    void Update()
    {
        float dx = 0;

        if (Input.GetKey(KeyCode.A))
            dx = -moveSpeed;
        if (Input.GetKey(KeyCode.D))
            dx = moveSpeed;

        this.transform.Translate(dx, 0, 0, Space.Self);
    }

    private void Fire()
    {
        // 实例化一个子弹节点
        GameObject node = Instantiate(bulletPrefab, bulletFolder);
        // 把子弹移动到出生点位置
        node.transform.position = firePoint.position;
    }
}

在这里插入图片描述

(6)怪兽控制:给怪兽添加脚本 EnemyLogic

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LiEnemyLogic : MonoBehaviour
{
    [Tooltip("前进速度")]
    public float zSpeed = 10;
    // 横移速度
    float xSpeed = 0;
    
    // Start is called before the first frame update
    void Start()
    {
        // 每秒改变一次横移速度
        InvokeRepeating("SnakeMove", 1f, 1f);
    }

    // Update is called once per frame
    void Update()
    {
        float dz = zSpeed * Time.deltaTime;
        float dx = xSpeed * Time.deltaTime;

        this.transform.Translate(dx, 0 , dz, Space.Self);
    }

    // 蛇皮走位
    void SnakeMove()
    {
        // 4 种速度选项
        float[] options = { -10, -5, 5, 10 };
        int sel = Random.Range(0, options.Length);
        xSpeed = options[sel];
    }
}

(7)怪兽生成器:定时生成怪兽(实质还是预制体创建实例的技术)

更新预制体的资源,隐藏怪兽
在这里插入图片描述
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LiEnemyCreator : MonoBehaviour
{
    public GameObject enemyPrefab;

    public float interval = 1;

    // Start is called before the first frame update
    void Start()
    {
        InvokeRepeating("CreateEnemy", 0.1f, interval);
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void CreateEnemy()
    {
        GameObject node = Instantiate(enemyPrefab, this.transform);
        node.transform.position = this.transform.position;
        // 把怪兽的投头转过来
        node.transform.localEulerAngles = new Vector3(0, 180, 0);
        // 出生之后,不要在原点呆着,而是左右偏一个位置,防止被立即击毙
        float dx = Random.Range(-30, 30);
        node.transform.Translate(dx, 0, 0, Space.Self);
    }
}

在这里插入图片描述
(8)子弹特效:添加子弹特效,粒子特效 Particle System

注意,修改之后要应用 Prefab

在这里插入图片描述

(9)爆炸特效 :在击中目标时,创建特效节点
在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LiBulletLogic : MonoBehaviour
{
    [Tooltip("子弹飞行速度")]
    public float speed = 25;
    [Tooltip("子弹生命时长")]
    public float lifetime = 3;
    [Tooltip("爆炸粒子特效的Prefab")]
    public GameObject explosionEffect;

    // Start is called before the first frame update
    void Start()
    {
        Invoke("SelfDestroy", lifetime);
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(0, 0, speed * Time.deltaTime, Space.Self);
    }

    private void OnTriggerEnter(Collider other)
    {
        Debug.Log("* 子弹碰撞,other=" + other.name);

        if (!other.name.StartsWith("怪兽")) return;

        Destroy(this.gameObject);
        Destroy(other.gameObject);

        // 创建一个粒子特效,表现爆炸的效果
        GameObject effectNode = Instantiate(explosionEffect, null);
        effectNode.transform.position = this.transform.position;
        // 当粒子特效播放完,会自己销毁
    }

    private void SelfDestroy()
    {
        Object.Destroy(this.gameObject);
    }
}

在这里插入图片描述

最后再设置一下音乐
在这里插入图片描述



网站公告

今日签到

点亮在社区的每一天
去签到