Particle System new features

2 new Particle System Distribution types:

borderellipse - spawns new particles around the border of an elllipse shape defined by dx,dy
borderrectangle - spawns new particles around the border of a rectangle shape defined by dx, dy

New functions:

getAreaSpreadAngle()
getAreaSpreadIsRelativeDirection()
setAreaSpreadAngle(angle in radians)
setAreaSpreadIsRelativeDirection(boolean)

setAreaSpread(distribution, x, y, (optional)angle, (optional)isRelativeDirection)

- angle - defaults 0. In radians the angle to rotate the entire area spread distribution
- isRelativeDirection - defaults false. When false, particles will travel in the direction defined by setDirection(). When true, particles will travel away from the center of the area spread shape

Demo: http://i.imgur.com/sBQ9Xhr.png

The new angle parameter should address: https://bitbucket.org/rude/love/issues/1172

--HG--
branch : particle system new features
This commit is contained in:
lognz
2017-03-11 01:54:26 -06:00
parent 09b757f018
commit 0f99f261e0
3 changed files with 180 additions and 26 deletions
+78 -22
View File
@@ -66,6 +66,8 @@ ParticleSystem::ParticleSystem(Graphics *gfx, Texture *texture, uint32 size)
, emissionRate(0)
, emitCounter(0)
, areaSpreadDistribution(DISTRIBUTION_NONE)
, areaSpreadAngle(0)
, areaSpreadIsRelativeDirection(false)
, lifetime(-1)
, life(0)
, particleLifeMin(0)
@@ -122,6 +124,8 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p)
, prevPosition(p.prevPosition)
, areaSpreadDistribution(p.areaSpreadDistribution)
, areaSpread(p.areaSpread)
, areaSpreadAngle(p.areaSpreadAngle)
, areaSpreadIsRelativeDirection(p.areaSpreadIsRelativeDirection)
, lifetime(p.lifetime)
, life(p.lifetime) // Initialize with the maximum life time.
, particleLifeMin(p.particleLifeMin)
@@ -265,60 +269,77 @@ void ParticleSystem::initParticle(Particle *p, float t)
max = direction + spread/2.0f;
float dir = (float) rng.random(min, max);
// In this switch statement, variables 'rand_y', 'min', and 'max'
// are sometimes reused as data stores for performance reasons
float rand_x, rand_y;
switch (areaSpreadDistribution)
{
case DISTRIBUTION_UNIFORM:
p->position.x += (float) rng.random(-areaSpread.getX(), areaSpread.getX());
p->position.y += (float) rng.random(-areaSpread.getY(), areaSpread.getY());
rand_x = (float) rng.random(-areaSpread.getX(), areaSpread.getX());
rand_y = (float) rng.random(-areaSpread.getY(), areaSpread.getY());
p->position.x += cosf(areaSpreadAngle) * rand_x - sinf(areaSpreadAngle) * rand_y;
p->position.y += sinf(areaSpreadAngle) * rand_x + cosf(areaSpreadAngle) * rand_y;
break;
case DISTRIBUTION_NORMAL:
p->position.x += (float) rng.randomNormal(areaSpread.getX());
p->position.y += (float) rng.randomNormal(areaSpread.getY());
rand_x = (float) rng.randomNormal(areaSpread.getX());
rand_y = (float) rng.randomNormal(areaSpread.getY());
p->position.x += cosf(areaSpreadAngle) * rand_x - sinf(areaSpreadAngle) * rand_y;
p->position.y += sinf(areaSpreadAngle) * rand_x + cosf(areaSpreadAngle) * rand_y;
break;
case DISTRIBUTION_ELLIPSE:
rand_x = (float) rng.random(-1, 1);
rand_y = (float) rng.random(-1, 1);
p->position.x += areaSpread.getX() * (rand_x * sqrt(1 - 0.5f*pow(rand_y, 2)));
p->position.y += areaSpread.getY() * (rand_y * sqrt(1 - 0.5f*pow(rand_x, 2)));
min = areaSpread.getX() * (rand_x * sqrt(1 - 0.5f*pow(rand_y, 2)));
max = areaSpread.getY() * (rand_y * sqrt(1 - 0.5f*pow(rand_x, 2)));
p->position.x += cosf(areaSpreadAngle) * min - sinf(areaSpreadAngle) * max;
p->position.y += sinf(areaSpreadAngle) * min + cosf(areaSpreadAngle) * max;
break;
case DISTRIBUTION_BORDER_ELLIPSE:
rand_x = (float) rng.random(0, LOVE_M_PI * 2);
p->position.x += cosf(rand_x) * areaSpread.getX();
p->position.y += sinf(rand_x) * areaSpread.getY();
dir += rand_x;
min = cosf(rand_x) * areaSpread.getX();
max = sinf(rand_x) * areaSpread.getY();
p->position.x += cosf(areaSpreadAngle) * min - sinf(areaSpreadAngle) * max;
p->position.y += sinf(areaSpreadAngle) * min + cosf(areaSpreadAngle) * max;
// dir += rand_x + areaSpreadAngle;
break;
case DISTRIBUTION_BORDER_RECTANGLE:
// Unwraps rectangle border onto straight line and pick random point
rand_x = (float) rng.random((areaSpread.getX() + areaSpread.getY()) * -2, (areaSpread.getX() + areaSpread.getY()) * 2);
min = areaSpread.getY() * 2;
if (rand_x < -min)
rand_y = areaSpread.getY() * 2;
if (rand_x < -rand_y)
{
p->position.x += rand_x + min + areaSpread.getX();
p->position.y += -areaSpread.getY();
min = rand_x + rand_y + areaSpread.getX();
p->position.x += cosf(areaSpreadAngle) * min - sinf(areaSpreadAngle) * -areaSpread.getY();
p->position.y += sinf(areaSpreadAngle) * min + cosf(areaSpreadAngle) * -areaSpread.getY();
}
else if (rand_x < 0)
{
p->position.x += -areaSpread.getX();
p->position.y += rand_x + (areaSpread.getY());
max = rand_x + areaSpread.getY();
p->position.x += cosf(areaSpreadAngle) * -areaSpread.getX() - sinf(areaSpreadAngle) * max;
p->position.y += sinf(areaSpreadAngle) * -areaSpread.getX() + cosf(areaSpreadAngle) * max;
}
else if (rand_x < min)
else if (rand_x < rand_y)
{
p->position.x += areaSpread.getX();
p->position.y += rand_x - (areaSpread.getY());
max = rand_x - areaSpread.getY();
p->position.x += cosf(areaSpreadAngle) * areaSpread.getX() - sinf(areaSpreadAngle) * max;
p->position.y += sinf(areaSpreadAngle) * areaSpread.getX() + cosf(areaSpreadAngle) * max;
}
else
{
p->position.x += rand_x - min - areaSpread.getX();
p->position.y += areaSpread.getY();
min = rand_x - rand_y - areaSpread.getX();
p->position.x += cosf(areaSpreadAngle) * min - sinf(areaSpreadAngle) * areaSpread.getY();
p->position.y += sinf(areaSpreadAngle) * min + cosf(areaSpreadAngle) * areaSpread.getY();
}
dir += atan2(p->position.y - pos.getY(), p->position.x - pos.getX());
// dir += atan2(p->position.y - pos.getY(), p->position.x - pos.getX());
break;
case DISTRIBUTION_NONE:
default:
break;
}
// Determine if the origin of each particle is the center of the area
if (areaSpreadIsRelativeDirection)
dir = atan2(p->position.y - pos.getY(), p->position.x - pos.getX());
p->origin = pos;
min = speedMin;
@@ -555,6 +576,21 @@ void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x,
areaSpreadDistribution = distribution;
}
void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y, float angle)
{
areaSpread = love::Vector(x, y);
areaSpreadDistribution = distribution;
areaSpreadAngle = angle;
}
void ParticleSystem::setAreaSpread(AreaSpreadDistribution distribution, float x, float y, float angle, bool isRelativeDirection)
{
areaSpread = love::Vector(x, y);
areaSpreadDistribution = distribution;
areaSpreadAngle = angle;
areaSpreadIsRelativeDirection = isRelativeDirection;
}
ParticleSystem::AreaSpreadDistribution ParticleSystem::getAreaSpreadDistribution() const
{
return areaSpreadDistribution;
@@ -565,6 +601,26 @@ const love::Vector &ParticleSystem::getAreaSpreadParameters() const
return areaSpread;
}
void ParticleSystem::setAreaSpreadAngle(float angle)
{
this->areaSpreadAngle = angle;
}
float ParticleSystem::getAreaSpreadAngle() const
{
return areaSpreadAngle;
}
void ParticleSystem::setAreaSpreadIsRelativeDirection(bool isRelativeDirection)
{
this->areaSpreadIsRelativeDirection = isRelativeDirection;
}
bool ParticleSystem::getAreaSpreadIsRelativeDirection() const
{
return areaSpreadIsRelativeDirection;
}
void ParticleSystem::setDirection(float direction)
{
this->direction = direction;
+63 -2
View File
@@ -197,15 +197,50 @@ public:
* 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.
* * 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.
* * Normal: Parameters denote the standard deviation in x and y direction. x and y are assumed to be uncorrelated.
* * borderellipse: Parameter causes particle distribution around outside of ellipse
* * borderrectangle: Parameter causes particle distribution around outside of rectangle
* @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 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.
* * borderellipse: Parameter causes particle distribution around outside of ellipse
* * borderrectangle: Parameter causes particle distribution around outside of rectangle
* @param x First parameter. Interpretation depends on distribution type.
* @param y Second parameter. Interpretation depends on distribution type.
* @param distribution Distribution type
* @param angle Angle for the distribution to be rotated by
**/
void setAreaSpread(AreaSpreadDistribution distribution, float x, float y, float angle);
/**
* 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.
* * borderellipse: Parameter causes particle distribution around outside of ellipse
* * borderrectangle: Parameter causes particle distribution around outside of rectangle
* @param x First parameter. Interpretation depends on distribution type.
* @param y Second parameter. Interpretation depends on distribution type.
* @param distribution Distribution type
* @param angle Angle for the distribution to be rotated by
* @param isRelativeDirection whether to set direction of each particle to away from center
**/
void setAreaSpread(AreaSpreadDistribution distribution, float x, float y, float angle, bool isRelativeDirection);
/**
* Returns area spread distribution type.
**/
@@ -216,6 +251,30 @@ public:
**/
const love::Vector &getAreaSpreadParameters() const;
/**
* Returns the angle of the area distribution (in radians).
**/
float getAreaSpreadAngle() const;
/**
* Sets the angle of the area distribution
* @param angle The angle (in radians).
**/
void setAreaSpreadAngle(float angle);
/**
* Returns true if particles spawn relative to the center of the
* shape area or false if they will use the setDirection parameter
**/
bool getAreaSpreadIsRelativeDirection() const;
/**
* Sets if particles starting direction is away from the center of the
* area spread or the setDirection parameter
* @param isRelativeDirection boolean use relative direction from center
**/
void setAreaSpreadIsRelativeDirection(bool isRelativeDirection);
/**
* Sets the direction of the particle emitter.
* @param direction The direction (in degrees).
@@ -595,6 +654,8 @@ protected:
// Emission area spread.
AreaSpreadDistribution areaSpreadDistribution;
love::Vector areaSpread;
float areaSpreadAngle;
bool areaSpreadIsRelativeDirection;
// The lifetime of the particle emitter (-1 means infinite) and the life it has left.
float lifetime;
+39 -2
View File
@@ -197,7 +197,8 @@ int w_ParticleSystem_setAreaSpread(lua_State *L)
ParticleSystem *t = luax_checkparticlesystem(L, 1);
ParticleSystem::AreaSpreadDistribution distribution = ParticleSystem::DISTRIBUTION_NONE;
float x = 0.f, y = 0.f;
float x = 0.f, y = 0.f, angle = 0.f;
bool isRelativeDirection = false;
const char *str = lua_isnoneornil(L, 2) ? 0 : luaL_checkstring(L, 2);
if (str && !ParticleSystem::getConstant(str, distribution))
@@ -209,9 +210,11 @@ int w_ParticleSystem_setAreaSpread(lua_State *L)
y = (float) luaL_checknumber(L, 4);
if (x < 0.0f || y < 0.0f)
return luaL_error(L, "Invalid area spread parameters (must be >= 0)");
angle = (float) luaL_optnumber(L, 5, 0.0);
isRelativeDirection = luax_optboolean(L, 6, false);
}
t->setAreaSpread(distribution, x, y);
t->setAreaSpread(distribution, x, y, angle, isRelativeDirection);
return 0;
}
@@ -230,6 +233,36 @@ int w_ParticleSystem_getAreaSpread(lua_State *L)
return 3;
}
int w_ParticleSystem_setAreaSpreadAngle(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
float arg1 = (float)luaL_checknumber(L, 2);
t->setAreaSpreadAngle(arg1);
return 0;
}
int w_ParticleSystem_getAreaSpreadAngle(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
lua_pushnumber(L, t->getAreaSpreadAngle());
return 1;
}
int w_ParticleSystem_setAreaSpreadIsRelativeDirection(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
bool arg1 = luax_toboolean(L, 2);
t->setAreaSpreadIsRelativeDirection(arg1);
return 0;
}
int w_ParticleSystem_getAreaSpreadIsRelativeDirection(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
lua_pushnumber(L, t->getAreaSpreadIsRelativeDirection());
return 1;
}
int w_ParticleSystem_setDirection(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
@@ -720,6 +753,10 @@ static const luaL_Reg w_ParticleSystem_functions[] =
{ "moveTo", w_ParticleSystem_moveTo },
{ "setAreaSpread", w_ParticleSystem_setAreaSpread },
{ "getAreaSpread", w_ParticleSystem_getAreaSpread },
{ "setAreaSpreadAngle", w_ParticleSystem_setAreaSpreadAngle },
{ "getAreaSpreadAngle", w_ParticleSystem_getAreaSpreadAngle },
{ "setAreaSpreadIsRelativeDirection", w_ParticleSystem_setAreaSpreadIsRelativeDirection },
{ "getAreaSpreadIsRelativeDirection", w_ParticleSystem_getAreaSpreadIsRelativeDirection },
{ "setDirection", w_ParticleSystem_setDirection },
{ "getDirection", w_ParticleSystem_getDirection },
{ "setSpread", w_ParticleSystem_setSpread },