Skip to content

Commit d499ec4

Browse files
sofarkwolekr
authored andcommittedMay 28, 2016
Particles: Add option to remove particles on collision
Adds the particle option `collision_removal = bool` Some particles are hard to use right now since they either go through solid blocks (without collision detection), and with collision detection enabled they (e.g. raindrops) would just stop dead on the floor and sit there until they expire, or worse, scrape along a wall or ceiling. We can solve the problem by adding a boolean flag that tells the particle to be removed if it ever collides with something. This will make it easier to add rain that doesn't fall through your roof or stick on the top of it. Or clouds and smoke that don't go through trees. Particles that collide with this flag are marked expired unconditionally, causing them to be treated like normal expired particles and cleaned up normally. Documentation is adjusted accordingly. An added bonus of this patch is that particles can potentially collide many times with nodes, and this reduces the amount of collisions to 1 (max), which may end up reducing particle load on the client.
1 parent 62d15ac commit d499ec4

File tree

9 files changed

+84
-32
lines changed

9 files changed

+84
-32
lines changed
 

‎doc/lua_api.txt

+6
Original file line numberDiff line numberDiff line change
@@ -3885,6 +3885,9 @@ Definition tables
38853885
size = 1,
38863886
collisiondetection = false,
38873887
-- ^ collisiondetection: if true collides with physical objects
3888+
collision_removal = false,
3889+
-- ^ collision_removal: if true then particle is removed when it collides,
3890+
-- ^ requires collisiondetection = true to have any effect
38883891
vertical = false,
38893892
-- ^ vertical: if true faces player using y axis only
38903893
texture = "image.png",
@@ -3914,6 +3917,9 @@ Definition tables
39143917
-- ^ minsize/maxsize, minexptime/maxexptime (expirationtime)
39153918
collisiondetection = false,
39163919
-- ^ collisiondetection: if true uses collision detection
3920+
collision_removal = false,
3921+
-- ^ collision_removal: if true then particle is removed when it collides,
3922+
-- ^ requires collisiondetection = true to have any effect
39173923
vertical = false,
39183924
-- ^ vertical: if true faces player using y axis only
39193925
texture = "image.png",

‎src/client.h

+2
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ struct ClientEvent
182182
f32 expirationtime;
183183
f32 size;
184184
bool collisiondetection;
185+
bool collision_removal;
185186
bool vertical;
186187
std::string *texture;
187188
} spawn_particle;
@@ -199,6 +200,7 @@ struct ClientEvent
199200
f32 minsize;
200201
f32 maxsize;
201202
bool collisiondetection;
203+
bool collision_removal;
202204
bool vertical;
203205
std::string *texture;
204206
u32 id;

‎src/network/clientpackethandler.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -898,8 +898,10 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
898898
bool collisiondetection = readU8(is);
899899
std::string texture = deSerializeLongString(is);
900900
bool vertical = false;
901+
bool collision_removal = false;
901902
try {
902903
vertical = readU8(is);
904+
collision_removal = readU8(is);
903905
} catch (...) {}
904906

905907
ClientEvent event;
@@ -910,6 +912,7 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
910912
event.spawn_particle.expirationtime = expirationtime;
911913
event.spawn_particle.size = size;
912914
event.spawn_particle.collisiondetection = collisiondetection;
915+
event.spawn_particle.collision_removal = collision_removal;
913916
event.spawn_particle.vertical = vertical;
914917
event.spawn_particle.texture = new std::string(texture);
915918

@@ -942,8 +945,11 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
942945
*pkt >> id;
943946

944947
bool vertical = false;
948+
bool collision_removal = false;
945949
try {
946950
*pkt >> vertical;
951+
*pkt >> collision_removal;
952+
947953
} catch (...) {}
948954

949955
ClientEvent event;
@@ -961,6 +967,7 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
961967
event.add_particlespawner.minsize = minsize;
962968
event.add_particlespawner.maxsize = maxsize;
963969
event.add_particlespawner.collisiondetection = collisiondetection;
970+
event.add_particlespawner.collision_removal = collision_removal;
964971
event.add_particlespawner.vertical = vertical;
965972
event.add_particlespawner.texture = new std::string(texture);
966973
event.add_particlespawner.id = id;

‎src/network/networkprotocol.h

+2
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ enum ToClientCommand
474474
u8 bool vertical
475475
u32 len
476476
u8[len] texture
477+
u8 collision_removal
477478
*/
478479

479480
TOCLIENT_ADD_PARTICLESPAWNER = 0x47,
@@ -495,6 +496,7 @@ enum ToClientCommand
495496
u32 len
496497
u8[len] texture
497498
u32 id
499+
u8 collision_removal
498500
*/
499501

500502
TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY = 0x48,

‎src/particles.cpp

+24-15
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Particle::Particle(
5454
float expirationtime,
5555
float size,
5656
bool collisiondetection,
57+
bool collision_removal,
5758
bool vertical,
5859
video::ITexture *texture,
5960
v2f texpos,
@@ -85,6 +86,7 @@ Particle::Particle(
8586
m_player = player;
8687
m_size = size;
8788
m_collisiondetection = collisiondetection;
89+
m_collision_removal = collision_removal;
8890
m_vertical = vertical;
8991

9092
// Irrlicht stuff
@@ -126,20 +128,21 @@ void Particle::render()
126128
void Particle::step(float dtime)
127129
{
128130
m_time += dtime;
129-
if (m_collisiondetection)
130-
{
131+
if (m_collisiondetection) {
131132
aabb3f box = m_collisionbox;
132-
v3f p_pos = m_pos*BS;
133-
v3f p_velocity = m_velocity*BS;
134-
collisionMoveSimple(m_env, m_gamedef,
135-
BS*0.5, box,
136-
0, dtime,
137-
&p_pos, &p_velocity, m_acceleration * BS);
138-
m_pos = p_pos/BS;
139-
m_velocity = p_velocity/BS;
140-
}
141-
else
142-
{
133+
v3f p_pos = m_pos * BS;
134+
v3f p_velocity = m_velocity * BS;
135+
collisionMoveResult r = collisionMoveSimple(m_env,
136+
m_gamedef, BS * 0.5, box, 0, dtime, &p_pos,
137+
&p_velocity, m_acceleration * BS);
138+
if (m_collision_removal && r.collides) {
139+
// force expiration of the particle
140+
m_expiration = -1.0;
141+
} else {
142+
m_pos = p_pos / BS;
143+
m_velocity = p_velocity / BS;
144+
}
145+
} else {
143146
m_velocity += m_acceleration * dtime;
144147
m_pos += m_velocity * dtime;
145148
}
@@ -210,8 +213,8 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
210213
u16 amount, float time,
211214
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
212215
float minexptime, float maxexptime, float minsize, float maxsize,
213-
bool collisiondetection, bool vertical, video::ITexture *texture, u32 id,
214-
ParticleManager *p_manager) :
216+
bool collisiondetection, bool collision_removal, bool vertical,
217+
video::ITexture *texture, u32 id, ParticleManager *p_manager) :
215218
m_particlemanager(p_manager)
216219
{
217220
m_gamedef = gamedef;
@@ -230,6 +233,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
230233
m_minsize = minsize;
231234
m_maxsize = maxsize;
232235
m_collisiondetection = collisiondetection;
236+
m_collision_removal = collision_removal;
233237
m_vertical = vertical;
234238
m_texture = texture;
235239
m_time = 0;
@@ -277,6 +281,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
277281
exptime,
278282
size,
279283
m_collisiondetection,
284+
m_collision_removal,
280285
m_vertical,
281286
m_texture,
282287
v2f(0.0, 0.0),
@@ -317,6 +322,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
317322
exptime,
318323
size,
319324
m_collisiondetection,
325+
m_collision_removal,
320326
m_vertical,
321327
m_texture,
322328
v2f(0.0, 0.0),
@@ -446,6 +452,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
446452
event->add_particlespawner.minsize,
447453
event->add_particlespawner.maxsize,
448454
event->add_particlespawner.collisiondetection,
455+
event->add_particlespawner.collision_removal,
449456
event->add_particlespawner.vertical,
450457
texture,
451458
event->add_particlespawner.id,
@@ -480,6 +487,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
480487
event->spawn_particle.expirationtime,
481488
event->spawn_particle.size,
482489
event->spawn_particle.collisiondetection,
490+
event->spawn_particle.collision_removal,
483491
event->spawn_particle.vertical,
484492
texture,
485493
v2f(0.0, 0.0),
@@ -555,6 +563,7 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
555563
visual_size,
556564
true,
557565
false,
566+
false,
558567
texture,
559568
texpos,
560569
texsize);

‎src/particles.h

+5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
3030

3131
struct ClientEvent;
3232
class ParticleManager;
33+
class ClientEnvironment;
3334

3435
class Particle : public scene::ISceneNode
3536
{
@@ -45,6 +46,7 @@ class Particle : public scene::ISceneNode
4546
float expirationtime,
4647
float size,
4748
bool collisiondetection,
49+
bool collision_removal,
4850
bool vertical,
4951
video::ITexture *texture,
5052
v2f texpos,
@@ -97,6 +99,7 @@ class Particle : public scene::ISceneNode
9799
float m_size;
98100
u8 m_light;
99101
bool m_collisiondetection;
102+
bool m_collision_removal;
100103
bool m_vertical;
101104
v3s16 m_camera_offset;
102105
};
@@ -115,6 +118,7 @@ class ParticleSpawner
115118
float minexptime, float maxexptime,
116119
float minsize, float maxsize,
117120
bool collisiondetection,
121+
bool collision_removal,
118122
bool vertical,
119123
video::ITexture *texture,
120124
u32 id,
@@ -148,6 +152,7 @@ class ParticleSpawner
148152
video::ITexture *m_texture;
149153
std::vector<float> m_spawntimes;
150154
bool m_collisiondetection;
155+
bool m_collision_removal;
151156
bool m_vertical;
152157

153158
};

‎src/script/lua_api/l_particles.cpp

+17-7
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2121
#include "lua_api/l_internal.h"
2222
#include "common/c_converter.h"
2323
#include "server.h"
24+
#include "particles.h"
2425

2526
// add_particle({pos=, velocity=, acceleration=, expirationtime=,
26-
// size=, collisiondetection=, vertical=, texture=, player=})
27+
// size=, collisiondetection=, collision_removal=, vertical=,
28+
// texture=, player=})
2729
// pos/velocity/acceleration = {x=num, y=num, z=num}
2830
// expirationtime = num (seconds)
2931
// size = num
3032
// collisiondetection = bool
33+
// collision_removal = bool
3134
// vertical = bool
3235
// texture = e.g."default_wood.png"
3336
int ModApiParticles::l_add_particle(lua_State *L)
@@ -41,8 +44,8 @@ int ModApiParticles::l_add_particle(lua_State *L)
4144
float expirationtime, size;
4245
expirationtime = size = 1;
4346

44-
bool collisiondetection, vertical;
45-
collisiondetection = vertical = false;
47+
bool collisiondetection, vertical, collision_removal;
48+
collisiondetection = vertical = collision_removal = false;
4649

4750
std::string texture = "";
4851
std::string playername = "";
@@ -94,12 +97,14 @@ int ModApiParticles::l_add_particle(lua_State *L)
9497
size = getfloatfield_default(L, 1, "size", 1);
9598
collisiondetection = getboolfield_default(L, 1,
9699
"collisiondetection", collisiondetection);
100+
collision_removal = getboolfield_default(L, 1,
101+
"collision_removal", collision_removal);
97102
vertical = getboolfield_default(L, 1, "vertical", vertical);
98103
texture = getstringfield_default(L, 1, "texture", "");
99104
playername = getstringfield_default(L, 1, "playername", "");
100105
}
101-
getServer(L)->spawnParticle(playername, pos, vel, acc,
102-
expirationtime, size, collisiondetection, vertical, texture);
106+
getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size,
107+
collisiondetection, collision_removal, vertical, texture);
103108
return 1;
104109
}
105110

@@ -110,13 +115,15 @@ int ModApiParticles::l_add_particle(lua_State *L)
110115
// minexptime=, maxexptime=,
111116
// minsize=, maxsize=,
112117
// collisiondetection=,
118+
// collision_removal=,
113119
// vertical=,
114120
// texture=,
115121
// player=})
116122
// minpos/maxpos/minvel/maxvel/minacc/maxacc = {x=num, y=num, z=num}
117123
// minexptime/maxexptime = num (seconds)
118124
// minsize/maxsize = num
119125
// collisiondetection = bool
126+
// collision_removal = bool
120127
// vertical = bool
121128
// texture = e.g."default_wood.png"
122129
int ModApiParticles::l_add_particlespawner(lua_State *L)
@@ -129,8 +136,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
129136
minpos= maxpos= minvel= maxvel= minacc= maxacc= v3f(0, 0, 0);
130137
float time, minexptime, maxexptime, minsize, maxsize;
131138
time= minexptime= maxexptime= minsize= maxsize= 1;
132-
bool collisiondetection, vertical;
133-
collisiondetection= vertical= false;
139+
bool collisiondetection, vertical, collision_removal;
140+
collisiondetection = vertical = collision_removal = false;
134141
std::string texture = "";
135142
std::string playername = "";
136143

@@ -189,6 +196,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
189196
maxsize = getfloatfield_default(L, 1, "maxsize", maxsize);
190197
collisiondetection = getboolfield_default(L, 1,
191198
"collisiondetection", collisiondetection);
199+
collision_removal = getboolfield_default(L, 1,
200+
"collision_removal", collision_removal);
192201
vertical = getboolfield_default(L, 1, "vertical", vertical);
193202
texture = getstringfield_default(L, 1, "texture", "");
194203
playername = getstringfield_default(L, 1, "playername", "");
@@ -201,6 +210,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
201210
minexptime, maxexptime,
202211
minsize, maxsize,
203212
collisiondetection,
213+
collision_removal,
204214
vertical,
205215
texture, playername);
206216
lua_pushnumber(L, id);

0 commit comments

Comments
 (0)
Please sign in to comment.