]> git.lizzy.rs Git - minetest.git/commitdiff
Particles: Add option to remove particles on collision
authorAuke Kok <sofar+github@foo-projects.org>
Sat, 28 May 2016 04:08:23 +0000 (21:08 -0700)
committerkwolekr <kwolekr@minetest.net>
Sat, 28 May 2016 04:08:23 +0000 (00:08 -0400)
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.

doc/lua_api.txt
src/client.h
src/network/clientpackethandler.cpp
src/network/networkprotocol.h
src/particles.cpp
src/particles.h
src/script/lua_api/l_particles.cpp
src/server.cpp
src/server.h

index 01763fd73e93a174adfa8088ee675cf7ff5068ad..03f2dad321abce8b44aa639b046ccbb52e2e5649 100644 (file)
@@ -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",
@@ -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",
index cdadb9d3ea42b1f2566f0a48fcb3524a1477345c..a7eb22ad945160d3cf451bc2afdd157eaca6e3b5 100644 (file)
@@ -182,6 +182,7 @@ struct ClientEvent
                        f32 expirationtime;
                        f32 size;
                        bool collisiondetection;
+                       bool collision_removal;
                        bool vertical;
                        std::string *texture;
                } spawn_particle;
@@ -199,6 +200,7 @@ struct ClientEvent
                        f32 minsize;
                        f32 maxsize;
                        bool collisiondetection;
+                       bool collision_removal;
                        bool vertical;
                        std::string *texture;
                        u32 id;
index 0498f4048eb7bd1a2e916c97ce1a5e6baaa3a45e..48c573da594ae77977c7336b732bed57e2527557 100644 (file)
@@ -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;
@@ -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);
 
@@ -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;
@@ -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;
index 177b97680e46b5f2641c1e82349b8e3d7c095b6c..3a9483efbfa15c0fd8a34845ed2319aef1da5398 100644 (file)
@@ -474,6 +474,7 @@ enum ToClientCommand
                u8 bool vertical
                u32 len
                u8[len] texture
+               u8 collision_removal
        */
 
        TOCLIENT_ADD_PARTICLESPAWNER = 0x47,
@@ -495,6 +496,7 @@ enum ToClientCommand
                u32 len
                u8[len] texture
                u32 id
+               u8 collision_removal
        */
 
        TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY = 0x48,
index 525258a25fa21f08b35b146900fc192eb5cb8c86..ccca691d17d76267f386c7f91b801e1d922dbc74 100644 (file)
@@ -54,6 +54,7 @@ Particle::Particle(
        float expirationtime,
        float size,
        bool collisiondetection,
+       bool collision_removal,
        bool vertical,
        video::ITexture *texture,
        v2f texpos,
@@ -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
@@ -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;
        }
@@ -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;
@@ -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;
@@ -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),
@@ -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),
@@ -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,
@@ -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),
@@ -555,6 +563,7 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
                visual_size,
                true,
                false,
+               false,
                texture,
                texpos,
                texsize);
index dda84385c1bf49df9571b62823153b26506adf71..bc3ca53b7ce2e14328fc538f9f594c00b44c59ec 100644 (file)
@@ -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
 {
@@ -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,
@@ -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;
 };
@@ -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,
@@ -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;
 
 };
index f6c1725de37ef389c06451381f1d4df33e441125..263e35407e36d0312988e155daf08c4ef82c51af 100644 (file)
@@ -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)
@@ -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 = "";
@@ -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;
 }
 
@@ -110,6 +115,7 @@ int ModApiParticles::l_add_particle(lua_State *L)
 //                             minexptime=, maxexptime=,
 //                             minsize=, maxsize=,
 //                             collisiondetection=,
+//                             collision_removal=,
 //                             vertical=,
 //                             texture=,
 //                             player=})
@@ -117,6 +123,7 @@ int ModApiParticles::l_add_particle(lua_State *L)
 // 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)
@@ -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 = "";
 
@@ -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", "");
@@ -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);
index a3b686c257050027afc6672d8f6a7d86afd31626..ada45dc684fdb2983327bccf0c1ef7177cbdf530 100644 (file)
@@ -1673,7 +1673,8 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
 // Spawns a particle on peer with peer_id
 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
                                float expirationtime, float size, bool collisiondetection,
-                               bool vertical, std::string texture)
+                               bool collision_removal,
+                               bool vertical, const std::string &texture)
 {
        DSTACK(FUNCTION_NAME);
 
@@ -1683,6 +1684,7 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
                        << size << collisiondetection;
        pkt.putLongString(texture);
        pkt << vertical;
+       pkt << collision_removal;
 
        if (peer_id != PEER_ID_INEXISTENT) {
                Send(&pkt);
@@ -1695,7 +1697,8 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
 // Adds a ParticleSpawner on peer with peer_id
 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
        v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
-       float minsize, float maxsize, bool collisiondetection, bool vertical, std::string texture, u32 id)
+       float minsize, float maxsize, bool collisiondetection, bool collision_removal,
+       bool vertical, const std::string &texture, u32 id)
 {
        DSTACK(FUNCTION_NAME);
 
@@ -1708,6 +1711,7 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
        pkt.putLongString(texture);
 
        pkt << id << vertical;
+       pkt << collision_removal;
 
        if (peer_id != PEER_ID_INEXISTENT) {
                Send(&pkt);
@@ -3160,7 +3164,8 @@ void Server::notifyPlayers(const std::wstring &msg)
 void Server::spawnParticle(const std::string &playername, v3f pos,
        v3f velocity, v3f acceleration,
        float expirationtime, float size, bool
-       collisiondetection, bool vertical, const std::string &texture)
+       collisiondetection, bool collision_removal,
+       bool vertical, const std::string &texture)
 {
        // m_env will be NULL if the server is initializing
        if (!m_env)
@@ -3175,13 +3180,15 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
        }
 
        SendSpawnParticle(peer_id, pos, velocity, acceleration,
-                       expirationtime, size, collisiondetection, vertical, texture);
+                       expirationtime, size, collisiondetection,
+                       collision_removal, vertical, texture);
 }
 
 u32 Server::addParticleSpawner(u16 amount, float spawntime,
        v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
        float minexptime, float maxexptime, float minsize, float maxsize,
-       bool collisiondetection, bool vertical, const std::string &texture,
+       bool collisiondetection, bool collision_removal,
+       bool vertical, const std::string &texture,
        const std::string &playername)
 {
        // m_env will be NULL if the server is initializing
@@ -3200,7 +3207,7 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
        SendAddParticleSpawner(peer_id, amount, spawntime,
                minpos, maxpos, minvel, maxvel, minacc, maxacc,
                minexptime, maxexptime, minsize, maxsize,
-               collisiondetection, vertical, texture, id);
+               collisiondetection, collision_removal, vertical, texture, id);
 
        return id;
 }
index daf51dee10756b87e2dc8645db73b64cd3c11e84..7ee15a4638a5f1e75975e9ae61cf5e115eed6e5e 100644 (file)
@@ -275,7 +275,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
        void spawnParticle(const std::string &playername,
                v3f pos, v3f velocity, v3f acceleration,
                float expirationtime, float size,
-               bool collisiondetection, bool vertical, const std::string &texture);
+               bool collisiondetection, bool collision_removal,
+               bool vertical, const std::string &texture);
 
        u32 addParticleSpawner(u16 amount, float spawntime,
                v3f minpos, v3f maxpos,
@@ -283,7 +284,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
                v3f minacc, v3f maxacc,
                float minexptime, float maxexptime,
                float minsize, float maxsize,
-               bool collisiondetection, bool vertical, const std::string &texture,
+               bool collisiondetection, bool collision_removal,
+               bool vertical, const std::string &texture,
                const std::string &playername);
 
        void deleteParticleSpawner(const std::string &playername, u32 id);
@@ -456,7 +458,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
                v3f minacc, v3f maxacc,
                float minexptime, float maxexptime,
                float minsize, float maxsize,
-               bool collisiondetection, bool vertical, std::string texture, u32 id);
+               bool collisiondetection, bool collision_removal,
+               bool vertical, const std::string &texture, u32 id);
 
        void SendDeleteParticleSpawner(u16 peer_id, u32 id);
 
@@ -464,7 +467,8 @@ class Server : public con::PeerHandler, public MapEventReceiver,
        void SendSpawnParticle(u16 peer_id,
                v3f pos, v3f velocity, v3f acceleration,
                float expirationtime, float size,
-               bool collisiondetection, bool vertical, std::string texture);
+               bool collisiondetection, bool collision_removal,
+               bool vertical, const std::string &texture);
 
        u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas);
        void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true);