<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>luminance &#187; particles</title>
	<atom:link href="http://www.luminance.org/tag/particles/feed" rel="self" type="application/rss+xml" />
	<link>http://www.luminance.org/blog</link>
	<description>Programming and Game Development - Kevin Gadd&#039;s Blog</description>
	<lastBuildDate>Sun, 02 Oct 2011 00:15:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>GPU accelerated particles</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/07/08/gpu-accelerated-particles</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/07/08/gpu-accelerated-particles#comments</comments>
		<pubDate>Wed, 08 Jul 2009 21:01:15 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[hlsl]]></category>
		<category><![CDATA[particles]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=548</guid>
		<description><![CDATA[During this last week, some of the work I did was to optimize my particle system, since it was showing up consistently on my profiles and I was adding more and more particles to my environments. There are a few basic approaches you can take when trying to optimize code like my particle system. The [...]]]></description>
			<content:encoded><![CDATA[<p>During this last week, some of the work I did was to optimize my particle system, since it was showing up consistently on my profiles and I was adding more and more particles to my environments.</p>
<div class="video">
<object width="640" height="385" data="http://www.youtube-nocookie.com/v/vIXl9xFTd08&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/vIXl9xFTd08&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><param name="allowfullscreen" value="true" /></object>
</div>
<p>There are a few basic approaches you can take when trying to optimize code like my particle system.</p>
<ul>
<li>The fact that you have a large number of particles all behaving in the same way means that you can easily distribute the work of updating/rendering particles across multiple cores, as long as your data structures and libraries are set up correctly to handle it &#8211; so one option is to multithread your particle system.</li>
<li>The parallel-friendly nature of a particle system also means that it&#8217;s possible to offload much of the work involved in rendering particles directly to the GPU, and do it in a shader instead of on the CPU. This is almost always faster.</li>
<li>In fact, in many cases, you can even update your particles on the GPU, by storing their state in a texture or vertex buffer and having a shader run over all the particles and write their new state to another texture/buffer. You can then take the new state and feed it into another shader as input to render your particles.</li>
<li>And of course, you can always take the standard approach of brute-force optimization, by making your particle system as efficient as possible with the same basic algorithm.</li>
</ul>
<p><span id="more-548"></span></p>
<p>While I could have attempted to shift all the work onto the GPU, or make use of multiple threads, for now I decided to simply offload rendering work onto the GPU, because my profiles showed that I was spending a considerable amount of time handing particle system state off to the XNA SpriteBatch class. Reading the source code for SpriteBatch in Reflector shows that there are lots of tiny inefficiencies in its implementation when you&#8217;re trying to use it to render particles &#8211; it does a lot of work to handle state changes, texture sorting, and other considerations that do not apply when you have large batches of particles with identical parameters.</p>
<p>As an upside, rendering particles yourself using a shader makes it easier to distribute your updating and rendering logic across threads, because you can now generate vertex information for your particles in batches on multiple threads, before handing them to the GPU. When using SpriteBatch, you&#8217;re stuck because every SpriteBatch.Draw call requires synchronization.</p>
<p>Since this was my first time writing a HLSL shader, the process of moving from SpriteBatch to my custom shader was an interesting one. I ran into lots of little snags and ended up having to change my design multiple times along the way, and spent a little while experimenting with different rendering techniques to try and figure out which one performed the best. One particularly surprising conclusion was that small batches of vertices were much faster than large batches &#8211; initially, I was updating and rendering all my particles in a single batch, and then handing them all to the GPU at once.</p>
<p>I assumed that this would allow the driver and the GPU to crunch away on all the particles in the background while I moved on to doing other work on the CPU, but in practice, generating a small batch and handing it to the GPU while I work on the next batch is consistently faster on both the PC and the XBox 360. This is one of those cases where you might assume a code change will improve performance, but if you don&#8217;t benchmark and tune carefully, it can actually impair your game&#8217;s performance &#8211; disappointing if you just spent 8 hours hacking on something only to realize it was a bad idea.</p>
<p>The first step when implementing the shader for my particle system was to determine how to convert my particle system&#8217;s state into vertices for the shader to consume. There are a few factors that make this a bit of a challenge:</p>
<ul>
<li>In general, GPUs operate on collections of values &#8211; vectors and matrices &#8211; not individual values. This means you can&#8217;t just toss 16 uniquely named floats and integers into a vertex and get good performance; for ideal performance you need to pack groups of related values into vectors. This is straightforward for things like positions and velocities.</li>
<li>With a few exceptions, you need to send the GPU as many vertices as you want it to draw. This is a bit of a pain when dealing with a particle system, since you typically want to map one set of values (a particle) into 6 vertices for a textured quad that represents the particle. In some cases, you can utilize Point Sprite support to get the job done, but hardware point sprites are tremendously limited. This means you need to find an efficient way to transform each particle into 6 vertices.</li>
<li>Since you have to generate 6 vertices from each particle, you need to minimize redundant calculations &#8211; there are lots of calculations that the GPU is capable of doing, so you want to offload as many of them to the GPU as possible, so you can avoid doing them on the main CPU, where they cost significantly more.</li>
</ul>
<p>For my particle system, the state of a particle looks like this:</p>
<pre>    public struct Particle {
        public Vector2 Position;
        public Vector2 Velocity;
        public float Opacity;
        public float Scale;
        public float Rotation;
        public Color Color;
    }</pre>
<p>After some experimenting and thinking, the vertex format I ended up with looks like this:</p>
<pre>    public struct ParticleVertex {
        public Vector2 Position;
        public Vector3 Params; // Opacity, Scale, Rotation
        public Color Color;
        public short Corner;
        public short Unused;
    }</pre>
<p>So, to begin with, you&#8217;ll notice that I&#8217;m packing three unique values (opacity, scale, rotation) into a single vector. This is important because the vertex shader will only need to use one register to hold all three values, instead of needing a register for each individual value. I&#8217;m also separating the opacity value from the particle&#8217;s color, because combining the two values on the CPU is prohibitively expensive (mostly due to some stupid design decisions in the XNA framework, but I digress&#8230;), so I multiply out the alpha in the shader instead. The &#8216;Corner&#8217; value is used so the shader can determine which of the particle&#8217;s four corners are being shaded &#8211; this allows us to duplicate a given particle vertex six times to satisfy the video card&#8217;s desire for two triangles, by only changing the Corner. There&#8217;s also that strange looking &#8216;Unused&#8217; value there, which exists for a reason I&#8217;ll explain later.</p>
<p>Given the two formats, it&#8217;s relatively simple to write some code to transform from one to the other:</p>
<pre>Particle p = particles[i];
vertex.Position = p.Position;
vertex.Params.X = p.Opacity;
vertex.Params.Y = p.Scale;
vertex.Params.Z = p.Rotation;
vertex.Color = p.Color;</pre>
<p>Once you have a vertex for a given particle, then all you have to do is emit the vertices for each corner:</p>
<pre>for (short k = 0; k &lt; 4; j++, k++) {
    vertex.Unused = vertex.Corner = k;
    d[j] = vertex;
}</pre>
<p>You may notice that Unused has shown up again. Here&#8217;s why: Originally, I only populated the Corner field, and the shader worked perfectly &#8211; on my PC. On the XBox, it mysteriously rendered nothing. I finally realized that the XBox has a different byte ordering from my PC, since it&#8217;s a PowerPC-based chip instead of an x86 one. As a result, my shader was reading from Unused on the 360 instead of from Corner. As a simple solution, I just populate both fields, since I have to send them anyway (there&#8217;s no way to send a single byte or integer as part of a vertex).</p>
<p>You may also notice that I&#8217;m generating four vertices, not six. This is so that I can take advantage of a pre-generated index buffer and only send four vertices per particle to the GPU instead of six. The index buffer is really simple to generate:</p>
<pre>for (short i = 0, j = 0; i &lt; numVertices; i += 4, j += 6) {
    indices[j] = i;
    indices[j + 1] = (short)(i + 1);
    indices[j + 2] = (short)(i + 3);
    indices[j + 3] = (short)(i + 1);
    indices[j + 4] = (short)(i + 2);
    indices[j + 5] = (short)(i + 3);
}</pre>
<p>Once I have the vertex format set up, and I have code to generate vertices for my particles, the only hard parts remaining are to write a shader and set it up to be used by the game. The shader ends up being relatively simple &#8211; the only real complicated part is handling rotation:</p>
<pre>float2 TextureSize;
float2 Translation;
texture ParticleTexture;
float4x4 MatrixTransform;

sampler TextureSampler = sampler_state {
    Texture = (ParticleTexture);

    MinFilter = Linear;
    MagFilter = Linear;
    MipFilter = Linear;
};

const float2 Corners[] = {
    {-0.5f, -0.5f},
    { 0.5f, -0.5f},
    { 0.5f,  0.5f},
    {-0.5f,  0.5f}
};

void VertexShader(
    in float2 position : POSITION0, // x, y
    inout float4 color : COLOR0,
    in float3 params : POSITION1, // opacity, scale, rotation
    in int2 cornerIndex : BLENDINDICES0, // 0-3
    out float2 texCoord : TEXCOORD0,
    out float4 result : POSITION0
) {
    float2 corner = Corners[cornerIndex.x];
    texCoord = corner + Corners[2];
    float2 sinCos, rotatedCorner;
    corner *= TextureSize.xy;
    sincos(params.z, sinCos.x, sinCos.y);
    rotatedCorner.x = (sinCos.y * corner.x) - (sinCos.x * corner.y);
    rotatedCorner.y = (sinCos.x * corner.x) + (sinCos.y * corner.y);
    position.xy += (rotatedCorner * params.y) - Translation;
    color *= params.x;
    result = mul(float4(position.xy, 0, 1), MatrixTransform);
}

void PixelShader(
    inout float4 color : COLOR0,
    float2 texCoord : TEXCOORD0
) {
    color *= tex2D(TextureSampler, texCoord);
}

technique ParticleTechnique
{
    pass P0
    {
        vertexShader = compile vs_1_1 VertexShader();
        pixelShader = compile ps_1_1 PixelShader();
    }
}</pre>
<p>There are a few things at work here: We define a Sampler in our shader that represents the texture for our particles, and set the parameters that determine how the texture will be scaled and mipmapped. We also define some variables that can be set by the game at runtime to feed into the shader, along with a constant array that contains offsets for all four vertex corners. The array lets us map those integer corner indices to x/y coordinates easily, so we can convert four identical points into the corners of a quad.</p>
<p>The pixel shader doesn&#8217;t do anything of note, so I&#8217;ll just go over the vertex shader. First, we map the corner index into an xy coordinate pair, by looking it up in the constant array. Then, we read the rotation out of the parameters structure, and use sincos to generate a rotated version of the corner coordinate, so that the resulting quad for the particle is rotated appropriately (You could do this with a matrix multiply instead of individual arithmetic, but I&#8217;m too lazy. <img src='http://www.luminance.org/wordpress/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> ).</p>
<p>Finally, we combine the rest of the parameters: Add the location of the rotated corner to the particle&#8217;s centerpoint, scale it by the scale parameter, and then translate it by the position of the camera.</p>
<p>Once we&#8217;ve done that, we multiply the input color by the input opacity to generate the actual color for the particle, and apply our transform matrix to generate the actual position of the particle&#8217;s vertex. Note that the translation and rotation stages could be done here if we wanted, since we&#8217;re using a 4&#215;4 transform matrix. All in all, a relatively simple shader.</p>
<p>After adding the shader to my game&#8217;s content project and compiling it, I can load it up at runtime as an Effect, and apply it when I want to render particles. Of course, using it requires filling in the various constants with the right values so that the shader can generate particles at the right coordinates:</p>
<pre>Effect.CurrentTechnique = Effect.Techniques["ParticleTechnique"];
Effect.Parameters["TextureSize"].SetValue(new Vector2(Texture.Width, Texture.Height));
Effect.Parameters["ParticleTexture"].SetValue(Texture);
Effect.Parameters["Translation"].SetValue(Camera.ViewportPosition);</pre>
<p>Once we&#8217;ve set the constants, we&#8217;re ready to render some particles.</p>
<p>At this point, we have a relatively efficient GPU-accelerated particle system. There&#8217;s lots of room for improvement, but as-is this system is considerably faster than my previous SpriteBatch-based implementation. The fact that I&#8217;m generating vertices in arrays and handing them to the GPU directly also means that if I want to, I can improve my particle system to use multiple threads to do updating and rendering without much hassle, since I won&#8217;t need to add any sophisticated synchronization &#8211; I can just slice up the particle array into chunks and hand each chunk to a thread.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/07/08/gpu-accelerated-particles/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Platforms, particles and precision</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/02/13/platforms-particles-and-precision</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/02/13/platforms-particles-and-precision#comments</comments>
		<pubDate>Sat, 14 Feb 2009 06:07:44 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[particles]]></category>
		<category><![CDATA[platformer]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=269</guid>
		<description><![CDATA[Not a whole lot interesting to show for this week; mostly some performance adjustments and tuning changes. I spent a day or so wrestling with some weird floating-point accuracy issues. In one case, a routine I was using to convert a convex polygon into a list of triangles wasn&#8217;t working correctly in Release builds of [...]]]></description>
			<content:encoded><![CDATA[<p>Not a whole lot interesting to show for this week; mostly some performance adjustments and tuning changes.</p>
<p>I spent a day or so wrestling with some weird floating-point accuracy issues. In one case, a routine I was using to convert a convex polygon into a list of triangles wasn&#8217;t working correctly in Release builds of the game &#8211; rounding errors resulted in a point being represented as outside a triangle when it was actually right on the edge, which ended up causing the routine to iterate forever. (Whoops.)</p>
<p>After a little experimenting, I ended up changing all the variables in the point-in-triangle check routine to use double precision floats, which fixed my test case. Unfortunately, I&#8217;m still pretty sure that the routine is broken; doubling the precision just reduced the magnitude of the error. This is particularly annoying since I have had trouble with rounding errors in my collision detection routines in the past, and I still haven&#8217;t found a robust approach for deailng with those either. I suspect I&#8217;m going to have to spend a while reading up on techniques for reducing error. One upside is that I haven&#8217;t seen any rounding errors while running the game on the 360, so if all goes well I won&#8217;t ever have to debug PowerPC floating point error issues on my x86 development machine &#8211; my understanding is that PPC&#8217;s instruction set for floating point arithmetic is far less sensitive than the x86&#8242;s, so I&#8217;m hoping it won&#8217;t be a problem.</p>
<p>I also did a little bit of experimenting with improving the quality of particle effects in the game. I recently added a little effect that causes one-way barriers to emit sparks when their passable axis changes, so that the player&#8217;s attention is drawn to the change to avoid confusion in puzzles that rely on barriers. It was pretty, but it also made it obvious that sparks were flying through walls and other geometry, which looked kind of ridiculous. So, in order to address that, I did some work on making sparks not spawn inside of geometry, and making them able to bounce off walls. The end result looked a lot more convincing, but had some unfortunate performance consequences I haven&#8217;t managed to get a handle on yet &#8211; I spent an hour or two trying to optimize the code responsible for bouncing sparks off walls, and basically got no performance improvement out of it whatsoever; I suspect the profiling I did generated incorrect data for some reason.</p>
<p><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/DM-hSE0OBL4&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&amp;ap=%2526fmt%3D18"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/DM-hSE0OBL4&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&amp;ap=%2526fmt%3D18" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></p>
<p>Implementing support for sparks bouncing off walls involved some changes to the <strong>UpdateSpark</strong> routine, mostly the addition of an obstruction test using a new type of obstruction resolver:</p>
<pre>        protected bool UpdateSpark (ref SparkParticle particle, int index) {
            particle.Opacity -= 0.01f;

            _ParticleResolver.position = particle.Position;
            _ParticleResolver.velocity = particle.Velocity;
            _ParticleResolver.Reset();
            var result = ObstructionTest(_ParticleResolver, ObstructionFlags.Geometry);
            particle.Position = _ParticleResolver.resultPosition;
            particle.Velocity = _ParticleResolver.resultVelocity;
            if (result == null) {
                particle.Velocity.Y += 0.025f;
            }
            particle.Rotation = (float)(Math.Atan2(particle.Velocity.Y, particle.Velocity.X) + (Math.PI / 2.0f));

            return (particle.Opacity &lt;= 0.0f);
        }</pre>
<p>Fairly simple in concept; perform an obstruction test between the particle and nearby level geometry, and use that to determine the new position of the particle. The new resolver looks like this:</p>
<pre>
    internal class ParticleMotionResolver : ICollisionVisitor {
        public Vector2 position, velocity, resultPosition, resultVelocity;

        public void Reset () {
            resultPosition = position + velocity;
            resultVelocity = velocity;
        }

        public Bounds GetBounds () {
            return new Bounds(position, resultPosition);
        }

        public CollisionState VisitPolygon (Polygon poly) {
            Vector2 intersection;
            bool result = false;

            for (int i = 0; i &lt; poly.Count; i++) {
                var edge = poly.GetEdge(i);
                var normal = Vector2.Normalize(edge.End - edge.Start).Perpendicular();

                if (Geometry.DoLinesIntersect(position, resultPosition, edge.Start, edge.End, out intersection)) {
                    result = true;
                    velocity -= (intersection - position);
                    position = intersection;
                    Vector2.Reflect(ref resultVelocity, ref normal, out resultVelocity);
                    velocity = Vector2.Normalize(resultVelocity) * velocity.Length();
                    resultPosition = position + velocity;
                    if (velocity.LengthSquared() &lt;= 0)
                        return new CollisionState(true, true);
                }
            }

            return result;
        }

        public CollisionState VisitCollidable (ICollidable obj) {
            if (velocity.LengthSquared() &lt;= 0)
                return new CollisionState(true, true);
            else
                return CollisionState.True;
        }
    }</pre>
<p>Fairly straightforward, really: For every polygon within the particle&#8217;s bounding box, I test the particle&#8217;s velocity vector against the polygon&#8217;s edges, to see if the particle is going to intersect the edge. If it is, I move the particle so that it&#8217;s lying directly on the edge, and then compute a reflection vector so that I know which direction it&#8217;s going to bounce in. After that, I apply the particle&#8217;s remaining velocity (if any) to bounce it off the edge, and change its direction.</p>
<p>This new routine has the unfortunate side effect of revealing some of the rounding errors lurking in my code &#8211; sparks are able to slip through some curved surfaces since the triangles that make up their edges are so small. The end result was definitely an improvement regardless, though.</p>
<p>The last significant thing I worked on was getting moving platforms working correctly again. While moving platforms were one of the first things I implemented originally, A few weeks back I ended up taking them out because they didn&#8217;t make sense with my current collision detection model, and they were a constant hassle. Now that my collision detection is more sane, it was easy to adapt the existing code for doors to create a moving platform class that behaves more or less the way I want: You can grip onto the edges of moving platforms just like ledges without falling off; you can climb up onto them; you can ride them; etc. I had to do some tweaking here and there to ensure that you couldn&#8217;t ride moving platforms through geometry that&#8217;s supposed to obstruct you, and there are still some usability issues &#8211; right now the only way to control a platform&#8217;s movement is by writing complex vector expressions, which isn&#8217;t fun at all; good moving platforms really require a system for defining paths for them to follow, and that&#8217;s still on the todo list. Regardless, it&#8217;s nice to have platforms working again, since they&#8217;re an essential part of my arsenal for designing good puzzles.</p>
<p><object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/WvsOAJ9tygg&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&amp;ap=%2526fmt%3D18"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/WvsOAJ9tygg&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&amp;ap=%2526fmt%3D18" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/02/13/platforms-particles-and-precision/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple Particle Effects</title>
		<link>http://www.luminance.org/blog/gruedorf/2008/12/21/simple-particle-effects</link>
		<comments>http://www.luminance.org/blog/gruedorf/2008/12/21/simple-particle-effects#comments</comments>
		<pubDate>Sun, 21 Dec 2008 21:00:31 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[particles]]></category>
		<category><![CDATA[platformer]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=120</guid>
		<description><![CDATA[After doing some more tuning on the grappling hook, I decided to take a break and work on a particle system implementation. To handle various types of particle effects, I made a generic ParticleSystem class, where you can specify a particle type for the system to handle when creating it, along with a function to [...]]]></description>
			<content:encoded><![CDATA[<p>After doing some more tuning on the grappling hook, I decided to take a break and work on a particle system implementation.</p>
<p>To handle various types of particle effects, I made a generic <strong>ParticleSystem</strong> class, where you can specify a particle type for the system to handle when creating it, along with a function to handle updating the particle, and a texture to use for drawing it:</p>
<pre>public class ParticleSystem&lt;T&gt; where T : struct, IParticle {
    public delegate bool Updater (ref T particle, int index);</pre>
<pre>SmokeParticles = new ParticleSystem&lt;BasicParticle&gt;(SmokeTexture, UpdateSmoke);
SparkParticles = new ParticleSystem&lt;SparkParticle&gt;(SparkTexture, UpdateSpark);</pre>
<p>The <strong>IParticle</strong> interface contains all the properties the particle system needs to draw a particle. So, at runtime, to update and draw each particle system, I just call the appropriate methods:</p>
<pre>SmokeParticles.Update();

SpriteBatch.Begin(SpriteBlendMode.AlphaBlend);
SmokeParticles.Draw(SpriteBatch, ViewportPosition);
SpriteBatch.End();</pre>
<p>The updater function is responsible for updating every particle each frame, and also determines when it&#8217;s time for a particle to die and be removed.</p>
<pre>    protected bool UpdateSmoke (ref BasicParticle particle, int index) {
        particle.Scale += 0.05f;
        particle.Rotation += 0.025f;
        particle.Opacity -= 0.01f;

        return (particle.Opacity &lt;= 0.0f);
    }</pre>
<p>In my case, I made a couple assumptions that allow me to simplify things some:</p>
<ul>
<li> Particles don&#8217;t ever interact with each other.</li>
<li> Particles are not modified from outside the particle system after being created.</li>
</ul>
<p>As a result, I was able to make this optimization (among others):</p>
<p>To remove a &#8216;dead&#8217; particle, instead of having to use a potentially expensive method call like <strong>List.Remove</strong> or having to use a garbage-heavy data structure like a linked list, I can instead swap dead particles with the last live particle. Doing this moves the live particle forward in the list so that it will still get updated, and means that the last item in the list is now a dead particle &#8211; so all I have to do is reduce the particle count by one.</p>
<p>To integrate the particle system with the game, I wrote helper functions for &#8216;spawning&#8217; particle effects at a given location, like this:</p>
<pre>    public void SpawnSparks (Vector2 position) {
        var rng = new Random();
        Vector2 dir;

        for (int i = 0; i &lt; 24; i++) {
            dir.X = rng.NextFloat(-1, 1);
            dir.Y = rng.NextFloat(-1, 1);
            dir.Normalize();

            SparkParticles.Spawn(new SparkParticle {
                Position = position,
                Opacity = rng.NextFloat(0.40f, 0.60f),
                Velocity = dir * rng.NextFloat(1.66f, 2.66f),
                Color = new Color(rng.NextFloat(0.8f, 1.0f), rng.NextFloat(0.45f, 0.65f), rng.NextFloat(0.2f, 0.35f), 1.0f),
                Scale = 0.35f
            });
        }
    }</pre>
<p>This function does all the work of spawning a bunch of particles at the right location with randomized parameters, and the updater function does the work after that. The final bit of code goes in the grappling hook class:</p>
<pre>    this.Stopped = true;
    _Game.SpawnSparks(this.Position);</pre>
<p>The call to <strong>SpawnSparks</strong> spawns some spark particles at the location of the grappling hook when it first makes contact with a surface and stops.</p>
<p>After I got it working, I used it to add a few simple particle effects to go with some of the game mechanics already in the prototype. It definitely looks a bit nicer, and helps add a little more feedback for the player when doing things like performing a wall-jump.</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube.com/v/zbR90VU6cc0&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;ap=%2526fmt%3D18" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube.com/v/zbR90VU6cc0&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;ap=%2526fmt%3D18" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2008/12/21/simple-particle-effects/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

