Category Archives: MonoGame

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!

Advertisements

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 #31 – Attack Procedurals

In order to test the gameplay for Jetboard Joust I needed to start to thinking properly about how enemies are going to appear. Originally I was imagining that all enemies would spawn at the start of each level, however a few initial tests have led me to realise that that approach won’t work for two reasons 1) The player is too likely to become overwhelmed at the start of the level and 2) The difficulty of the level would tail off too much as enemies are destroyed.

So – in order for levels not to feel too ‘front-loaded’ I’m going to have enemies spawn in batches after a certain amount of time has elapsed, much like in Defender.

I also needed to think about the logic behind the choice of enemies in each level. As there will be an infinite number of levels in the game they will have to be procedurally generated somehow – my ideal scenario is to allocate a difficulty score for a level and have an algorithm allocate a spread of enemies that matches it without feeling too ‘random’.

The problem is complicated by the fact that many enemies are a combination of two factors, enemy type and weapon type – so allocating a simple difficulty score per enemy type won’t wash.

The solution I’ve come up with so far (which may well change) is as follows…

I have three separate enums WeaponTypes, EnemyRiderTypes and EnemyTypes. The two different enemy types represent ‘armed’ jetboard riding enemies and ‘standard’ enemies. The values allocated to each element in the enum represent a difficulty score, e.g…

I then have a new class EnemyDefinition which represents an enemy to which a difficulty score can be allocated. This could be either a standard EnemyType or a combination of an EnemyRiderType and WeaponType. EnemyDefinition also has a method EnemyDefinition.Create() that creates an instance of the enemy it defines.

At startup I automatically create a list of EnemyDefinitions which contains an entry for each EnemyType and for each possible EnemyRiderType/WeaponType combination – I store this in a static class EnemyRandomizer.

Now I have a static method EnemyRandomizer.CreateBatch() which takes a parameter for a total difficulty score and a parameter for the current level. This method creates a list of all EnemyDefinitions that are equal or less than the supplied difficulty score and chooses one of these at random. It then calls EnemyDefinition.Create() as many times as necessary to create enemies that total the supplied difficulty score and returns this ‘batch’ in a list.

When I originate a level I take a difficulty score based on the level number, split this into a series of ‘batch’ scores and then call EnemyRandomizer.CreateBatch() for each one – so a level with a difficulty score of 500 might have five separate batches with a difficulty score of 100 each. These ‘batches’ spawn at a preset time interval or when all existing enemies have been destroyed.

There’s a few extra complications such as making sure we don’t get ‘stray’ enemies and stuff but this is the basic approach and (for now) it seems to work OK. Hopefully it’ll prove robust enough to be used for the final game.

Dev Time: 0.5 days
Total Dev Time: approx 33 days

previous | next

mockup_3x
Oops – Rather Too Many Enemies!


Jetboard Joust Devlog #30 – Crossed Platforms

Porting From Mobile To PC with MonoGame
This week I was supposed to have started on the initial gameplay testing for Jetboard Joust but I came up against a rather nasty snag.I develop using Xamarin Studio on a Mac and had been using the GenyMotion Android emulator for my main testing platform. This probably seems strange given that my main target platform is PC, but GenyMotion generally runs extremely well and I don’t want to have to buy another machine just for development purposes. Unfortunately I discovered a problem with GenyMotion in that it seems to just ‘miss’ some keyup/keydown events. The problem is intermittent but bad enough to make serious gameplay testing on the platform impossible – no response from their support either.

That means I need another platform for testing. The iOS simulators are hopeless for graphics performance (and don’t respond to keyboard control as far as I’m aware), Google’s stock Android emulators take an age to launch/install builds and the Xamarin Android Player, though fast, is still pretty flaky. That left Xamarin.Mac as the only ‘native’ Mac option but there’s a hefty additional licence charge for that (or at least there used to be – I couldn’t quite work out what’s going on with Xamarin.Mac since the Microsoft buyout).

As a result of this tragic state of affairs (remember when Apple used to take x-platform development seriously in the initial OSX days?) I decided the only option would be to ditch Mac native and move to running Windows under VMWare Fusion (at least for any development that requires serious gameplay testing). Quite a change. I’ve done this before for ‘Attack Of Giant Jumping Man’ though so was optimistic that it should be a workable solution, plus I’d have to do the PC port anyway at some point – may as well get on with it.

So I started with a brand new Windows 8.1 VM and a fresh installation of Visual Studio 2015. I’ve been using MonoGame 3.2 up to this point but this was as good a time as any to update to 3.5. Installation of the various components was a breeze. I chose the DesktopGL target as it was most similar to the target I’d worked on for ‘Attack Of Giant Jumping Man’ (so hopefully the few bits of platform-specifc code I’d had to write could be re-used) and it didn’t take too long to get my project to compile. The only problem I ran into was that references to the Microsoft.Xna.Framework.GamerServices namespace couldn’t be resolved. For some reason the reference to the assembly that contains these wasn’t included in the MonoGame template project and had to be added manually (Add Reference->Extensions and then choose the appropriate MonoGame.Framework.Net assembly for the platform you are targeting, its a bit confusing as all the assemblies are named the same in the list so you have to click on each one to see more info).

I’m using the ‘shared folder’ feature of VMWare Fusion to share my source code directory between Mac and Windows – if I import the source files as links then both my Xamarin Studio projects on MacOS and my Visual Studio projects on windows both remain perfectly in sync – nice!

Next step is to import all the content – unfortunately I can’t figure out a way to keep all these files in sync as importing a file as a link from a shared folder doesn’t seem to work in the MonoGame pipeline tool. This is a bit of a bummer but not to much of an issue at the moment – hopefully I can figure something out eventually.

Only issue with the content was that I was getting an error when compiling my custom shader files due to a missing DirectX component (‘d3dcompiler_43.dll’) despite having DirectX 11 installed. I followed the instructions to fix this here (using the second method, not the full install) and all was fine.

So now everything would compile and run. Imagine my joy when, on launching, all I got was the garbage you can see in the GIF on the right. Complete gobbledegook. Spirits totally crushed. What. The. Hell.

I had absolutely no idea what was going on here and no idea where to start debugging. Nothing I thought of initially had any effect. Jetboard Joust runs on MEAT, my own (originally Java-based) 2D gaming platform that has been over ten years in development. MEAT is another layer of abstraction above MonoGame and fairly complex making it difficult to strip things down to MonoGame basics and do a few simple tests but this is clearly what I needed to do.

I decided to run a few simple MEAT tests first and see if I could get anything up and running…

1. Load image and draw sprite
2. Load image and draw sprite with clipping (as if from sprite sheet)
3. Load image and draw sprite with crop (MonoGame ScissorRectangle)
4. Load image, render to offscreen buffer (RenderTarget2D) and then to screen.

…all of these worked fine which was encouraging to an extent but didn’t get me any closer to a solution. However the next test produced some very strange results.

One of the MEAT classes is a graphical font class – a bitmap font and associated metrics data are stored in a single file which can be used to easily render bitmap text to screen. When I tried a test render using one of these graphical fonts the text would appear OK and then mysteriously disappear after around 30 seconds on screen. Bizarre. This mysterious disappearance only happened when my game template code (that handles all the main menus and stuff) had been executed at startup, ie at least 30 seconds before the problem occurred.

So all I could do was to comment out chunks of the game template code, launch the app, and then run a timer for approx 45 seconds to see if the font disappeared – an incredibly tedious process reminiscent of debugging on J2ME handsets. Eventually I narrowed it down to the line of code that was causing the problem – I was reassigning the property originally assigned to the graphical font that was drawn to screen to a different graphical font. Even though this was a mistake on my part there is absolutely nothing ‘wrong’ with this and it wasn’t causing a problem on any other platform. I had to test and retest several times to convince myself that this line of code was the problem but it was – as soon as I didn’t reallocate the property once the font was drawn to screen the test font didn’t disappear and the entire game ran perfectly!

All I can think of is this had something to do with garbage collection of graphics memory. Reallocating the property meant that the garbage collector (incorrectly) thought the memory should be freed which resulted in some kind of graphics meltdown. This would explain why it took around 30 seconds for the problem to appear – it only happened when the garbage collector kicked in. I create the font images using Texture2D.FromStream() rather than the Content.Load() methods in MonoGame which is slightly weird and could be something to do with it as well – I doubt this is as well tested as the Content.Load() methods.

Anyway, one can’t really blame the MonoGame team for missing such an obscure issue and even with the amount of time I wasted over this it was still a pretty fast cross-platform port so kudos to them. Android/iOS to PC in around a day with about 99% of the codebase consistent – not to be sniffed at! Nice to see the issues with the XBox controller fixed in MonoGame 3.5 too!

Dev Time: 1 days
Total Dev Time: approx 32.5 days

previous | next

mockup_3x
Where On Earth Do You Start To Debug This Shit?

Got There In The End – PC, Full Screen, XBox Controller

Jetboard Joust Devlog #18 -Enter The Warp Gate

Wasn’t working much on Jetboard Joust last week – had to do an ad-free update of Flapping Bird for a distributor (yes, I did a ‘Flappy Bird’ clone – the shame)!

Anyway – back onto it this week and I’ve been doing more custom shader stuff, this time for the ‘level complete/next level’ cycle. I wasn’t looking forward to this to be honest as I thought it would be a really fiddly process but actually it went OK.

What’s going to happen when the level is complete is that a kind of ‘warp gate’ appears – enter the warp gate and you get transported to the next level. I wanted the level to disintegrate into pixels in much the same way the main character does when teleported in/out (see previous post).

The first thing though was to actually design the warp gate itself. I wanted something that felt a little ‘sci-fi’ and also a little ‘primitive’ to fit in with the ruins. I looked at various things for inspiration, not least the ‘hub portals‘ from ‘Turok – Dinosaur Hunter’ on the N64 (remember that game, it was ace!) which hold very fond memories for me. This page of concept art from Destiny was also a big influence.

I wasn’t too tough to arrive at a design I liked – and animating it (though very time consuming) was also pretty trouble free. I then spent quite a bit of time tweaking some particle fx to go with it – trying to keep a ‘pixelly’ feel. I’m really pleased with the end result now.

Implementing the ‘pixel dissolve’ for the entire level meant using a custom shader for ‘post-render’ fx. This was another first for me but fortunately pretty simple to implement. Rather than drawing the game world to screen I draw it to an offscreen image (RenderTarget2D in MonoGame) and then apply the shader when rendering this offscreen image to screen. As if often the case with this stuff, the hardest part is tweaking the tweens so that the dissolve feels ‘right’. I think it’s OK now but there’s still something bugging me about the ‘fade in’ a bit. I used the same shader I wrote for the teleport fx as described in the previous post.

Then it’s a matter of sequencing everything together which I have now done, though this procedure is too long to get across in an animated GIF…

1. Complete level
2. Warp gate appears (using teleport shader) –
3. Enter warp gate
4. Main character teleports out
5. Old level dissolves out
6. New level dissolves in
7. Main character teleports in

If you’re being observant you’ll notice that I’ve made the particles on the player teleport rather more ‘pixelly’. I’ve also updated the die/retry loop from the pipes of old to a new version using the teleport effect.

Next up will be some work on pickups and changing jetboards.

Dev Time: 2 days
Total Dev Time: approx 20.5 days

previous | next

mockup_3x
The Final Warp Gate Design With Particles

mockup_3x
The Level Exit/Enter Dissolve Effect

mockup_3x
Entering The Warp Gate And Leaving The Level

Jetboard Joust Devlog #17 – Beam Me Up, Dotty

More going over old ground as the game starts to develop it’s own visual style. It’s annoying but necessary – one has to take an organic approach to these types of things I think. Really I should stick with placeholder art and work on the design almost completely separately from the gameplay (as if I was working with another artist) but I find it very hard to do that. Consequently I’ve wasted at least two or three days so far which is kind of frustrating. Hey ho!

Anyway, the latest thing to be redone is the new life/appear animation. I did have the main character being shot from a Mario-style pipe as you’ll see here but that didn’t really seem in character any more. I wanted something more spacey and in keeping with the feel of Defender which is my main inspiration for Jetboard Joust.

So I started work on a ‘teleport’ effect. I knew I wanted the main character to dissolve into a kind of pixelated fog and the most appropriate way to achieve this seemed to be through a custom shader – down the HLSL rabbit hole again.

I started by creating a shader that reduced the pixel resolution of the drawn texture. I split the texture into a series of chunks and took a sample from the centre of each chunk which was returned as the colour to draw. Having no HLSL experience it took a while just to get to this stage. I have all my animations on sprite sheets so each sprite drawn is generally a small portion of a much larger texture, HLSL works with coordinates relative to the full texture (regardless of the region being drawn) so initially the results I was getting were pretty random (when they weren’t completely blank) but when I figured out to pass the coordinates of the cropped region to the shader and do my calculations based on that instead things started to progress pretty quickly.

Initial results were promising (though somewhat static) and the effect looked like something I could progress with. I added some motion by sampling from a random point in each chunk rather than the center (I do this every other frame) and a kind of ‘spark’ effect by inverting the colour balance every so often (currently every four frames). I also added the ability to sample from a smaller portion of the texture than that being drawn, effectively scaling up the sprite. Then I added the ability to set the alpha for the entire shader allowing it to fade out smoothly.

We were getting there now! This was all the functionality I really needed from the shader and the next stage was setting up some tweens in my main game code to control the various parameters. There’s quite a few tweens chained together in the final result, one controlling the sample size, one the scaling and one the transparency. I wanted it to look like tuning into a radio station sounds with big adjustments at the start (no reception) and small ones at the end (finding the point of best reception).

Once I was happy with that I added some more particles, trying to keep things fairly stylised looking. A small change to the particle generator was required to allow for imploding particles. There’s also a pixel particle generator which blurs the edges of the actual texture (this looked a bit too obviously square at low sample sizes).

And now I think almost done. Only thing that’s really bugging me is the very dark pixels from the shader when they get large, these look a bit too glitchy (not in a good way). May have to knock these back a bit or something. And there’s something about the small explosion/implosion particles not quite sitting right with the larger pixels – I might need to make these particle fx more ‘pixelly’ somehow…

One HLSL thing that had me stumped for a while was that, whilst I was tweaking and commenting out bits of code, the C# code that set an effect parameter in the shader suddenly started throwing a null pointer exception indicating that that parameter was no longer present in the shader. WTF? Turns out that, though I hadn’t removed the parameter declaration in the shader, I’d removed all references to it in the actual code so the compiler was optimising it out (doh)!

It may also interest you to know that I did all this thinking ‘Defender’ had a similar ‘implosion’ effect when the player’s ship appears – but it turns out it doesn’t at all – neither does the sequel ‘Stargate’! Damn childhood memories deceiving me.

Dev Time: 0.75 days (including project setup)
Total Dev Time: approx 18.5 days

previous|next

mockup_3x
Attempt #1

mockup_3x
Attempt #2

mockup_3x
Attempt #3

mockup_3x
Attempt #4 – Almost Done(!)