基本思路:
离线把怪物死亡那帧的模型数据生成体素信息保存起来
在死亡的时候,隐藏原本的模型,用体素数据生成体素
低端机型用特效数据做爆炸,高端机型用真实物理
体素数量可以在生成时调整(低画质之初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>());
}
}
}
x
182
1
using System.Collections;2
using System.Collections.Generic;3
using UnityEngine;4
5
public class Bomb : MonoBehaviour6
{7
public bool autoBomb = false;8
public int cullPower = 0;9
public float showVoxelTime = 0.1f;10
public GameObject modelObj;11
public Transform voxelParent;12
public ParticleSystem bombPs;13
public bool usePhysics = false;14
public float forcePower = 10;15
public GameObject[] voxelObj;16
17
float delTime;18
float showTime;19
float bombTime;20
bool isShow;21
bool isBomb;22
bool isDoUsePhysics;23
ParticleSystem.Particle[] m_Particles;24
List<Vector3> oriPosition;25
26
// Use this for initialization27
void Awake()28
{29
if (autoBomb)30
{31
showTime = Time.time + 1;32
bombTime = showTime + showVoxelTime;33
isShow = false;34
isBomb = false;35
isDoUsePhysics = false;36
}37
38
voxelParent.gameObject.SetActive(false);39
bombPs.gameObject.SetActive(false);40
41
oriPosition = new List<Vector3>();42
43
//剔除44
if (cullPower > 1)45
{46
int nextCull = 0;47
for (int i = voxelParent.childCount -1; i >= 0; --i)48
{49
if (nextCull != 0)50
{51
DestroyImmediate(voxelParent.GetChild(i).gameObject);52
}53
nextCull = (++nextCull) % cullPower;54
}55
}56
57
//体素生成58
if (voxelObj != null && voxelObj.Length > 0)59
{60
for (int i = 0; i < voxelParent.childCount; ++i)61
{62
Transform vox = voxelParent.GetChild(i);63
GameObject randomVox = voxelObj[Random.Range(0, voxelObj.Length)];64
GameObject voxObj = Instantiate(randomVox);65
if (!usePhysics)66
{67
Destroy(voxObj.GetComponent<BoxCollider>());68
Destroy(voxObj.GetComponent<Rigidbody>());69
}70
71
voxObj.transform.parent = vox;72
voxObj.transform.localPosition = Vector3.zero;73
voxObj.transform.localScale = Vector3.one;74
}75
}76
}77
78
// Update is called once per frame79
void Update()80
{81
if (!autoBomb)82
return;83
84
if (!isShow)85
{86
if (Time.time >= showTime)87
{88
delTime = Time.time + 3;89
isShow = true;90
if (modelObj != null) modelObj.SetActive(false);91
voxelParent.gameObject.SetActive(true);92
93
for (int i = 0; i < voxelParent.childCount; ++i)94
{95
Transform vox = voxelParent.GetChild(i);96
oriPosition.Add(vox.position);97
}98
}99
else100
{101
return;102
}103
}104
105
if (Time.time >= delTime)106
{107
Destroy(gameObject);108
}109
110
if (Time.time < bombTime)111
return;112
113
if (!isBomb)114
{115
isBomb = true;116
117
short nVoxelCount = (short)voxelParent.childCount;118
m_Particles = new ParticleSystem.Particle[nVoxelCount];119
bombPs.emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0.0f, nVoxelCount, nVoxelCount) });120
bombPs.gameObject.SetActive(true);121
return;122
}123
124
if (!usePhysics)125
{126
Quaternion qua = bombPs.transform.rotation;127
int numParticlesAlive = bombPs.GetParticles(m_Particles);128
for (int i = 0; i < voxelParent.childCount; ++i)129
{130
if (i >= numParticlesAlive)131
return;132
133
Transform newTrans = voxelParent.GetChild(i);134
newTrans.forward = qua * m_Particles[i].rotation3D;135
newTrans.position = oriPosition[i] + qua * m_Particles[i].position;136
}137
}138
else139
{140
if (!isDoUsePhysics)141
{142
isDoUsePhysics = true;143
Quaternion qua = bombPs.transform.rotation;144
int numParticlesAlive = bombPs.GetParticles(m_Particles);145
for (int i = 0; i < voxelParent.childCount; ++i)146
{147
if (i >= numParticlesAlive)148
return;149
150
Vector3 force = qua * m_Particles[i].velocity;151
force *= forcePower;152
153
Transform newTrans = voxelParent.GetChild(i);154
var rigi = newTrans.GetComponentInChildren<Rigidbody>();155
rigi.AddForce(force);156
}157
158
bombPs.gameObject.SetActive(false);159
}160
}161
}162
163
[ContextMenu("DoBomb")]164
public void DoBomb()165
{166
autoBomb = true;167
showTime = Time.time;168
bombTime = showTime + showVoxelTime;169
}170
171
[ContextMenu("DelAllRender")]172
public void DelAllRender()173
{174
for (int i = 0; i < voxelParent.childCount; ++i)175
{176
GameObject obj = voxelParent.GetChild(i).gameObject;177
DestroyImmediate(obj.GetComponent<MeshFilter>());178
DestroyImmediate(obj.GetComponent<MeshRenderer>());179
}180
}181
}182