体素爆炸
基本思路:
离线把怪物死亡那帧的模型数据生成体素信息保存起来
在死亡的时候,隐藏原本的模型,用体素数据生成体素
低端机型用特效数据做爆炸,高端机型用真实物理
体素数量可以在生成时调整(低画质之初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 : MonoBehaviour
6
{
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 initialization
27
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 frame
79
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
else
100
{
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
else
139
{
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