Monthly Archives: June 2016

Optimising Memory Use In MonoGame

Don’t we all love the garbage collector in .net? It frees us from that irksome task of allocating and releasing memory ourselves and (virtually) eradicates memory leaks. Hooray for the garbage man!

Unfortunately there’s no such thing as a free lunch and all this ease of use comes with a performance penalty – and potentially quite a nasty one at that. Each time the garbage collector kicks in there’s a small CPU spike which can cause an inconsistent frame rate or the appearance of ‘juddering’ in your game.

The solution is to try and make sure as little garbage build up as possible and (if necessary) manually trigger collection at points in your game where there’s a natural pause, for example on losing a life or completing a level.

So, here’s a few tips on minimising the garbage… I welcome any feedback on any of these or any other suggestions.

1. Reuse and Recycle
Any game is bound to have a bunch of objects that are used and discarded on a regular basis. Sprites, rectangles, animations etc etc. Rather than creating and discarding these on an ‘as needed’ basis create a ‘pool’ of objects up front and retrieve and return them to the pool as required. This approach obviates the need for both memory allocation and garbage collection for the applicable objects in-game and can have a very positive impact on game performance.

Of course this approach comes with a development overhead, you are now (effectively) back to managing memory yourself and have to be very careful that you don’t attempt to re-use an object once it has been returned to the pool and re-initialized. These types of bugs can be very tricky to track down!

Below is the template I use for a simple generically-typed object pooling system consisting of an ObjectPool class and an IPoolable interface.

using System;
using System.Collections.Generic;

namespace com.bitbull.objectpool
{
	/*
	 * Any object that is to be pooled needs to implement this
	 * interface and support a parameterless constructor.
	 */
	public interface IPoolable
	{
		/*
		 Should reset all the object's properties to their default state.
		 */
		void Initialize();

		/*
		 Called when an object is returned to the pool. The implementation of 
		 this method doesn't need to do anything but it can be useful for certain
		 cleanup operations (possibly including releasing attached IPoolables).
		 */
		void Release();

		/*
		 Set by the pool and used as a 'sanity check' to check this object came from
		 the pool originally
		 */
		bool PoolIsValid
		{
			get;
			set;
		}

		/*
		 Used by the pool as a 'sanity check' to ensure objects aren't freed twice.
		 */
		bool PoolIsFree
		{
			get;
			set;
		}
	}
	/*
	  Template for a generically-typed object pool - pooled objects must
	  implement the IPoolable interface and support a parameterless constructor.

	  To create a new pool - ObjectPool pool = new ObjectPool(int initial_capacity)
	 */
	public class ObjectPool where T:IPoolable,new()
	{
		// I use a Stack data structure for storing the objects as it should be 
		// more efficient than List and we don't have to worry about indexing 
		private Stack stack;
		// The total capacity of the pool - this I only really use this for debugging
		private int capacity;

		/*
		 Creates a new object pool with the specifed initial number of objects
		 */
		public ObjectPool( int capacity )
		{
			stack=new Stack( capacity );

			for( int i=0; i<capacity; i++ )
			{
				AddNewObject();
			}
		}

		/*
		 Adds a new object to the pool - ideally this doesn't happen very often 
		 other than when the pool is constructed
		 */
		private void AddNewObject()
		{
			T obj=new T();
			obj.PoolIsValid=true;
			stack.Push( obj );
			capacity++;
		}

		/*
		 * Releases an object from the pool - note that there's no real need 
		 * to throw the first exception here as if an object is freed twice it's not
		 * really a problem, however the fact that this is happening usually indicates 
		 * an issue with one's memory management that could cause issues later so I 
		 * prefer to leave it in.
		 */
		public void Release( T obj )
		{
			if ( obj.PoolIsFree )
			{
				throw new Exception( "POOL ("+this+"): Object already released " + obj );
			}
			else if ( !obj.PoolIsValid )
			{
				throw new Exception( "POOL ("+this+") Object not valid " + obj );
			}
			obj.Release();
			obj.PoolIsFree=true;
			stack.Push( obj );
		}

		/*
		 * Retrieves an object from the pool - automatically create a new object if the pool
		 * has become depleted.
		 * 
		 * Calls Initialize() on the released object which should set all its parameters to
		 * their default values.
		 */
		public T Get()
		{
			if (stack.Count==0)
			{
				AddNewObject();
			}
			T obj=stack.Pop();
			obj.Initialize();
			obj.PoolIsFree=false;
			return obj;
		}
	}

}

2. Don’t Create Temporary Objects
Avoid the temptation to do stuff like this in your code (and I don’t mean the ridiculously long variable names)…

public void SomeMethod()
{
	FooBar some_temporary_object_needed_for_a_calculation = new FooBar();
	//
	// Do some stuff that needs a temporary FooBar object 
	//
	return;
}
Instead (providing your code is thread safe) make the FooBar object a ‘scratch’ class variable (so it persists for the life of the containing object) or even better a static variable (so that it persists for the lifespan of your app). Note that I don’t think there’s really any point in doing this with temporary structs as their creation/disposal is relatively trivial compared to that of classes.
private static FooBar foobar_scratch;

public void SomeMethod()
{
	//
	// Do some stuff with the 'scratch' FooBar object 
	//
	return;
}

3. Stack ‘Em Up
If you have objects that are not being pooled (because it’s too much effort or whatever) consider adding them to a Stack on creation and only emptying the stack at a point where there’s a natural pause in the game. Note that you have to watch your overall memory use with this approach as you have basically, albeit deliberately, created a massive memory leak! Only really suitable for small objects or those that aren’t created that regularly.

4. Avoid Using SetRenderTarget()
Even though it’s used in most examples SetRenderTarget() creates a bunch of garbage and should be avoided. Use SetRenderTargets() instead (even if you have only one). There’s more information on this (and some other cool tips) here.

5. Overload Your SpriteBatcher
When running some diagnostic tools on Jetboard Joust I realised that there was a bunch of wasted memory generated by the MonoGame SpriteBatch class. It seems that for every render an array is created to the size of the number of ‘draw’ operations to be executed. Whilst this array persists to an extent (much like the Collections classes a new array is only created if the old one doesn’t have enough capacity) when the amount of render operations can increase and vary considerably (for example with particle systems) you have, potentially, an awful lot of memory allocation and retrieval going on.

The solution I’ve tried for this (which appears to work) is simply to hammer your SpriteBatch with a load of render operations the first time around to ensure that an array is created that’s big enough to cover most scenarios.

6. Watch Those Strings
Though you wouldn’t think it, strings are a common cause of memory problems – particularly where there’s string concatenation involved (as there is in most debug calls). There appears to be an especially JNI-related nasty memory ‘leak’ (ie tons of garbage getting created) involving strings in the MonoGame Android implementation (though it’s deep in OpenTK rather than in the MonoGame code per se).

Be particularly wary of ‘debug’ type calls where your debug string may still be being created even if it’s not being output!

Building An Optimised Particle System In MonoGame

I’ve spent the last few days optimising the performance of ‘Jetboard Joust’ and one of the key components of this has been the particle system which is integral to the game’s visual style.

Over the course of doing this I’ve had to think a lot about the way my particle system is designed and have ended up changing it an awful lot to get the most out of performance and usability.

There are a bunch of tutorials on how to build a simple particle system out there, some of them very good, but none of them approach things in quite the way I did so I thought it would be worth sharing where I ended up. As my code is quite tied in to other aspects of my gaming APIs it’s difficult to share the source itself so this post will focus on the overall design and approach rather than the specific implementation. I welcome feedback on things I could do better and other optimisation suggestions. First some general tips…

Avoid Garbage – Recycle
Particle systems generate a lot of objects and memory allocation and deallocation is a very performance-intensive task, particularly when there’s a garbage collector involved as there is in C#. Therefore I allocate as many particle objects as I think I’m going to need at startup and reuse them rather than throwing them away. I use linked lists to manage a list of unused/used particle and emitter objects. Linked lists are much more efficient than array-based lists when allocating additional capacity and inserting and removing objects from the middle of the list making them ideal for this type of task. I use my own simple linked list implementation with each particle and emitter having a pointer to the previous and next one in the list but the generic C# LinkedList implementation is probably just as efficient and a lot easier to debug.

Don’t Switch Textures
Keep all your particles as part of the same texture atlas/sprite sheet so they can be rendered in one batch by the GPU. Switching textures is very performance intensive. If you are using a ‘layered’ 2D drawing approach make sure all your particles are drawn at once, ie you don’t have other sprites intermingled between them which would mean another texture needs to be passed to the GPU.

Pre-Calculate Tweens
If you are using relatively expensive tween based algorithms (particularly ones based on trigonometry) pre-calculate these so they are not having to be calculated per particle per frame. I explain how I manage this in the overall design description as it is not entire straightforward. Generally using tweens looks a lot better than simple linear transforms – I intend to share some tweening code in a later post.

Cull Where Possible
If you are likely to have a lot of offscreen particles don’t pass these to the GPU to be drawn each frame but don’t make an intersection check for each particle. Again, finding the most efficient way to do this is not straightforward but I explain my approach in the design description. Culling ‘invisible’ particles before they are passed to the GPU will also likely mean you can avoid unnecessary calculations for tweens on scale/opacity etc.

Scroll down for a breakdown of the classes I use and design approach and please get in touch via Twitter with any questions or comments…

mockup_3x
Constructivist Northern Lights

mockup_3x
Fun With Scaling And Rotation
ParticleEmitterState
This class represents a ‘snapshot’ of the parameters that apply to any particle emitter. Many tutorials bundle these parameters in with the emitter itself so don’t have a separate ‘state’ object. I find the separate state object makes it much easier both to to manage multiple emitters that have the same appearance and to recycle emitter objects.
namespace com.bitbull.particles
{

	public class ParticleEmitterState
	{
		/*
		 Sets up the state object with some sensible default values 
		 */
		public ParticleEmitterState();

		/*
		 Called once the first time MaxParticleFrames, ParticleFrames or TweenValues is requested.
		
		 This method allocates a float[] the size of MaxParticleFrames and pre-calculates a tween value from 1.0
		 to 0.0 for each frame. These tween values could be thought of as the 'energy' of the particle and are often
		 used to calculate a particle's opacity, rotation or scale.
		
		 An exception will be thrown if either ParticleDuration or ParticleDurationDeviation are set after this has
		 been called making these the only properties that are more-or-less 'immutable' once a state has been set up.
		 */
		private void Initialize();
		
		/*
		Returns a float[] the size of MaxParticleFrames containing a tween value from 1.0 to 0.0 for each frame. These 
		tween values could be thought of as the 'energy' of the particle and are often used to calculate a particle's
		opacity, rotation or scale.
		
		If a TweenAlgorithm has not been set this method returns null and tweening is ignored for this particle.
		
		Read only.
		*/
		public float[] TweenValues;

		/*
		The maximum lifespan of a particle in frames. Read only.
		*/
		public int MaxParticleFrames;
		
		/*
		The minimum lifespan of a particle in frames. Read only.
		*/
		public int ParticleFrames;

		#region particleproperties

		/*
		 Start velocity of particles
		 */
		public float Velocity;
		
		/*
		 Amount of random deviation from start velocity per particle.
		 Particle velocity will run from Velocity-VelocityDeviation/2 to velocity+VelocityDeviation/2 
		 */
		public float VelocityDeviation;

		/*
		 Amount of spawn deviation from emitter centre along the x-axis.
		 Particles will spawn from 0-SpawnDeviationX/2 to 0+SpawnDeviationX/2 
		 */
		public float SpawnDeviationX;
		
		/*
		 Amount of spawn deviation from emitter centre along the y-axis.
		 Particles will spawn from 0-SpawnDeviationY/2 to 0+SpawnDeviationY/2 
		 */
		public float SpawnDeviationX;

		/*
		 Distance of particle from emitter centre on the x-axis before deviation is applied
		 */
		public float SpawnRadiusX;

		/*
		 Distance of particle from emitter centre on the y-axis before deviation is applied
		 */
		public float SpawnRadiusY;

		/*
		 Whether to reverse velocity (implode) on the x axis 
		 */
		public bool ReverseVelocityX;

		/*
		 Whether to reverse velocity (implode) on the y axis
		 */
		public bool ReverseVelocityY;

		/*
		 Start angle of particle spread.
		 */
		public float StartAngle;

		/*
		 End angle of particle spread.
		 */
		public float StopAngle;

		/*
		 Colour of particle
		 */
		public Color Tint;

		/*
		 Some kind of representation of the texture that is to be drawn for the particle - will 
		 most likely be an encapsulation of an Image and a source rect for the area of the image
		 that is to be drawn. 
		 */
		public Drawable Texture;

		/*
		 Overall velocity of particle is multiplied by this per frame. In most cases particles will
		 deccelerate as they lose energy so this will be less than 1.0. 
		 */
		public float Acceleration;

		/*
		 Added to horizontal velocity of particle per frame - single unit vector component between 0 and 1
		
		 In most particle systems this will be zero as gravity tends to pull straight down! 
		 */
		public float GravityX;

		/*
		 Added to vertical velocity of particle per frame - single unit vector component between 0 and 1

		 In most particle systems this will be 1.0 as gravity tends to pull straight down!
		 */
		public float GravityY;

		/*
 		 Amount of gravity added per frame, effectively the 'velocity' of the vector [GravityX,GravityY]
		 */
		public float Gravity;

		/*
		 Lifespan of each individual particle.
		 Trying to set this property once Initialize() has been called will throw an exception.
		 */
		public TimeSpan ParticleDuration;

		/*
		Random variance in lifespan of each individual particle.
		Particles will live from from 0-ParticleDuration/2 to 0+ParticleDuration/2 
		*/
		public TimeSpan ParticleDurationDeviation;
		
		/*
		Some kind of representation of a tweening algorithm to be used for particle 'energy'. 
		*/
		public Tween.TweenAlgorithm TweenAlgorithm;

		/*
		Base opacity of particle.
		*/
		public float Opacity;
		
		/*
		Random variance in opacity of each individual particle.
		*/
		public float OpacityDeviation;
		
		/*
		Change in particle's opacity based on the 'energy' of the particle.
		*/
		public float OpacityTweenAmount;
		
		/*
		Base rotation of particle.
		*/
		public float Rotation;
		
		/*
		Random variance in rotation of each individual particle.
		*/
		public float RotationDeviation;
		
		/*
		Change in particle's rotation based on the 'energy' of the particle.
		*/
		public float RotationTweenAmount;

		/*
		Base scale of particle.
		*/
		public float Scale;
		
		/*
		Random variance in scale of each individual particle.
		*/
		public float ScaleDeviation;
		
		/*
		Change in particle's scale based on the 'energy' of the particle.
		*/
		public float ScaleTweenAmount;
	}

}

Particle
This class represents an individual particle. Typically you will end up with thousands of these being active at any one time so it’s very important that any code executed in the Update() and Draw() methods is as efficient as possible.

Most particle properties are set by the emitter and therefore ‘baked in’ when a particle is emitted, however I maintain a pointer back from each individual particle to a ParticleState object for things like gravity and the array of tween values.

To allow for the fact that there is deviation in the amount of frames each particle lives for I maintain a float value per particle for a ‘tween frame’ and the amount this ‘tween frame’ is incremented per frame (State.MaxParticleFrames/Particle.DurationFrames). At each Draw() call the ‘tween frame’ float is casted to an int so that the appropriate value can be retrieved from State.TweenValues. I don’t like doing this cast every time but it’s the only method I can think of that ensures each particle can move smoothly from maximum to minimum pre-calculated tween values whatever its duration.

using System;

using com.bitbull.meat;
using com.maturus.multipacks.generic;
using com.maturus.genericarcade;

namespace com.bitbull.particles
{
	public class Particle
	{
		/*
		Creates a new particle
		*/
		internal Particle();
		
		/*
		Sets this particle moving based on the supplied ParticleEmitterState
		*/
		internal void Activate( ParticleEmitterState state );
		
		/*
		Draws the particle on the specified graphics object relative to the specified x and y values.
		
		This method should also perform any 'per frame' calculations that can be skipped if the particle
		is offscreen and therefore doesn't need to to be drawn, for example scaling an opacity tweening.  
		*/
		public void draw( float x, float y, Graphics g );

		/*
		Updates the X and Y location of the particle based on its velocity and state gravity.
		
		Increments a frame counter and returns false if the particle has reached its allocated lifespan.
		
		Any 'per frame' calculations that need to be carried out whether or not the particle is 
		visible should also be carried out here, for example increasing or decreasing velocity based
		on acceleration. 
		*/
		internal bool update();
		
		/*
		X Location of particle
		*/
		public float X;
		
		/*
		Y Location of particle
		*/
		public float Y;
		
		/*
		Horizontal velocity component of particle (single unit vector) 
		*/
		public float VX;
		
		/*
		Vertical velocity component of particle (single unit vector) 
		*/
		public float VY;
		
		/*
		Current velocity of particle (ie length of vector [VX,VY]) 
		*/
		public float Velocity;
		
		/*
		Frames elapsed since particle was emitted
		*/
		public int Frame;
		
		/*
		Particle lifespan in frames
		*/
		public int DurationFrames;

		/*
		Initial scale of particle
		*/
		public float Scale;
		
		/*
		Initial opacity of particle
		*/
		public float Opacity;
		
		/*
		Initial rotation of particle
		*/
		public float Rotation;
	}
	
}

ParticleEmitter
This class represents something that emits particles according to a particular ParticleEmitterState. Emitters are managed by a ParticleSystem and each emitter maintains a pointer back to its ‘parent’ ParticleSystem as well as a linked list of particles emitted that are still active.

Each emitter can be set to emit a certain amount of particles for a certain amount of frames and to do this for a number of iterations with a defined pause between each iteration.

An emitter remains active until all the particles it has emitted have expired.

Each emitter has it’s own onscreen location relative to which its particles are drawn – this enables emitters to track another sprite’s movement which is often very useful.

using System;

namespace com.bitbull.particles
{
	public class ParticleEmitter
	{
		/*
		Creates a new particle emitter
		*/
		public ParticleEmitter();
		
		/*
		Sets the parent ParticleSystem for the emitter and resets location
		*/
		public void Activate( ParticleSystem p );
		
		/*
		Forces the emitter to deactivate all currently active particles, set its
		state to non-permanent, and call DeactivateEmitter() on the parent ParticleSystem
		*/
		public void Flush();
		
		/*
		Iterates through and calls Update() on every active particle.
		
		If a particle's Update() call returns false it is deactivated. 
		*/
		public void UpdateParticles ();
		
		/*
		Iterates through and calls Draw() on every active particle.
		
		Active particles are drawn relative to the emitter's own x,y location 
		*/
		public void DrawParticles ( float x, float y, Graphics g );
		
		/*
		Deactivates the supplied particle by removing it from the list of active 
		particles and adding it to the parent ParticleSystem's list of inactive particles
		*/
		public void DeactivateParticle( Particle p );

		/*
		Emits an individual particle based on the parameters in the supplied ParticleEmitterState.

		Particles are not instantiated here but retrieved from the list of inactive particles 
		in the parent ParticleSystem using ParticleSystem.RetrieveParticle()
		
		This method calculates initial x, y, scale, rotation and opacity values for the particle
		as well as the particle's duration in frames based on the 'deviation' parameters set in 
		the ParticleEmitterState.  
		*/
		public void EmitParticle( ParticleEmitterState state );

		/*
		Emits n_particles_per_frame particles for n_frames for n_iterations iterations with frames_pause
		frames pause between each iteration.
		*/
		public void EmitParticles( ParticleEmitterState state, int n_particles_per_frame, int n_frames, int n_iterations, int frames_pause  );

		/*
		Immediately emits the specified amount of particles 
		*/
		public void AddParticles( ParticleEmitterState state, int n );
		
		/*
		Calls UpdateParticles and emits as many particles as necessary this frame.
		
		If the list of active particles is empty and we have no more particles to emit and IsPermanent is
		false calls DeactivateEmitter() on the parent state.
		*/
		public void update();

		/*
		When set to true this emitter will not automatically be deactivated once all particles are emitted.
		*/
		public bool IsPermanent;

		/*
		 Origin of emitted particles on the x-axis
		 */
		public float OriginX;

		/*
		 Origin of emitted particles on the y-axis
		 */
		public float OriginY;

		/*
		Location of emitter on the x-axis
		
		This is different from OriginX in that all particles are drawn relative to LocationX whereas
		OriginX only specifies the location at which new particles appear
		*/
		public float LocationX;
		
		/*
		Location of emitter on the y-axis
		
		This is different from OriginY in that all particles are drawn relative to LocationY whereas
		OriginY only specifies the location at which new particles appear
		*/
		public float LocationY;

	}

}

ParticleSystem
This class is responsible for maintaining a linked list of inactive Particle objects as well as active and inactive ParticleEmitter objects.

The list of inactive Particle objects is static and thus shared across multiple ParticleSystems.

In many situations there is only the need for one ParticleSystem – however in games with large scrolling worlds a ParticleManager can be used which maintains several different ParticleSystem objects and ‘culls’ any that don’t need to be drawn to screen thus improving performance.

Another reason to maintain different ParticleSystems would be to manage the order in which different particle effects are drawn as there is no control of the draw order of ParticleEmitter objects within any one ParticleSystem.

using System;

namespace com.bitbull.particles
{
	public class ParticleSystem
	{
		/*
		The amount of inactive particles to be created at startup
		
		A count is maintained of how many particles are created - if the value set here
		exceeds this amount then additional particles are created as soon as the value
		is set.
		*/
		public static int InitialCapacity;
		
		/*
		Creates a particle and adds it to the list of inactive particles
		*/
		private static void CreateParticle();
		
		/*
		Creates a new particle system
		*/
		public ParticleSystem ();

		/*
		Iterates through and calls Flush() on all active ParticleEmitter objects
		*/
		public void Flush();
		
		/*
		Retrieves a ParticleEmitter object from the list of inactive emitters.
		
		If none are available a new one is created. 
		*/
		public ParticleEmitter RetrieveEmitter();
		
		/*
		Retrieves an emitter and then calls ParticleEmitter.EmitParticles() with the supplied parameters
		*/
		public void EmitParticles( ParticleEmitterState state, float x, float y, int n_particles, int n_frames, int n_iterations, int frames_pause );
		
		/*
		Immediately adds the specified number of particles at the specified location based on the supplied ParticleState
		*/
		public void AddParticles( ParticleEmitterState state, float x, float y, int n );
		
		/*
		Returns the supplied ParticleEmitter object to the list of inactive emitters 
		*/
		public void StashEmitter( ParticleEmitter emitter );

		/*
		Iterates through and calls Update() on all active emitters
		*/
		public override bool update();

		/*
		Iterates through and calls Draw() on all active emitters
		*/
		public override bool drawToScreen (float h, float v, Graphics g);
		
		/*
		Returns the specified particle to the list of inactive particles
		*/
		internal void StashParticle( Particle p );
		
		/*
		Retrieves a particle from the list of inactive particles - this method is only called by
		ParticleEmitter.EmitParticle() so, once retrieved, a particle is always added to the list
		of active particles in a ParticleEmitter. 
		
		If no inactive particles are available a new one is created.
		*/
		internal Particle RetrieveParticle();
	}
}

ParticleSystemManager
This class is used by games with a scrolling play area to manage offscreen culling of particles.

Maintaining a boundary rectangle for each ParticleEmitter would require numerous calculations per frame. Even though these would be relatively ‘cheap’ >< comparisons the amount of them required (potentially many thousands per frame) makes this an ineffective approach.

My solution is more 'fuzzy'. I split the overall play area into a grid of ParticleSystem objects. Each ParticleSystem is assigned an 'emit' rectangle (standard grid coordinates) and an 'overlap' rectangle. The 'overlap' rectangle is larger than the 'emit' rectangle by an amount specified programatically. This overlap needs to be at least as large as the maximum necessary draw radius of any ParticleEmitter so a little trial and error may be needed to find the ideal value

Any ParticleSystem whose 'overlap' rectangle doesn't intersect the screen area at draw time can be safely culled, potentially eliminating a huge amount of particles with one simple Rectangle.Intersects() call.

The only real drawback of this method (apart from the fact that it requires a little trial and error to set up) is that it's only really good for particle emitters that are stationary. In practice though I've found that either using ParticleSystemManager.AddParticles and/or having a separate ParticleSystem for moving emitters to work fine.

using System;

namespace com.bitbull.particles
{

	public class ParticleSystemManager
	{
		/*
		Creates a new ParticleSystem manager to cover the specified world Rectangle broken
		down into a separate ParticleSystem for each 'cell' and with the specified overlap
		between each cell.
		
		Overlap should be at least as much as the radius of the largest particle effect.
		*/
		public ParticleSystemManager( Rectangle world, int cols, int rows, float overlap );

		/*
		Calls AddParticles() on the ParticleSystem that contains the specified x and y values.
		*/
		public void AddParticles( ParticleEmitterState state, float x, float y, int n );
		
		/*
		Calls EmitParticles() on the ParticleSystem that contains the specified x and y values.
		*/
		public void EmitParticles ( ParticleEmitterState state, float x, float y, int n_particles, int n_frames);

		/*
		Iterates through and calls Update() on all ParticleSystems
		*/
		public override bool update ();
		
		/*
		Iterates through all particle systems and calls Draw() on the ones whose bounding 
		rectangle + overlap intersects the screen. 
		*/
		public override bool drawToScreen (float h, float v, Graphics g);

		/*
		Calls Flush() on all ParticleSystems
		*/
		public void Flush();

	}
}

Jetboard Joust Devlog #35 – Abductions & Mutations

Now we have our alien babies it’s time to make something horrible happen to them – seems cruel but this is a videogame right?

First step was to get the enemies to abduct them. This was rather harder than I thought as it required some reasonably complex changes to the AI in order to get the ‘chasing baby’ code to play nice with the ‘chase player’ code. Picking up ‘cargo’ in Jetboard Joust is more complex than in Defender as the terrain in Jetboard Joust can be interacted with whereas in Defender it’s just for show.

I didn’t really run into any issues I hadn’t come up against already when writing the ‘chase player’ code though so thankfully I could pretty much reuse the techniques I’d come up with there and blogged about earlier.

One thing I have implemented in order to get things to look vaguely ‘realistic’ is an ‘aggro range’ parameter for the enemies. This is the range within which enemies will actively chase the player – outside of the aggro range enemies will idle or attempt to abduct babies(!) When the aggro range is activated it becomes larger so the player must run a certain distance away from the enemy in order for it to go back to ignoring them.

If an enemy is in the process of abducting a baby the aggro range is shorter, however if the player shoots the enemy or strays too close it will still go on the offensive.

Another issue with the abductions was having the baby ‘jump’ to the middle of the board when picked up. In order to make this look decent I had to implement some code to check whether the enemy had passed ‘through’ the baby at the last update. This raised another issue though in that if a baby ended up positioned right next to a building it was impossible for the enemy to pass ‘through’ it – this was a pretty rare occurrence but impossible to avoid so I’ve implemented a necessary hack for these situations where a ‘pass through’ is not necessary. The baby jumps slightly but it’s better than it being impossible to pick up.

Next step – design a mutant! This was fun and I’m pleased with the results, I didn’t take me too long either. For inspiration I had in mind Space Invaders (of course), Cthulhu, and the aliens from District 9. The mutant animates slightly differently to other board-riding enemies but it wasn’t too tough to get this working OK – I’d already set the relevant methods up so they were easy to override.

Fortunately the actual transformation happens offscreen so this part of the sequence was very easy! Part of me thinks I should do some kind of onscreen transformation – or will that look a bit odd?

Dev Time: 1 day
Total Dev Time: approx 37.5 days

previous | next

mockup_3x
Stay Away From My Babies!!

mockup_3x
Babies Aren’t So Cute When They Grow Up

mockup_3x
Mutation!!

Jetboard Joust Devlog #34 – Making Babies

I’ve been thinking for a while that the basic ‘destroy all enemies’ objective in Jetboard Joust was a bit too one-dimensional and that I needed to add something to give the gameplay a bit more depth.

The obvious source to look for inspiration was Defender, to which Jetboard Joust is pretty much a homage, so look to Defender I did!

In Defender you protect these little coloured blob things which get carried off by a certain type of enemy. If an invader manages to get a blob to the top of the screen it mutates and becomes a lot more dangerous. I thought I may as well go the whole hog with the Defender homage thing and replicate this scenario – maybe I could have the player protecting radioactive cannisters which enemies carry off and then use to mutate themselves?

This seemed to make sense to I went about designing some radioactive ‘cargo’. Unfortunately, despite my best efforts, it was shit! The little cannisters were OK but drawing a decent radiation symbol in about 5×5 pixels proved beyond my abilities, and the cannisters on their own just looked too boring. Time to rethink!

According to the Wikipedia page for Defender the little coloured blobs that you defend are, in fact ‘astronauts’ (not that you’d guess it from just playing the game). This triggered a memory of them being referred to as ‘humanoids’ in the original game instructions (though i could be wrong about this).

Something with a bit more character seemed a good idea so I thought I’d go about designing the most basic ‘humanoid’ form I could in as few pixels as possible and see if that would work. What I came up with kind of looked like a baby version of ET so I thought – what if you were protecting alien babies? This seemed to make sense! Babies are inherently something that warrants protecting, they look cute and have character, and having them carried off by aliens has overtones of the whole alien abduction/conspiracy thing which I liked.

So now I have alien babies! I created a little ‘idle’ sequence for them and a ‘panic’ animation for when they’re abducted. I think they’re pretty cute! Glad I was so bad at drawing radiation canisters! Now to work on their abduction…

Dev Time: 1 day
Total Dev Time: approx 36.5 days

previous | next


Alien Babies – Panic Animation


Alien Babies – Idle Sequence

Jetboard Joust Devlog #33 – Game On!

It’s always a great moment in the development of a game when the game actually starts to feel like a game, rather than a prototype, tech demo, or a bunch of animated GIFs on Twitter.

Thankfully I’ve now reached that stage on Jetboard Joust and have been able to spend the last couple of days refining gameplay rather than tweaking visuals or adding basic functionality – and I’m pleased to say that, considering it’s still early stages, it’s playing fairly well and has the old-school arcade feel I’d hoped for.

So now I’ll bore you with the kind of refinements I’ve been making over the last couple of days – some major, some pretty minor…

The Jump Attack
This was the really major change. It became obvious whilst testing that the ‘jump attack’ (which I’ve sometime previously referred to as the ‘weaponised jetboard’) was far too powerful and needed to be ‘nerfed’ in some way. I’ve settled for limiting the amount of jump attacks the player can do which seems to work well and is a solution I like because it’s somewhat akin to the smart bombs in Defender.

So there’s now ‘ammo’ for the jump attack which is represented by a new rocket icon in the HUD – enemies also drop extra rockets occasionally when destroyed (see the last post for more on that saga).

I was going to use the ‘jump attack’ as the basic attack when the player runs out of ammo but had never been entirely happy with this idea as I was worried that the transition from button-mashing ‘fire’ to fire a weapon to something that required a more judicious button treatment would be too jarring. I now have a separate button for ‘fire weapon’ and for ‘jump’ which works much better – the only disadvantage is that it will make the control system more complex on touchscreen devices. Those are low-priority for me at the moment though.

Ammo
It was far too easy to run out of ammo so I’ve upped the initial capacity of the pistol to 24 shots. This will be expandable via weapon upgrades. It’s still pretty easy to run out of ammo but I like the gameplay aspect of having to dive down to retrieve the mini-ammo pickups all the time, it adds a ‘survival’ element which is unusual for SHMUPs but I think works nicely. It will have to be well balanced though.

Health
I’ve added mini-health pickups as an additional occasional drop when enemies are destroyed. I felt I need something smaller than the ‘bubble’ health pickup which recharges you to full health (at least at the start of the game, the player’s max health level may be able to be upgraded).

Pickup Balancing
The algorithm that decides which pickups are dropped is ‘intelligent’ to a degree in that if the player is very low on health or rockets it is more likely to drop these items (though there is still a limit on the frequency at which these appear). I’ve done this type of thing in other games and like the result as it leads to plenty of moments where you are just ‘saved by a pickup’ which leads to more of an ‘edge of the seat’ feel – playing on the players ‘gambling response’.

Pickup balancing is going to be very important to gameplay. I’ve also added the more powerful ‘bubble’ pickups which, so far, appear after a certain number of enemy ‘batches’ have been released.

Pickup Timeouts
The ‘mini pickups’ now have a timeout attached so they don’t hang around forever. This is particularly important for the coins which otherwise could all be left for the player to scoop them up easily when the level was complete. Consequently coins have a relatively short timeout, whereas ammo, health and rockets i can afford to have hang around rather longer.

Enemy Frequency
This is another key thing to get right – so far the game seems to work better if smaller enemy batches are released frequently rather than large batches less frequently. In a previous post I talked about allocating enemies based on a difficulty score – I have also added something that prevents additional enemy batches from being released if the enemies currently in-game exceed a certain difficulty threshold. This prevents the user from becoming ‘swarmed’ by enemies which was becoming a bit of a problem.

Enemy Clustering
This one’s still on the ‘to do’ list but I need to add some variation to the speed and acceleration of the same type of enemy so they don’t end up ‘clustering’ too much which has a tendency to happen at the moment. I will probably also add some variation to the timing of their AI decisions.

Those are the main fixes – I’ve also fixed a ton of minor bugs and made a load of other minor improvements. Next step is to finish the initial set of gameplay tweaks and then start to look at optimising performance, particularly in regards to the way the ‘world wrap’ is handled.

Dev Time: 2 days
Total Dev Time: approx 35.5 days

previous | next



mockup_3x
Enemies Now Drop Mini Health Pickups