mirror of
https://github.com/love2d/love.git
synced 2026-08-15 15:51:12 +02:00
Fix issue #437: Area-based particle spawn.
New particles are spawned around the particle emitter position according to a
configurabe distribution.
New functionality:
particlesystem:setAreaSpread(distributon, x, y)
distribution, x, y = particlesystem:getAreaSpread()
Where `distribution' is one of "none", "uniform", "normal".
`x' and `y' take different meaning based on the distribution:
* none: no area spread - particles spawned at emitter position.
* uniform: particle spawned at px,py in the rectangle around emitter
position ex,ey, i.e.:
ex - x < px < ex + x, ey - y < py < ey + y,
* normal: particle position drawn from a normal/gaussian distribution
with mean ex,ey and standard deviation x,y, i.e.:
px \in N(ex, x²), py \in N(ey, y²).
This commit is contained in:
@@ -45,10 +45,18 @@ float calculate_variation(float inner, float outer, float var)
|
||||
{
|
||||
float low = inner - (outer/2.0f)*var;
|
||||
float high = inner + (outer/2.0f)*var;
|
||||
float r = (rand() / (float(RAND_MAX)+1));
|
||||
float r = random();
|
||||
return low*(1-r)+high*r;
|
||||
}
|
||||
|
||||
StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM>::Entry ParticleSystem::distributionsEntries[] = {
|
||||
{ "none", ParticleSystem::DISTRIBUTION_NONE },
|
||||
{ "uniform", ParticleSystem::DISTRIBUTION_UNIFORM },
|
||||
{ "normal", ParticleSystem::DISTRIBUTION_NORMAL },
|
||||
};
|
||||
|
||||
StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM> ParticleSystem::distributions(ParticleSystem::distributionsEntries, sizeof(ParticleSystem::distributionsEntries));
|
||||
|
||||
|
||||
ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer)
|
||||
: pStart(0)
|
||||
@@ -57,6 +65,7 @@ ParticleSystem::ParticleSystem(Image *sprite, unsigned int buffer)
|
||||
, active(true)
|
||||
, emissionRate(0)
|
||||
, emitCounter(0)
|
||||
, areaSpreadDistribution(DISTRIBUTION_NONE)
|
||||
, lifetime(-1)
|
||||
, life(0)
|
||||
, particleLifeMin(0)
|
||||
@@ -108,45 +117,60 @@ void ParticleSystem::add()
|
||||
if (min == max)
|
||||
pLast->life = min;
|
||||
else
|
||||
pLast->life = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
|
||||
pLast->life = random(min, max);
|
||||
pLast->lifetime = pLast->life;
|
||||
|
||||
pLast->position[0] = position.getX();
|
||||
pLast->position[1] = position.getY();
|
||||
|
||||
switch (areaSpreadDistribution)
|
||||
{
|
||||
case DISTRIBUTION_UNIFORM:
|
||||
pLast->position[0] += random(-areaSpread.getX(), areaSpread.getX());
|
||||
pLast->position[1] += random(-areaSpread.getY(), areaSpread.getY());
|
||||
break;
|
||||
case DISTRIBUTION_NORMAL:
|
||||
pLast->position[0] += random_normal(areaSpread.getX());
|
||||
pLast->position[1] += random_normal(areaSpread.getY());
|
||||
break;
|
||||
case DISTRIBUTION_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
min = direction - spread/2.0f;
|
||||
max = direction + spread/2.0f;
|
||||
pLast->direction = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
|
||||
pLast->direction = random(min, max);
|
||||
|
||||
pLast->origin = position;
|
||||
|
||||
min = speedMin;
|
||||
max = speedMax;
|
||||
float speed = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
|
||||
float speed = random(min, max);
|
||||
pLast->speed = love::Vector(cos(pLast->direction), sin(pLast->direction));
|
||||
pLast->speed *= speed;
|
||||
|
||||
min = gravityMin;
|
||||
max = gravityMax;
|
||||
pLast->gravity = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
|
||||
pLast->gravity = random(min, max);
|
||||
|
||||
min = radialAccelerationMin;
|
||||
max = radialAccelerationMax;
|
||||
pLast->radialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
|
||||
pLast->radialAcceleration = random(min, max);
|
||||
|
||||
min = tangentialAccelerationMin;
|
||||
max = tangentialAccelerationMax;
|
||||
pLast->tangentialAcceleration = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;
|
||||
pLast->tangentialAcceleration = random(min, max);
|
||||
|
||||
pLast->sizeOffset = (rand() / (float(RAND_MAX)+1)) * sizeVariation; // time offset for size change
|
||||
pLast->sizeIntervalSize = (1.0f - (rand() / (float(RAND_MAX)+1)) * sizeVariation) - pLast->sizeOffset;
|
||||
pLast->sizeOffset = random(sizeVariation); // time offset for size change
|
||||
pLast->sizeIntervalSize = (1.0f - random(sizeVariation)) - pLast->sizeOffset;
|
||||
pLast->size = sizes[(size_t)(pLast->sizeOffset - .5f) * (sizes.size() - 1)];
|
||||
|
||||
min = rotationMin;
|
||||
max = rotationMax;
|
||||
pLast->spinStart = calculate_variation(spinStart, spinEnd, spinVariation);
|
||||
pLast->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
|
||||
pLast->rotation = (rand() / (float(RAND_MAX)+1)) * (max - min) + min;;
|
||||
pLast->rotation = random(min, max);
|
||||
|
||||
pLast->color = colors[0];
|
||||
|
||||
@@ -204,6 +228,13 @@ void ParticleSystem::setPosition(float x, float y)
|
||||
position = love::Vector(x, y);
|
||||
}
|
||||
|
||||
|
||||
void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y)
|
||||
{
|
||||
areaSpread = love::Vector(x, y);
|
||||
areaSpreadDistribution = distribution;
|
||||
}
|
||||
|
||||
void ParticleSystem::setDirection(float direction)
|
||||
{
|
||||
this->direction = direction;
|
||||
@@ -349,6 +380,16 @@ const love::Vector &ParticleSystem::getPosition() const
|
||||
return position;
|
||||
}
|
||||
|
||||
ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const
|
||||
{
|
||||
return areaSpreadDistribution;
|
||||
}
|
||||
|
||||
const love::Vector &ParticleSystem::getAreaSpreadParameters() const
|
||||
{
|
||||
return areaSpread;
|
||||
}
|
||||
|
||||
float ParticleSystem::getDirection() const
|
||||
{
|
||||
return direction;
|
||||
@@ -543,6 +584,16 @@ void ParticleSystem::update(float dt)
|
||||
} // while
|
||||
}
|
||||
|
||||
bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
|
||||
{
|
||||
return distributions.find(in, out);
|
||||
}
|
||||
|
||||
bool ParticleSystem::getConstant(AreaSpreadDistribution in, const char *&out)
|
||||
{
|
||||
return distributions.find(in, out);
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -72,6 +72,16 @@ struct particle
|
||||
class ParticleSystem : public Drawable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Type of distribution new particles are drawn from: None, uniform, normal.
|
||||
*/
|
||||
enum AreaSpreadDistribution
|
||||
{
|
||||
DISTRIBUTION_NONE,
|
||||
DISTRIBUTION_UNIFORM,
|
||||
DISTRIBUTION_NORMAL,
|
||||
DISTRIBUTION_MAX_ENUM,
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a particle system with the specified buffersize and sprite.
|
||||
@@ -122,6 +132,19 @@ public:
|
||||
**/
|
||||
void setPosition(float x, float y);
|
||||
|
||||
/**
|
||||
* Sets the emission area spread parameters and distribution type. The interpretation of
|
||||
* the parameters depends on the distribution type:
|
||||
*
|
||||
* * None: Parameters are ignored. No area spread.
|
||||
* * Uniform: Parameters denote maximal (symmetric) displacement from emitter position.
|
||||
* * Normal: Parameters denote the standard deviation in x and y direction. x and y are assumed to be uncorrelated.
|
||||
* @param x First parameter. Interpretation depends on distribution type.
|
||||
* @param y Second parameter. Interpretation depends on distribution type.
|
||||
* @param distribution Distribution type
|
||||
* */
|
||||
void setAreaSpread(AreaSpreadDistribution distribution, float x, float y);
|
||||
|
||||
/**
|
||||
* Sets the direction and the spread of the particle emitter.
|
||||
* @param direction The direction (in degrees).
|
||||
@@ -285,6 +308,16 @@ public:
|
||||
**/
|
||||
const love::Vector &getPosition() const;
|
||||
|
||||
/**
|
||||
* Returns area spread distribution type.
|
||||
*/
|
||||
AreaSpreadDistribution getAreaSpreadDistribution() const;
|
||||
|
||||
/**
|
||||
* Returns area spread parameters.
|
||||
*/
|
||||
const love::Vector &getAreaSpreadParameters() const;
|
||||
|
||||
/**
|
||||
* Returns the direction of the emitter (in degrees).
|
||||
**/
|
||||
@@ -357,6 +390,9 @@ public:
|
||||
* @param dt Time since last update.
|
||||
**/
|
||||
void update(float dt);
|
||||
|
||||
static bool getConstant(const char *in, AreaSpreadDistribution &out);
|
||||
static bool getConstant(AreaSpreadDistribution in, const char *&out);
|
||||
protected:
|
||||
|
||||
// The max amount of particles.
|
||||
@@ -386,6 +422,10 @@ protected:
|
||||
// The relative position of the particle emitter.
|
||||
love::Vector position;
|
||||
|
||||
// Emission area spread.
|
||||
AreaSpreadDistribution areaSpreadDistribution;
|
||||
love::Vector areaSpread;
|
||||
|
||||
// The lifetime of the particle emitter (-1 means infinite) and the life it has left.
|
||||
float lifetime;
|
||||
float life;
|
||||
@@ -439,6 +479,9 @@ protected:
|
||||
|
||||
void add();
|
||||
void remove(particle *p);
|
||||
|
||||
static StringMap<AreaSpreadDistribution, DISTRIBUTION_MAX_ENUM>::Entry distributionsEntries[];
|
||||
static StringMap<AreaSpreadDistribution, DISTRIBUTION_MAX_ENUM> distributions;
|
||||
};
|
||||
|
||||
} // opengl
|
||||
|
||||
@@ -172,7 +172,7 @@ std::string PixelEffect::getGLSLVersion()
|
||||
|
||||
bool PixelEffect::isSupported()
|
||||
{
|
||||
return GLEE_VERSION_2_0 && GLEE_ARB_shader_objects && GLEE_ARB_fragment_shader && getGLSLVersion() >= "1.2";
|
||||
return (GLEE_VERSION_2_0 || (GLEE_ARB_shader_objects && GLEE_ARB_fragment_shader)) && getGLSLVersion() >= "1.2";
|
||||
}
|
||||
|
||||
std::string PixelEffect::getWarnings() const
|
||||
|
||||
@@ -86,6 +86,24 @@ int w_ParticleSystem_setPosition(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setAreaSpread(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
|
||||
ParticleSystem::AreaSpreadDistribution distribution;
|
||||
const char *str = luaL_checkstring(L, 2);
|
||||
if (!ParticleSystem::getConstant(str, distribution))
|
||||
return luaL_error(L, "Invalid distribution: '%s'", str);
|
||||
|
||||
float x = (float)luaL_checknumber(L, 3);
|
||||
float y = (float)luaL_checknumber(L, 4);
|
||||
if (x < 0.0f || y < 0.0f)
|
||||
return luaL_error(L, "Invalid area spread parameters (must be >= 0)");
|
||||
|
||||
t->setAreaSpread(distribution, x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setDirection(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
@@ -273,6 +291,21 @@ int w_ParticleSystem_getPosition(lua_State *L)
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getAreaSpread(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
ParticleSystem::AreaSpreadDistribution distribution = t-> getAreaSpreadDistribution();
|
||||
const char *str;
|
||||
ParticleSystem::getConstant(distribution, str);
|
||||
const love::Vector &p = t->getAreaSpreadParameters();
|
||||
|
||||
lua_pushstring(L, str);
|
||||
lua_pushnumber(L, p.x);
|
||||
lua_pushnumber(L, p.y);
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getDirection(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
@@ -373,6 +406,7 @@ static const luaL_Reg functions[] =
|
||||
{ "setLifetime", w_ParticleSystem_setLifetime },
|
||||
{ "setParticleLife", w_ParticleSystem_setParticleLife },
|
||||
{ "setPosition", w_ParticleSystem_setPosition },
|
||||
{ "setAreaSpread", w_ParticleSystem_setAreaSpread },
|
||||
{ "setDirection", w_ParticleSystem_setDirection },
|
||||
{ "setSpread", w_ParticleSystem_setSpread },
|
||||
{ "setRelativeDirection", w_ParticleSystem_setRelativeDirection },
|
||||
@@ -390,6 +424,7 @@ static const luaL_Reg functions[] =
|
||||
{ "getX", w_ParticleSystem_getX },
|
||||
{ "getY", w_ParticleSystem_getY },
|
||||
{ "getPosition", w_ParticleSystem_getPosition },
|
||||
{ "getAreaSpread", w_ParticleSystem_getAreaSpread },
|
||||
{ "getDirection", w_ParticleSystem_getDirection },
|
||||
{ "getSpread", w_ParticleSystem_getSpread },
|
||||
{ "getOffsetX", w_ParticleSystem_getOffsetX },
|
||||
|
||||
Reference in New Issue
Block a user