Over a million developers have joined DZone.

Developing Snowfight - Basic particle engine

· Mobile Zone

Me and some other Microsoft Student Insiders started working on a game for Windows Phone 7 (XNA-powered, of course). After some brainstorming we decided to develop a game that will somewhat resemble the old-style Worms game, but at the same time we thought about adapting it to the winter season. So it’s going to be Snowfight – kids throwing snowballs at each other.

The project is hosted on CodePlex and you can check it out here.

The tasks were divided between team members and each of us was assigned a component. For now I am developing the particle system and I decided to share the way I approached the problem.

NOTE: This is a very basic implementation and I will be extending it along the way.

First of all, here is the structure I decided to use:

image

The super-class here is the particle manager that is able to manage multiple systems. A particle system can contain multiple particles and at the same time each particle can have individual properties that define it’s behavior.

For the basic “skeleteon”, I created a simple class structure separated in folders:

image

If you are interested in the actual class diagram before I explain each class separately, here it is:

image

BasicParticle here is the fundamental atom – the particle itself (self-explanatory). Its structure is defined by these properties:

public class BasicParticle
{
public Vector2 CurrentPosition { get; set; }
public Vector2 Velocity { get; set; }
public float Size { get; set; }
}

Notice that velocity is also defined by a vector in two-dimensional space that defines how fast the particle will be moving on the X and Y axes.

Now that there is a basic particle, it is time to combine them in a system. A system will be directly managing the particles that will be held in it. I started with a set of basic properties:

public class ParticleSystem
{
public int SystemID { get; set; }
public Texture2D Texture { get; set; }
public List<BasicParticle> Particles { get; set; }
private SpriteBatch SpriteManager {get; set;}
private Vector2 CenterPosition { get; set; }
}

The SystemID is the unique identifier that is later on used to identify the particle system in the particle manager. Multiple particle systems can be running simultaneously in a game – for example, it could be snowing and at the same time there is a snowball crashing in a tree breaking into multiple snow pieces. As you can see, in a single system for now I assume that all particles will have the same texture. Later on, it is most certainly possible to extend but for an “elementary” component, it is okay to put everything in one bucket.

Now, given the fact that particles can have different sizes and properties, I am adding them to a common collection that will be used to draw each one of them. The passed SpriteBatch instance will actually represent the drawing mechanism and the CenterPosition vector will represent where exactly the system will be placed on the screen.

In the constructor for the ParticleSystem class, I am requesting the user to specify some details:

  • What’s going to be the SpriteBatch?
  • What is the system ID?
  • Where to place the system initially?
  • What texture to apply to each particle?

Here is what it actually looks like:

public ParticleSystem(SpriteBatch SpriteManager, int SystemID, Vector2 CenterPosition, Texture2D Texture)
{
this.SystemID = SystemID;
this.Texture = Texture;
this.Particles = new List<BasicParticle>();
this.SpriteManager = SpriteManager;
this.CenterPosition = CenterPosition;
}

Cool stuff. For testing purposes, let’s fill the collection with a  number of basic particles right here in the constructor:

for (int i = 0; i < 200; i++)
{
BasicParticle particle = new BasicParticle();
particle.CurrentPosition = CenterPosition;
particle.Size = new Random().Next(128);
float randomX = (float)new Random().NextDouble() - 0.5f;
float randomY = (float)new Random().NextDouble() - 0.5f;
particle.Velocity = new Vector2(randomX,randomY);
Particles.Add(particle);
}

I’ll have exactly 200 particles created. The size is randomly generated, so is the velocity. Notice the fact that the velocity can also be negative  – I don’t want all particles moving in the same direction.

Once the foundation is set, it is time to draw the particles. For now, I decided to keep this task inside the manager that holds those:

public void StartDrawing()
{
SpriteManager.Begin();
foreach (BasicParticle particle in Particles)
{
SpriteManager.Draw(Texture, new Rectangle((int)particle.CurrentPosition.X, (int)particle.CurrentPosition.Y,
(int)particle.Size, (int)particle.Size), Color.White);
particle.CurrentPosition += particle.Velocity;
}
SpriteManager.End();
}

One flaw here is the fact that I am not defining dead particles. So even if one particle leaves the visible part of the screen, theoretically it will still be moving. When I am going to extend this part, I will make sure to neutralize those particles – either renew them or remove from the collection.

The particle manager (defined by the ParticleManager class) is right now the simplest element in the engine:

public class ParticleManager
{
private List<ParticleSystem> Systems { get; set; }
public void Initialize()
{
Systems = new List<ParticleSystem>();
}
public void AddSystem(ParticleSystem SystemToAdd)
{
Systems.Add(SystemToAdd);
}
public ParticleSystem GetSystem(int SystemID)
{
return (from c in Systems where c.SystemID == SystemID select c).FirstOrDefault();
}
} 

All it is able to do at the moment is initialize itself, add a new system to the collection and return a system that is searched by its ID. That would be the basic functionality.

Now, if you want to experiment with this engine, try doing this.

1) Declare an instance of Texture2D and ParticleManager in the main class:

image

2) Load the texture in the LoadContent method:

image

NOTE: Here I am using a simple 16×16 bitmap image of a red shape. You can load your own texture.

3) In the same method, initialize the ParticleManager instance and add a new system to it:

image

4) In the Draw method, find the needed system and start drawing it:

image

Now if you run the game (either on the emulator or on the phone), you should see results similar to this:

image

Due to the not-so-random mechanism, the shapes are flying in multiple directions, but not exactly around the center but rather on diagonal vectors. This will change once I will implement vector generation based on trig functions, but right now (to demonstrate the possible capabilities) this is what we have.

Topics:

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}