mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 },
|
||||
|
||||
Reference in New Issue
Block a user