summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2025-02-22 01:35:06 +0100
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2025-02-25 18:28:11 +0100
commit00b4fb5120e951c52d82d56f559981eca30b89bc (patch)
tree99ba9b57535f0a9978acdec9b7308a5ef9e26d7e /src
parent63e2712b2ad2c398160d399bdd9e454417c2654b (diff)
downloadmana-00b4fb5120e951c52d82d56f559981eca30b89bc.tar.gz
mana-00b4fb5120e951c52d82d56f559981eca30b89bc.tar.bz2
mana-00b4fb5120e951c52d82d56f559981eca30b89bc.tar.xz
mana-00b4fb5120e951c52d82d56f559981eca30b89bc.zip
Replaced ParticleContainer with a ParticleHandle
The main feature of the ParticleContainer seemed to be to provide persistent access to particles, even though they are generally owned by their parent particle. This allowed particles to be moved along with the ActorSprite and to be killed explicitly when they were no longer wanted. The ParticleHandle now takes care of disabling automatic deletion and of killing the particle along with the handle. It allows the particle references to be stored in whatever container is suitable, like a vector for general ActorSprite particle effects, separate vectors for equipment based particles and finally a map for status effect particles. Moving the particles along with the ActorSprite does need to happen more explicitly now, but overall it's a nice cleanup.
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/actorsprite.cpp17
-rw-r--r--src/actorsprite.h4
-rw-r--r--src/being.cpp46
-rw-r--r--src/being.h6
-rw-r--r--src/game.cpp2
-rw-r--r--src/particle.cpp33
-rw-r--r--src/particle.h51
-rw-r--r--src/particlecontainer.cpp177
-rw-r--r--src/particlecontainer.h118
10 files changed, 96 insertions, 360 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 36d1a9fb..f47cbf5b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -465,8 +465,6 @@ set(SRCS
openglgraphics.h
particle.cpp
particle.h
- particlecontainer.cpp
- particlecontainer.h
particleemitter.cpp
particleemitter.h
particleemitterprop.h
diff --git a/src/actorsprite.cpp b/src/actorsprite.cpp
index 68803e26..f22fbd2d 100644
--- a/src/actorsprite.cpp
+++ b/src/actorsprite.cpp
@@ -35,6 +35,7 @@
#include "utils/time.h"
+#include <algorithm>
#include <cassert>
#define EFFECTS_FILE "effects.xml"
@@ -96,13 +97,19 @@ void ActorSprite::logic()
if (mUsedTargetCursor)
mUsedTargetCursor->update(Time::deltaTimeMs());
- // See note at ActorSprite::draw
+ // Erase all extinct particle effects
+ mChildParticleEffects.erase(std::remove_if(mChildParticleEffects.begin(),
+ mChildParticleEffects.end(),
+ [](const Particle *p) { return p->isExtinct(); }),
+ mChildParticleEffects.end());
+
+ // Move the remaining
float py = mPos.y;
if (mMap)
- py += mMap->getTileHeight() / 2;
+ py += mMap->getTileHeight() / 2; // See note at ActorSprite::draw
- // Update particle effects
- mChildParticleEffects.moveTo(mPos.x, py);
+ for (Particle *p : mChildParticleEffects)
+ p->moveTo(mPos.x, py);
}
void ActorSprite::setMap(Map* map)
@@ -115,7 +122,7 @@ void ActorSprite::setMap(Map* map)
void ActorSprite::controlParticle(Particle *particle)
{
- mChildParticleEffects.addLocally(particle);
+ mChildParticleEffects.emplace_back(particle);
}
void ActorSprite::setTargetType(TargetCursorType type)
diff --git a/src/actorsprite.h b/src/actorsprite.h
index c82a486a..93a4551f 100644
--- a/src/actorsprite.h
+++ b/src/actorsprite.h
@@ -23,7 +23,7 @@
#include "actor.h"
#include "compoundsprite.h"
#include "map.h"
-#include "particlecontainer.h"
+#include "particle.h"
class SimpleAnimation;
class StatusEffect;
@@ -122,7 +122,7 @@ protected:
bool forceDisplay = true);
int mId;
- ParticleList mChildParticleEffects;
+ std::vector<ParticleHandle> mChildParticleEffects;
CompoundSprite mSprites;
diff --git a/src/being.cpp b/src/being.cpp
index 4a74bfd8..d1934aef 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -79,7 +79,6 @@ Being::Being(int id, Type type, int subtype, Map *map)
Being::~Being()
{
- mStatusParticleEffects.clearLocally();
delete mSpeechBubble;
delete mDispName;
delete mText;
@@ -620,12 +619,10 @@ void Being::updateStatusEffect(int id, bool newStatus)
if (!effect)
return;
- Particle *particle = effect->getParticle(newStatus);
-
- if (id >= 0)
- {
- mStatusParticleEffects.setLocally(id, particle);
- }
+ if (Particle *particle = effect->getParticle(newStatus))
+ mStatusParticleEffects[id] = ParticleHandle(particle);
+ else
+ mStatusParticleEffects.erase(id);
}
void Being::setAction(Action action, int attackId)
@@ -823,11 +820,11 @@ void Being::logic()
restoreAllSpriteParticles();
// Restart status/particle effects, if needed
- for (int statusEffect : mStatusEffects)
+ for (int id : mStatusEffects)
{
- const StatusEffect *effect = StatusEffectDB::getStatusEffect(statusEffect);
+ const StatusEffect *effect = StatusEffectDB::getStatusEffect(id);
if (effect && effect->persistentParticleEffect)
- updateStatusEffect(statusEffect, true);
+ updateStatusEffect(id, true);
}
}
@@ -841,7 +838,12 @@ void Being::logic()
py += mMap->getTileHeight() / 2;
// Update particle effects
- mStatusParticleEffects.moveTo(mPos.x, py);
+ for (auto &spriteState : mSpriteStates)
+ for (auto &particle : spriteState.particles)
+ particle->moveTo(mPos.x, py);
+
+ for (auto &[_, p] : mStatusParticleEffects)
+ p->moveTo(mPos.x, py);
}
ActorSprite::logic();
@@ -1083,25 +1085,10 @@ void Being::addSpriteParticles(SpriteState &spriteState, const SpriteDisplay &di
for (const auto &particle : display.particles)
{
Particle *p = particleEngine->addEffect(particle, 0, 0, 0);
- controlParticle(p);
- spriteState.particles.push_back(p);
+ spriteState.particles.emplace_back(p);
}
}
-void Being::removeSpriteParticles(SpriteState &spriteState)
-{
- for (auto particle : spriteState.particles)
- mChildParticleEffects.removeLocally(particle);
-
- spriteState.particles.clear();
-}
-
-void Being::removeAllSpriteParticles()
-{
- for (auto &spriteState : mSpriteStates)
- removeSpriteParticles(spriteState);
-}
-
void Being::restoreAllSpriteParticles()
{
if (mType != PLAYER)
@@ -1276,7 +1263,7 @@ void Being::setSprite(unsigned slot, int id, const std::string &color,
// Clear current particles when the ID changes
if (spriteState.id != id)
- removeSpriteParticles(spriteState);
+ spriteState.particles.clear();
// Clear the current sprite when the color changes
if (spriteState.color != color && spriteState.visibleId)
@@ -1406,11 +1393,10 @@ void Being::event(Event::Channel channel, const Event &event)
void Being::setMap(Map *map)
{
- // Remove sprite particles because ActorSprite is going to kill them all
for (auto &spriteState : mSpriteStates)
spriteState.particles.clear();
- mStatusParticleEffects.clearLocally();
+ mStatusParticleEffects.clear();
mRestoreParticlesOnLogic = true;
diff --git a/src/being.h b/src/being.h
index 609953ce..ab5e33c3 100644
--- a/src/being.h
+++ b/src/being.h
@@ -446,7 +446,7 @@ class Being : public ActorSprite, public EventListener
int id = 0;
int visibleId = 0;
std::string color;
- std::vector<Particle*> particles;
+ std::vector<ParticleHandle> particles;
};
/**
@@ -460,8 +460,6 @@ class Being : public ActorSprite, public EventListener
void updateNamePosition();
void addSpriteParticles(SpriteState &spriteState, const SpriteDisplay &display);
- void removeSpriteParticles(SpriteState &spriteState);
- void removeAllSpriteParticles();
void restoreAllSpriteParticles();
void updateColors();
@@ -534,7 +532,7 @@ class Being : public ActorSprite, public EventListener
Type mType = UNKNOWN;
std::set<int> mStatusEffects; /**< set of active status effects */
- ParticleVector mStatusParticleEffects;
+ std::map<int, ParticleHandle> mStatusParticleEffects;
/** Speech Bubble components */
SpeechBubble *mSpeechBubble;
diff --git a/src/game.cpp b/src/game.cpp
index 8694402d..ac63fd6c 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -129,7 +129,7 @@ static void initEngines()
effectManager = new EffectManager;
particleEngine = new Particle(nullptr);
- particleEngine->setupEngine();
+ Particle::setupEngine();
Event::trigger(Event::GameChannel, Event::EnginesInitialized);
}
diff --git a/src/particle.cpp b/src/particle.cpp
index 754cc43b..6717653f 100644
--- a/src/particle.cpp
+++ b/src/particle.cpp
@@ -74,7 +74,6 @@ void Particle::setupEngine()
Particle::fastPhysics = config.particleFastPhysics;
Particle::emitterSkip = config.particleEmitterSkip + 1;
Particle::enabled = config.particleEffects;
- disableAutoDelete();
logger->log("Particle engine set up");
}
@@ -204,39 +203,35 @@ bool Particle::update()
// Update child particles
- for (auto p = mChildParticles.begin();
- p != mChildParticles.end();)
+ for (auto p = mChildParticles.begin(); p != mChildParticles.end(); )
{
+ auto particle = *p;
//move particle with its parent if desired
- if ((*p)->doesFollow())
+ if (particle->doesFollow())
{
- (*p)->moveBy(change);
+ particle->moveBy(change);
}
- //update particle
- if ((*p)->update())
+ if (particle->update())
{
p++;
}
else
{
- delete (*p);
+ delete particle;
p = mChildParticles.erase(p);
}
}
- return mAlive == ALIVE || !mChildParticles.empty() || !mAutoDelete;
+ return isAlive() || !mChildParticles.empty() || !mAutoDelete;
}
void Particle::moveBy(const Vector &change)
{
mPos += change;
+
for (auto &childParticle : mChildParticles)
- {
if (childParticle->doesFollow())
- {
childParticle->moveBy(change);
- }
- }
}
void Particle::moveTo(float x, float y)
@@ -405,13 +400,11 @@ Particle *Particle::addTextRiseFadeOutEffect(const std::string &text,
void Particle::adjustEmitterSize(int w, int h)
{
- if (mAllowSizeAdjust)
- {
- for (auto &childEmitter : mChildEmitters)
- {
- childEmitter->adjustSize(w, h);
- }
- }
+ if (!mAllowSizeAdjust)
+ return;
+
+ for (auto &childEmitter : mChildEmitters)
+ childEmitter->adjustSize(w, h);
}
float Particle::getCurrentAlpha() const
diff --git a/src/particle.h b/src/particle.h
index fb441b1b..a130a36e 100644
--- a/src/particle.h
+++ b/src/particle.h
@@ -76,7 +76,7 @@ class Particle : public Actor
* Gives a particle the properties of an engine root particle and loads
* the particle-related config settings.
*/
- void setupEngine();
+ static void setupEngine();
/**
* Updates particle position, returns false when the particle should
@@ -291,4 +291,53 @@ class Particle : public Actor
float mMomentum = 1.0f; /**< How much speed the particle retains after each game tick*/
};
+/**
+ * A handle on a particle. The handle prevents automatic deletion of the
+ * particle by its parent and kills the particle when the handle is destroyed.
+ */
+class ParticleHandle
+{
+ public:
+ explicit ParticleHandle(Particle *particle = nullptr):
+ mParticle(particle)
+ {
+ if (mParticle)
+ mParticle->disableAutoDelete();
+ }
+
+ ParticleHandle(const ParticleHandle &) = delete;
+
+ ParticleHandle(ParticleHandle &&other):
+ mParticle(other.mParticle)
+ {
+ other.mParticle = nullptr;
+ }
+
+ ~ParticleHandle()
+ {
+ if (mParticle)
+ mParticle->kill();
+ }
+
+ ParticleHandle &operator=(const ParticleHandle &) = delete;
+
+ ParticleHandle &operator=(ParticleHandle &&other)
+ {
+ if (this != &other)
+ {
+ if (mParticle)
+ mParticle->kill();
+ mParticle = other.mParticle;
+ other.mParticle = nullptr;
+ }
+ return *this;
+ }
+
+ Particle *operator->() const { return mParticle; }
+ operator Particle *() const { return mParticle; }
+
+ private:
+ Particle *mParticle;
+};
+
extern Particle *particleEngine;
diff --git a/src/particlecontainer.cpp b/src/particlecontainer.cpp
deleted file mode 100644
index 53742109..00000000
--- a/src/particlecontainer.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2008-2009 The Mana World Development Team
- * Copyright (C) 2009-2012 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <cassert>
-
-#include "particle.h"
-#include "particlecontainer.h"
-
-ParticleContainer::ParticleContainer(ParticleContainer *parent,
- bool delParent):
- mDelParent(delParent),
- mNext(parent)
-{}
-
-ParticleContainer::~ParticleContainer()
-{
- if (mDelParent)
- delete mNext;
-}
-
-void ParticleContainer::clear()
-{
- clearLocally();
- if (mNext)
- mNext->clear();
-}
-
-void ParticleContainer::moveTo(float x, float y)
-{
- if (mNext)
- mNext->moveTo(x, y);
-}
-
-// -- particle list ----------------------------------------
-
-ParticleList::ParticleList(ParticleContainer *parent, bool delParent):
- ParticleContainer(parent, delParent)
-{}
-
-ParticleList::~ParticleList()
-{
- clearLocally();
-}
-
-void ParticleList::addLocally(Particle *particle)
-{
- if (particle)
- {
- // The effect may not die without the beings permission or we segfault
- particle->disableAutoDelete();
- mElements.push_back(particle);
- }
-}
-
-void ParticleList::removeLocally(Particle *particle)
-{
- for (auto it = mElements.begin(), it_end = mElements.end(); it != it_end;)
- {
- if (*it == particle)
- {
- (*it)->kill();
- it = mElements.erase(it);
- }
- else
- it++;
- }
-}
-
-void ParticleList::clearLocally()
-{
- for (auto &element : mElements)
- element->kill();
-
- mElements.clear();
-}
-
-void ParticleList::moveTo(float x, float y)
-{
- ParticleContainer::moveTo(x, y);
-
- for (auto it = mElements.begin();
- it != mElements.end();)
- {
- (*it)->moveTo(x, y);
- if ((*it)->isExtinct())
- {
- (*it)->kill();
- it = mElements.erase(it);
- }
- else
- it++;
- }
-}
-
-// -- particle vector ----------------------------------------
-
-ParticleVector::ParticleVector(ParticleContainer *parent, bool delParent):
- ParticleContainer(parent, delParent)
-{}
-
-ParticleVector::~ParticleVector()
-{
- clearLocally();
-}
-
-void ParticleVector::setLocally(int index, Particle *particle)
-{
- assert(index >= 0);
-
- delLocally(index);
-
- if (mIndexedElements.size() <= (unsigned) index)
- mIndexedElements.resize(index + 1);
-
- if (particle)
- particle->disableAutoDelete();
- mIndexedElements[index] = particle;
-}
-
-void ParticleVector::delLocally(int index)
-{
- assert(index >= 0);
-
- if (mIndexedElements.size() <= (unsigned) index)
- return;
-
- Particle *p = mIndexedElements[index];
- if (p)
- {
- mIndexedElements[index] = nullptr;
- p->kill();
- }
-}
-
-void ParticleVector::clearLocally()
-{
- for (unsigned int i = 0; i < mIndexedElements.size(); i++)
- delLocally(i);
-}
-
-void ParticleVector::moveTo(float x, float y)
-{
- ParticleContainer::moveTo(x, y);
-
- for (auto &indexedElement : mIndexedElements)
- {
- if (indexedElement)
- {
- indexedElement->moveTo(x, y);
-
- if (indexedElement->isExtinct())
- {
- indexedElement->kill();
- indexedElement = nullptr;
- }
- }
- }
-}
-
diff --git a/src/particlecontainer.h b/src/particlecontainer.h
deleted file mode 100644
index 519553ab..00000000
--- a/src/particlecontainer.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * The Mana Client
- * Copyright (C) 2008-2009 The Mana World Development Team
- * Copyright (C) 2009-2012 The Mana Developers
- *
- * This file is part of The Mana Client.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include <list>
-#include <vector>
-
-class Particle;
-
-/**
- * Set of particle effects. May be stacked with other ParticleContainers. All
- * operations herein affect such stacked containers, unless the operations end
- * in `Locally'.
- */
-class ParticleContainer
-{
-public:
- /**
- * Constructs a new particle container and assumes responsibility for
- * its parent (for all operations defined herein, except when ending in `Locally')
- *
- * delParent means that the destructor should also free the parent.
- */
- ParticleContainer(ParticleContainer *parent = nullptr, bool delParent = true);
- virtual ~ParticleContainer();
-
- /**
- * Kills and removes all particle effects
- */
- void clear();
-
- /**
- * Kills and removes all particle effects (only in this container)
- */
- virtual void clearLocally() = 0;
-
- /**
- * Sets the positions of all elements
- */
- virtual void moveTo(float x, float y);
-
-protected:
- bool mDelParent; /**< Delete mNext in destructor */
- ParticleContainer *mNext; /**< Contained container, if any */
-};
-
-/**
- * Linked list of particle effects.
- */
-class ParticleList final : public ParticleContainer
-{
-public:
- ParticleList(ParticleContainer *parent = nullptr, bool delParent = true);
- ~ParticleList() override;
-
- /**
- * Takes control of and adds a particle
- */
- void addLocally(Particle *);
-
- /**
- * `kills' and removes a particle
- */
- void removeLocally(Particle *);
-
- void clearLocally() override;
-
- void moveTo(float x, float y) override;
-
-protected:
- std::list<Particle *> mElements; /**< Contained particle effects */
-};
-
-/**
- * Particle container with indexing facilities
- */
-class ParticleVector final : public ParticleContainer
-{
-public:
- ParticleVector(ParticleContainer *parent = nullptr, bool delParent = true);
- ~ParticleVector() override;
-
- /**
- * Sets a particle at a specified index. Kills the previous particle
- * there, if needed.
- */
- void setLocally(int index, Particle *particle);
-
- /**
- * Removes a particle at a specified index
- */
- void delLocally(int index);
-
- void clearLocally() override;
- void moveTo(float x, float y) override;
-
-protected:
- std::vector<Particle *> mIndexedElements;
-};