• Advertisement
Sign in to follow this  

Circular explosion with definable points

This topic is 3001 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to find an algorithm that will allow me to create an explosion effect using particles in 2D. I'd like to be able to define the number of points - and have them evenly spaced around the circles center, and radiate out from there. I have one working now - but it only works if I use 360 points - if I use anything else, for example 90 points - then it only draws an arc. There are lots of circle functions, but they all seem to assume that you want to draw a full circle. Code in C would be great. Thanks

Share this post


Link to post
Share on other sites
Advertisement

void getParticlePositions(float _x, float _y, float _r, float segments)
{
float theta = 2 * PI / (float)segments;
float tangetial_factor = tanf(theta);
float radial_factor = 1 - cosf(theta);

float x = _x + _r;
float y = _y;

for (int i = 0; i != segments; i++)
{
float tx = -(y - _y);
float ty = x - _x);

x += tx * tangetial_factor;
y += ty * tangetial_factor;

float rx = _x - x;
float ry = _y - y;

x += rx * radial_factor;
y += ry * radial_factor;

particlePos.x = x;
particlePos.y = y;
}
}



If I use 360 segments, I get a full circle, if I use 180 segments, I get a semi-circle - not a circle with the points spaced further apart.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gibbon_99

void getParticlePositions(float _x, float _y, float _r, float segments)
{
float theta = 2 * PI / (float)segments;
float tangetial_factor = tanf(theta);
float radial_factor = 1 - cosf(theta);

float x = _x + _r;
float y = _y;

for (int i = 0; i != segments; i++)
{
float tx = -(y - _y);
float ty = x - _x);

x += tx * tangetial_factor;
y += ty * tangetial_factor;

float rx = _x - x;
float ry = _y - y;

x += rx * radial_factor;
y += ry * radial_factor;

particlePos.x = x;
particlePos.y = y;
}
}



If I use 360 segments, I get a full circle, if I use 180 segments, I get a semi-circle - not a circle with the points spaced further apart.


I dunno if you're just trying to be crazy or what.. but what's wrong with this?

void getParticlePositions(float _x, float _y, float _r, float segments)
{
float theta = 2.0f * PI / segments;

for (int i = 0; i != segments; ++i)
{
particlePos.x = _x + cos(i * theta) * _r;
particlePos.y = _y + sin(i * theta) * _r;
}
}

Share this post


Link to post
Share on other sites
with bzroom suggestion, you can vary the "++i" by : i += step_size, to still
get a full revolution and use less points, although don't vary it too much.

Share this post


Link to post
Share on other sites
Quote:
Original post by bzroom
I dunno if you're just trying to be crazy or what.. but what's wrong with this?

void getParticlePositions(float _x, float _y, float _r, float segments)
{
float theta = 2.0f * PI / segments;

for (int i = 0; i != segments; ++i)
{
particlePos.x = _x + cos(i * theta) * _r;
particlePos.y = _y + sin(i * theta) * _r;
}
}


That still doesn't draw a set of points, evenly spaced around a circle.

But this does.



void getParticlePositions(float _x, float _y, float _r, float segments)
{
float theta = 2.0f * PI / segments;
int stepSize = 360 / segments;

for (int i = 0; i != segments; ++i)
{
particlePos.x = _x + cos(i + stepSize * theta) * _r;
particlePos.y = _y + sin(i + stepSize * theta) * _r;
}

}



As long as I use a reasonable number of segments, I get a nice expanding circle of points from a central point.

If I use something like 10 segments, I get three in the top left diagonal, 4 in the top right diagonal, and three heading straight down.

Thanks !

Share this post


Link to post
Share on other sites
I still can't figure out what you're trying to do. :P

stepSize * theta is a constant, there's no need to compute its value twice per loop.

If what you're saying is correct. then:

void getParticlePositions(float _x, float _y, float _r, float segments)
{
float theta = 2.0f * PI * 360 / (segments * segments);

for (int i = 0; i != segments; ++i)
{
particlePos.x = _x + cos(i + theta) * _r;
particlePos.y = _y + sin(i + theta) * _r;
}
}


Aught to work just the same. Which is just silly and i have no explanation for.

Share this post


Link to post
Share on other sites

That works as well !

Thanks.

PS: To be a little more efficient I should setup a lookup table for the COS and SIN as well.

Would I be right in guessing that these calculations are resulting in a radian result?

How do you go about setting up a COS lookup table for radians. I would imagine that a degree lookup table would be something like double cosTable[360] - but I obviously can't use a radian as an index into that table.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gibbon_99

That works as well !

Thanks.

PS: To be a little more efficient I should setup a lookup table for the COS and SIN as well.

Would I be right in guessing that these calculations are resulting in a radian result?

How do you go about setting up a COS lookup table for radians. I would imagine that a degree lookup table would be something like double cosTable[360] - but I obviously can't use a radian as an index into that table.


Have you measured your performance and determined this to be a bottleneck? I think you may be focusing on too low of a level. I would be surprised if your implementation didn't already use lookup tables or some sort of fast numerical algorithm for trig functions.

Share this post


Link to post
Share on other sites
Quote:
Original post by CrimsonSun
Have you measured your performance and determined this to be a bottleneck? I think you may be focusing on too low of a level. I would be surprised if your implementation didn't already use lookup tables or some sort of fast numerical algorithm for trig functions.


It seems to be taking about 1.01% of the total frame rate to do the calculations on 45 points. Not much.

But - I plan on having a fair number of these 'explosions' happening at once on the screen.

It's written in plain C running on Linux - so I wouldn't think it would be using any sort of lookup tables already.

EDIT: found this

http://www.flipcode.com/archives/Fast_Trigonometry_Functions_Using_Lookup_Tables.shtml

Gives a nice speed boost - and plugs straight into the existing solution. WIN !

[Edited by - Gibbon_99 on December 1, 2009 11:30:22 PM]

Share this post


Link to post
Share on other sites
You don't need to compute cosine and sine over and over, or even look them up over and over. You just need to build a rotation matrix (requires one sine and one cosine of the angular increment) and then apply it over and over. Equivalently you can do this using complex numbers instead of matrices and vectors.

(Pseudo?)code:

void explode(nPoints)
{
dTheta = 2*PI/nPoints;
R = rotationMatrix2d(dTheta);

Vector2d p(1, 0);
for(int i=0; i < nPoints; ++i)
{
createExplosionParticleAtPoint(p);
p = R*p; // '*' here is overloaded to do matrix multiplication
}
}


where


[ cos(θ) -sin(θ) ]
rotationMatrix2d(θ) = [ ] .
[ sin(θ) cos(θ) ]


This kind of approach in other situations opens you up to nasty rounding problems, but given the number of particles per circle (< a few hundred, I'm guessing), the accuracy of the data types (floats I'm guessing; maybe doubles), and the purpose (graphics -- to look good) these won't accumulate fast enough to matter,

[Edited by - Emergent on December 2, 2009 7:29:38 PM]

Share this post


Link to post
Share on other sites
Not to nitpick, but i'm nit picking :)

nPoints = 2;
dTheta = 2*PI/(nPoints-1);

dTheta then equals 2*PI, rather than PI.

Share this post


Link to post
Share on other sites
Quote:
Original post by bzroom
Not to nitpick, but i'm nit picking :)

nPoints = 2;
dTheta = 2*PI/(nPoints-1);

dTheta then equals 2*PI, rather than PI.


Good call. Should be divided by nPoints, not nPoints-1. I'd used the number of segments between n points on a line segment (n-1) rather than on a circle (n). Edited my original code; fixed now.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement