一、简单的爆炸

  • 使用场景
    零部件的简单爆炸展示
  • 复杂爆炸,比如物体炸开后,破碎的物体沿曲线运动,而且有动力学效果,则需要更复杂的实现,本例不作讨论。

二、实现的过程

  • 1、爆炸过程
    从初始位置 移动到 结束位置(position和ratation做lerp插值运动)
  • 2、收拢过程
    从结束位置 移动到 初始位置(position和ratation做lerp插值运动)

中间所有的物体都是在两点之间做匀速直线运动

  • 3、爆炸前和爆炸后的方位信息记录

物体方位信息表

unity 爆炸力 unity爆点_vr


自定义的类-【物体和方位信息】

/// <summary>
    /// 物体和方位信息
    /// 各个部件,在爆炸前和爆炸后的位置和方向信息
    /// </summary>
    [Serializable]
    public class goPositions{
        [Header("物体")]
        [SerializeField]
        public GameObject go;

        [Header("爆炸前的位置")]
        [SerializeField]
        public Vector3 positionStart;

        [Header("爆炸前的方向")]
        [SerializeField]
        public Quaternion rotationStart;

        [Header("爆炸后的位置")]
        [SerializeField]
        public Vector3 positionEnd;

        [Header("爆炸后的方向")]
        [SerializeField]
        public Quaternion rotationEnd;
    }
  • 4、爆炸的过程——插值或者pingpong
// Update is called once per frame
    void Update()
    {
        //测试代码==================================begin
        //if (Input.GetKeyDown(KeyCode.Alpha1))
        //{
        //    Debug.Log("111");
        //    SetToStartTransform();            
        //}

        //if (Input.GetKeyDown(KeyCode.Alpha2))
        //{
        //    Debug.Log("222");
        //    SetToEndTransform();
        //}
        //测试代码==================================end

        //更新物体的位置和方向——pingpong效果
        stepValue = Mathf.PingPong(Time.time, time) / time;
        GoPositions.ForEach(x =>
        {
            x.go.transform.position = Vector3.Lerp(x.positionStart, x.positionEnd, stepValue);
            x.go.transform.rotation = Quaternion.Lerp(x.rotationStart, x.rotationEnd, stepValue);
        });
    }

三、代码清单

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

/// <summary>
/// 一个组合的物体爆炸和收拢
/// 爆炸:从初始位置 移动到 结束位置(position和ratation做lerp插值运动)
/// 收拢:从结束位置 移动到 初始位置(position和ratation做lerp插值运动)
/// 
/// 编辑器状态下的功能:
/// 没有爆炸前:    右键菜单《初始化【部件和开始方位】》,记录各个部件的原始方向和位置
/// 拖拽爆炸位置后:右键菜单《初始化【结束方位】》      ,记录各个部件的结束方向和位置
/// 
/// 说明:物体命名规则,凡是爆炸的物体(要炸开和合拢的物体),命名包含"部件"两字
/// </summary>
public class baozha : MonoBehaviour
{
    /// <summary>
    /// 物体和方位信息
    /// 各个部件,在爆炸前和爆炸后的位置和方向信息
    /// </summary>
    [Serializable]
    public class goPositions{
        [Header("物体")]
        [SerializeField]
        public GameObject go;

        [Header("爆炸前的位置")]
        [SerializeField]
        public Vector3 positionStart;

        [Header("爆炸前的方向")]
        [SerializeField]
        public Quaternion rotationStart;

        [Header("爆炸后的位置")]
        [SerializeField]
        public Vector3 positionEnd;

        [Header("爆炸后的方向")]
        [SerializeField]
        public Quaternion rotationEnd;
    }

    [Header("部件的根物体")]
    [SerializeField]
    public GameObject root;

    [Header("部件以及方位信息列表")]
    [SerializeField]
    public List<goPositions> GoPositions = new List<goPositions>();

    [Header("散开的时间")]
    [SerializeField]
    public float time;

    /// <summary>
    /// pingpong效果的进度条值
    /// </summary>
    private float stepValue;

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

    // Update is called once per frame
    void Update()
    {
        //测试代码==================================begin
        //if (Input.GetKeyDown(KeyCode.Alpha1))
        //{
        //    Debug.Log("111");
        //    SetToStartTransform();            
        //}

        //if (Input.GetKeyDown(KeyCode.Alpha2))
        //{
        //    Debug.Log("222");
        //    SetToEndTransform();
        //}
        //测试代码==================================end

        //更新物体的位置和方向——pingpong效果
        stepValue = Mathf.PingPong(Time.time, time) / time;
        GoPositions.ForEach(x =>
        {
            x.go.transform.position = Vector3.Lerp(x.positionStart, x.positionEnd, stepValue);
            x.go.transform.rotation = Quaternion.Lerp(x.rotationStart, x.rotationEnd, stepValue);
        });
    }

    /// <summary>
    /// 物体摆放到初始位置
    /// </summary>
    void SetToStartTransform()
    {
        GoPositions.ForEach(
            x=> 
            {
                x.go.transform.position = x.positionStart;
                x.go.transform.rotation = x.rotationStart;
            });
    }

    void SetToEndTransform()
    {
        GoPositions.ForEach(
            x =>
            {
                x.go.transform.position = x.positionEnd;
                x.go.transform.rotation = x.rotationEnd;
            });
    }


#if UNITY_EDITOR // Editor的非running状态使用
    [ContextMenu("记录【部件和开始方位】")]
#endif
    public void InitTransformStart()
    {
        GoPositions.Clear();

        root.transform.GetComponentInChildren<Transform>().Cast<Transform>().ToList()
            .ForEach(item =>
            {
                if (item.name.Contains("部件")) //
                {                    
                    goPositions gp = new goPositions();
                    gp.go = item.gameObject;
                    gp.positionStart = item.gameObject.transform.position;
                    gp.rotationStart = item.gameObject.transform.rotation;
                    GoPositions.Add(gp);
                }
                else
                {
                    //
                }
            });
        Debug.Log("初始方位记录完毕");
    }


#if UNITY_EDITOR // Editor的非running状态使用
    [ContextMenu("记录【结束方位】")]
#endif
    public void InitTransformEnd()
    {
        var allGos = root.transform.GetComponentInChildren<Transform>().Cast<Transform>().ToList();

        GoPositions.ForEach(x=> 
        {
            x.positionEnd = allGos.Where(go => go.gameObject.name == x.go.name).ToList()[0].position;
            x.rotationEnd = allGos.Where(go => go.gameObject.name == x.go.name).ToList()[0].rotation;

        });
        Debug.Log("结束方位记录完毕");
    }
}