Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sofar authored and kwolekr committed May 28, 2016
1 parent 62d15ac commit d499ec4
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 32 deletions.
6 changes: 6 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -3885,6 +3885,9 @@ Definition tables
size = 1,
collisiondetection = false,
-- ^ collisiondetection: if true collides with physical objects
collision_removal = false,
-- ^ collision_removal: if true then particle is removed when it collides,
-- ^ requires collisiondetection = true to have any effect
vertical = false,
-- ^ vertical: if true faces player using y axis only
texture = "image.png",
Expand Down Expand Up @@ -3914,6 +3917,9 @@ Definition tables
-- ^ minsize/maxsize, minexptime/maxexptime (expirationtime)
collisiondetection = false,
-- ^ collisiondetection: if true uses collision detection
collision_removal = false,
-- ^ collision_removal: if true then particle is removed when it collides,
-- ^ requires collisiondetection = true to have any effect
vertical = false,
-- ^ vertical: if true faces player using y axis only
texture = "image.png",
Expand Down
2 changes: 2 additions & 0 deletions src/client.h
Expand Up @@ -182,6 +182,7 @@ struct ClientEvent
f32 expirationtime;
f32 size;
bool collisiondetection;
bool collision_removal;
bool vertical;
std::string *texture;
} spawn_particle;
Expand All @@ -199,6 +200,7 @@ struct ClientEvent
f32 minsize;
f32 maxsize;
bool collisiondetection;
bool collision_removal;
bool vertical;
std::string *texture;
u32 id;
Expand Down
7 changes: 7 additions & 0 deletions src/network/clientpackethandler.cpp
Expand Up @@ -898,8 +898,10 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
bool collisiondetection = readU8(is);
std::string texture = deSerializeLongString(is);
bool vertical = false;
bool collision_removal = false;
try {
vertical = readU8(is);
collision_removal = readU8(is);
} catch (...) {}

ClientEvent event;
Expand All @@ -910,6 +912,7 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
event.spawn_particle.expirationtime = expirationtime;
event.spawn_particle.size = size;
event.spawn_particle.collisiondetection = collisiondetection;
event.spawn_particle.collision_removal = collision_removal;
event.spawn_particle.vertical = vertical;
event.spawn_particle.texture = new std::string(texture);

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

bool vertical = false;
bool collision_removal = false;
try {
*pkt >> vertical;
*pkt >> collision_removal;

} catch (...) {}

ClientEvent event;
Expand All @@ -961,6 +967,7 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
event.add_particlespawner.minsize = minsize;
event.add_particlespawner.maxsize = maxsize;
event.add_particlespawner.collisiondetection = collisiondetection;
event.add_particlespawner.collision_removal = collision_removal;
event.add_particlespawner.vertical = vertical;
event.add_particlespawner.texture = new std::string(texture);
event.add_particlespawner.id = id;
Expand Down
2 changes: 2 additions & 0 deletions src/network/networkprotocol.h
Expand Up @@ -474,6 +474,7 @@ enum ToClientCommand
u8 bool vertical
u32 len
u8[len] texture
u8 collision_removal
*/

TOCLIENT_ADD_PARTICLESPAWNER = 0x47,
Expand All @@ -495,6 +496,7 @@ enum ToClientCommand
u32 len
u8[len] texture
u32 id
u8 collision_removal
*/

TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY = 0x48,
Expand Down
39 changes: 24 additions & 15 deletions src/particles.cpp
Expand Up @@ -54,6 +54,7 @@ Particle::Particle(
float expirationtime,
float size,
bool collisiondetection,
bool collision_removal,
bool vertical,
video::ITexture *texture,
v2f texpos,
Expand Down Expand Up @@ -85,6 +86,7 @@ Particle::Particle(
m_player = player;
m_size = size;
m_collisiondetection = collisiondetection;
m_collision_removal = collision_removal;
m_vertical = vertical;

// Irrlicht stuff
Expand Down Expand Up @@ -126,20 +128,21 @@ void Particle::render()
void Particle::step(float dtime)
{
m_time += dtime;
if (m_collisiondetection)
{
if (m_collisiondetection) {
aabb3f box = m_collisionbox;
v3f p_pos = m_pos*BS;
v3f p_velocity = m_velocity*BS;
collisionMoveSimple(m_env, m_gamedef,
BS*0.5, box,
0, dtime,
&p_pos, &p_velocity, m_acceleration * BS);
m_pos = p_pos/BS;
m_velocity = p_velocity/BS;
}
else
{
v3f p_pos = m_pos * BS;
v3f p_velocity = m_velocity * BS;
collisionMoveResult r = collisionMoveSimple(m_env,
m_gamedef, BS * 0.5, box, 0, dtime, &p_pos,
&p_velocity, m_acceleration * BS);
if (m_collision_removal && r.collides) {
// force expiration of the particle
m_expiration = -1.0;
} else {
m_pos = p_pos / BS;
m_velocity = p_velocity / BS;
}
} else {
m_velocity += m_acceleration * dtime;
m_pos += m_velocity * dtime;
}
Expand Down Expand Up @@ -210,8 +213,8 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
u16 amount, float time,
v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
float minexptime, float maxexptime, float minsize, float maxsize,
bool collisiondetection, bool vertical, video::ITexture *texture, u32 id,
ParticleManager *p_manager) :
bool collisiondetection, bool collision_removal, bool vertical,
video::ITexture *texture, u32 id, ParticleManager *p_manager) :
m_particlemanager(p_manager)
{
m_gamedef = gamedef;
Expand All @@ -230,6 +233,7 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
m_minsize = minsize;
m_maxsize = maxsize;
m_collisiondetection = collisiondetection;
m_collision_removal = collision_removal;
m_vertical = vertical;
m_texture = texture;
m_time = 0;
Expand Down Expand Up @@ -277,6 +281,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
exptime,
size,
m_collisiondetection,
m_collision_removal,
m_vertical,
m_texture,
v2f(0.0, 0.0),
Expand Down Expand Up @@ -317,6 +322,7 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
exptime,
size,
m_collisiondetection,
m_collision_removal,
m_vertical,
m_texture,
v2f(0.0, 0.0),
Expand Down Expand Up @@ -446,6 +452,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
event->add_particlespawner.minsize,
event->add_particlespawner.maxsize,
event->add_particlespawner.collisiondetection,
event->add_particlespawner.collision_removal,
event->add_particlespawner.vertical,
texture,
event->add_particlespawner.id,
Expand Down Expand Up @@ -480,6 +487,7 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
event->spawn_particle.expirationtime,
event->spawn_particle.size,
event->spawn_particle.collisiondetection,
event->spawn_particle.collision_removal,
event->spawn_particle.vertical,
texture,
v2f(0.0, 0.0),
Expand Down Expand Up @@ -555,6 +563,7 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
visual_size,
true,
false,
false,
texture,
texpos,
texsize);
Expand Down
5 changes: 5 additions & 0 deletions src/particles.h
Expand Up @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,

struct ClientEvent;
class ParticleManager;
class ClientEnvironment;

class Particle : public scene::ISceneNode
{
Expand All @@ -45,6 +46,7 @@ class Particle : public scene::ISceneNode
float expirationtime,
float size,
bool collisiondetection,
bool collision_removal,
bool vertical,
video::ITexture *texture,
v2f texpos,
Expand Down Expand Up @@ -97,6 +99,7 @@ class Particle : public scene::ISceneNode
float m_size;
u8 m_light;
bool m_collisiondetection;
bool m_collision_removal;
bool m_vertical;
v3s16 m_camera_offset;
};
Expand All @@ -115,6 +118,7 @@ class ParticleSpawner
float minexptime, float maxexptime,
float minsize, float maxsize,
bool collisiondetection,
bool collision_removal,
bool vertical,
video::ITexture *texture,
u32 id,
Expand Down Expand Up @@ -148,6 +152,7 @@ class ParticleSpawner
video::ITexture *m_texture;
std::vector<float> m_spawntimes;
bool m_collisiondetection;
bool m_collision_removal;
bool m_vertical;

};
Expand Down
24 changes: 17 additions & 7 deletions src/script/lua_api/l_particles.cpp
Expand Up @@ -21,13 +21,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h"
#include "common/c_converter.h"
#include "server.h"
#include "particles.h"

// add_particle({pos=, velocity=, acceleration=, expirationtime=,
// size=, collisiondetection=, vertical=, texture=, player=})
// size=, collisiondetection=, collision_removal=, vertical=,
// texture=, player=})
// pos/velocity/acceleration = {x=num, y=num, z=num}
// expirationtime = num (seconds)
// size = num
// collisiondetection = bool
// collision_removal = bool
// vertical = bool
// texture = e.g."default_wood.png"
int ModApiParticles::l_add_particle(lua_State *L)
Expand All @@ -41,8 +44,8 @@ int ModApiParticles::l_add_particle(lua_State *L)
float expirationtime, size;
expirationtime = size = 1;

bool collisiondetection, vertical;
collisiondetection = vertical = false;
bool collisiondetection, vertical, collision_removal;
collisiondetection = vertical = collision_removal = false;

std::string texture = "";
std::string playername = "";
Expand Down Expand Up @@ -94,12 +97,14 @@ int ModApiParticles::l_add_particle(lua_State *L)
size = getfloatfield_default(L, 1, "size", 1);
collisiondetection = getboolfield_default(L, 1,
"collisiondetection", collisiondetection);
collision_removal = getboolfield_default(L, 1,
"collision_removal", collision_removal);
vertical = getboolfield_default(L, 1, "vertical", vertical);
texture = getstringfield_default(L, 1, "texture", "");
playername = getstringfield_default(L, 1, "playername", "");
}
getServer(L)->spawnParticle(playername, pos, vel, acc,
expirationtime, size, collisiondetection, vertical, texture);
getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size,
collisiondetection, collision_removal, vertical, texture);
return 1;
}

Expand All @@ -110,13 +115,15 @@ int ModApiParticles::l_add_particle(lua_State *L)
// minexptime=, maxexptime=,
// minsize=, maxsize=,
// collisiondetection=,
// collision_removal=,
// vertical=,
// texture=,
// player=})
// minpos/maxpos/minvel/maxvel/minacc/maxacc = {x=num, y=num, z=num}
// minexptime/maxexptime = num (seconds)
// minsize/maxsize = num
// collisiondetection = bool
// collision_removal = bool
// vertical = bool
// texture = e.g."default_wood.png"
int ModApiParticles::l_add_particlespawner(lua_State *L)
Expand All @@ -129,8 +136,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
minpos= maxpos= minvel= maxvel= minacc= maxacc= v3f(0, 0, 0);
float time, minexptime, maxexptime, minsize, maxsize;
time= minexptime= maxexptime= minsize= maxsize= 1;
bool collisiondetection, vertical;
collisiondetection= vertical= false;
bool collisiondetection, vertical, collision_removal;
collisiondetection = vertical = collision_removal = false;
std::string texture = "";
std::string playername = "";

Expand Down Expand Up @@ -189,6 +196,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
maxsize = getfloatfield_default(L, 1, "maxsize", maxsize);
collisiondetection = getboolfield_default(L, 1,
"collisiondetection", collisiondetection);
collision_removal = getboolfield_default(L, 1,
"collision_removal", collision_removal);
vertical = getboolfield_default(L, 1, "vertical", vertical);
texture = getstringfield_default(L, 1, "texture", "");
playername = getstringfield_default(L, 1, "playername", "");
Expand All @@ -201,6 +210,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
minexptime, maxexptime,
minsize, maxsize,
collisiondetection,
collision_removal,
vertical,
texture, playername);
lua_pushnumber(L, id);
Expand Down

0 comments on commit d499ec4

Please sign in to comment.