体素爆炸

Posted Hichy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了体素爆炸相关的知识,希望对你有一定的参考价值。

基本思路:
    离线把怪物死亡那帧的模型数据生成体素信息保存起来
    在死亡的时候,隐藏原本的模型,用体素数据生成体素
    低端机型用特效数据做爆炸,高端机型用真实物理
    体素数量可以在生成时调整(低画质之初20分之一的体素)

结果:
    看不太出来是从模型样式开始爆炸的,最后使用了纯特效实现

演示效果图

体素生成代码使用地图体素信息导出工具临时改的,最终没有用这个方案就没有细化

爆炸测试脚本记录
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bomb : MonoBehaviour
{
	public bool autoBomb = false;
	public int cullPower = 0;
	public float showVoxelTime = 0.1f;
	public GameObject modelObj;
	public Transform voxelParent;
	public ParticleSystem bombPs;
	public bool usePhysics = false;
	public float forcePower = 10;
	public GameObject[] voxelObj;

	float delTime;
	float showTime;
	float bombTime;
	bool isShow;
	bool isBomb;
	bool isDoUsePhysics;
	ParticleSystem.Particle[] m_Particles;
	List<Vector3> oriPosition;

	// Use this for initialization
	void Awake()
	{
		if (autoBomb)
		{
			showTime = Time.time + 1;
			bombTime = showTime + showVoxelTime;
			isShow = false;
			isBomb = false;
			isDoUsePhysics = false;
		}

		voxelParent.gameObject.SetActive(false);
		bombPs.gameObject.SetActive(false);

		oriPosition = new List<Vector3>();

		//剔除
		if (cullPower > 1)
		{
			int nextCull = 0;
			for (int i = voxelParent.childCount -1; i >= 0; --i)
			{
				if (nextCull != 0)
				{
					DestroyImmediate(voxelParent.GetChild(i).gameObject);
				}
				nextCull = (++nextCull) % cullPower;
			}
		}

		//体素生成
		if (voxelObj != null && voxelObj.Length > 0)
		{
			for (int i = 0; i < voxelParent.childCount; ++i)
			{
				Transform vox = voxelParent.GetChild(i);
				GameObject randomVox = voxelObj[Random.Range(0, voxelObj.Length)];
				GameObject voxObj = Instantiate(randomVox);
				if (!usePhysics)
				{
					Destroy(voxObj.GetComponent<BoxCollider>());
					Destroy(voxObj.GetComponent<Rigidbody>());
				}

				voxObj.transform.parent = vox;
				voxObj.transform.localPosition = Vector3.zero;
				voxObj.transform.localScale = Vector3.one;
			}
		}
	}

	// Update is called once per frame
	void Update()
	{
		if (!autoBomb)
			return;

		if (!isShow)
		{
			if (Time.time >= showTime)
			{
				delTime = Time.time + 3;
				isShow = true;
				if (modelObj != null) modelObj.SetActive(false);
				voxelParent.gameObject.SetActive(true);

				for (int i = 0; i < voxelParent.childCount; ++i)
				{
					Transform vox = voxelParent.GetChild(i);
					oriPosition.Add(vox.position);
				}
			}
			else
			{
				return;
			}
		}

		if (Time.time >= delTime)
		{
			Destroy(gameObject);
		}

		if (Time.time < bombTime)
			return;

		if (!isBomb)
		{
			isBomb = true;

			short nVoxelCount = (short)voxelParent.childCount;
			m_Particles = new ParticleSystem.Particle[nVoxelCount];
			bombPs.emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0.0f, nVoxelCount, nVoxelCount) });
			bombPs.gameObject.SetActive(true);
			return;
		}

		if (!usePhysics)
		{
			Quaternion qua = bombPs.transform.rotation;
			int numParticlesAlive = bombPs.GetParticles(m_Particles);
			for (int i = 0; i < voxelParent.childCount; ++i)
			{
				if (i >= numParticlesAlive)
					return;

				Transform newTrans = voxelParent.GetChild(i);
				newTrans.forward = qua * m_Particles[i].rotation3D;
				newTrans.position = oriPosition[i] + qua * m_Particles[i].position;
			}
		}
		else
		{
			if (!isDoUsePhysics)
			{
				isDoUsePhysics = true;
				Quaternion qua = bombPs.transform.rotation;
				int numParticlesAlive = bombPs.GetParticles(m_Particles);
				for (int i = 0; i < voxelParent.childCount; ++i)
				{
					if (i >= numParticlesAlive)
						return;

					Vector3 force = qua * m_Particles[i].velocity;
					force *= forcePower;

					Transform newTrans = voxelParent.GetChild(i);
					var rigi = newTrans.GetComponentInChildren<Rigidbody>();
					rigi.AddForce(force);
				}

				bombPs.gameObject.SetActive(false);
			}
		}
	}

	[ContextMenu("DoBomb")]
	public void DoBomb()
	{
		autoBomb = true;
		showTime = Time.time;
		bombTime = showTime + showVoxelTime;
	}

	[ContextMenu("DelAllRender")]
	public void DelAllRender()
	{
		for (int i = 0; i < voxelParent.childCount; ++i)
		{
			GameObject obj = voxelParent.GetChild(i).gameObject;
			DestroyImmediate(obj.GetComponent<MeshFilter>());
			DestroyImmediate(obj.GetComponent<MeshRenderer>());
		}
	}
}