Category Archives: Development

Jetboard Joust Devlog #41 – Bombs Away

Really glad to be working on some new enemy types after wading through what seemed like an endless sludge of audio design and bugfixes! Feels like I’m finally making proper progress again.

I’m calling this enemy the ‘bomber’ – very much inspired by its namesake in Defender of course. I started by designing an enemy that was visually similar to the Defender bomber, a kind of robotic cube thing, but just couldn’t get anywhere with this. It seemed too devoid of personality compared to the other enemies in the game. I then tried designing a more humanoid robot with a jetpack but couldn’t get this to work within the restricted colour palette and resolution either. A fairly frustrating start.

Eventually I thought I’d try something with wings, I was originally thinking of a cross between a robot and a WW2 bomber, kind of like the planes in 1942, but as I started drawing it morphed into this sort of robotic angel which I liked – it reminds me of Antony Gormley’s ‘Angel Of The North‘. Added some particles too of course!

I wanted to keep the AI as simple as possible so settled on a simple algorithm that moves in alternate horizontal and vertical bursts towards the player. If contact is made with a building the sprite moves upwards until it is above the level of the building, thus freeing it to move left and right.

Surprisingly this straightforward algorithm worked OK, I was afraid the enemy would get stuck in endless loops against buildings if the player remained stationary and it did – but this was easily resolved by adding some randomness to the amount of movement in each ‘burst’.

The bomber drops bombs in its stationary phase between each burst of movement. The bombs are actually more like mines in that they float in the same place rather than fall to the floor – I added a small amount of oscillation to make the floating more interesting and a ‘warning’ vibration before the bomb detonates.

And that was pretty much it – there’s a few more subtle things going on like the damage inflicted by a bomb being proportional to how far the player is away from it but I won’t bore you with too many details. Now on to the next enemy…

Dev Time: 2 days
Total Dev Time: approx 56.5 days

previous | next


Probably The Final Bomber Animation


Planting Bombs – Still Looking A Bit Static


Making The Bombs Interact With The Player

Jetboard Joust Devlog #40 – Bits and Bugs

Tidying up some loose ends that were annoying me before I can (finally!) start work on some new enemy types!

1. Fixed ‘Invisible JetBoard’ Bug
If the player destroyed an enemy whilst it was teleporting in the enemy’s jetboard would remain static and invisible in the world. Fixed this so that a teleporting enemy’s jetboard drops down properly.

2. Cropped Jetboard Bug
This one had been ‘bugging’ (groan) me for some time, it appeared that enemy jetboards were getting randomly cropped on occasion for no apparent reason. Turned out that it was a crop at all but the board wasn’t always orientating correctly when the enemy changed direction.

3. Particles Going Weird On Level Exit
You can see this issue at the end of the video here. To get the level transform effect I render the entire world to a back buffer and then apply a custom shader when rendering to screen – turns out that optimisations I made to my particle system meant I was rendering direct to screen all the time and ignoring the back buffer (oops).

4. Various ‘End Of Life’ Bugs
There were various problems to do with a player getting killed when already dead and controls still operating the jetboard when the player was dead – these were largely to do with the fact that enemies continue shooting at the player even when he’s already dead ‘just to make sure’. I like this though, it’s funny, so I kept it and fixed the bugs.

5. Disallow Enemy Abductions/Mutations When Player Dead
Not really a ‘bug’ per se but I didn’t like the fact that enemies could carry on abducting babies and mutating when the player couldn’t do anything about it – it didn’t seem ‘fair’ somehow. Now they just hover when the player is in the ‘lost life’ state which, though it doesn’t make logical sense, seem to work from a gameplay perspective.

6. Add Floating Scores
I just like these and nearly always put them in my games – something very old school arcade’ about them.

7. Improve AI In Small Gaps
Enemies were doing some pretty stupid things when the player took cover in a gap between two buildings. This was the result of an algorithm I wrote to calculate the closest building to the player which didn’t work properly, and part of the AI which tries to move away from the player if overlapping (ie avoid ‘kamikaze’ style behaviour). Now, when in a small gap, the enemy should move to the edge of the building that’s furthest from the player, turn around and start firing. It’s tricky to get this stuff right and fixing this took a while!

8. Improve Message Font
This was probably the bulk of the work. Previous in-game messages appeared on the scanner – I didn’t like this for two reasons; it got in the way of the action on the scanner and it necessitated the use of a very small font which made the messages unclear. Double fail. I have moved messages to the main game area which seems to work OK, designed a custom bitmap font for them based on the font I’m using for the HUD (but smaller), and also added ‘impact shader’ effects. Still a bit worried about them getting in the way of the action but actually it seems to work OK (I tried placing them over the ‘ground’ at the bottom of the screen as well but this didn’t seem to work so well).

Dev Time: 2.5 days
Total Dev Time: approx 54.5 days

previous

mockup_3x
Enemies Now Act More Sensibly In Small Gaps

mockup_3x
Added Floating Scores When Enemies Are Destroyed

mockup_3x
Designing A Custom Bitmap Font For In-Game Messages

mockup_3x
Adding Impact Effects To In-Game Messages

Jetboard Joust Devlog #37 – Shake, Rattle & Roll!

I’d been thinking for a while that I needed a slightly more visceral feel to the collisions in Jetboard Joust, particularly when the main character crashes into the terrain but also when he’s taking damage from enemies.

So I’ve spent the last couple of days working on this by applying three different effects, the amount of each effect applied depends on the strength of impact (ie the speed the player is travelling or amount of damage taken) and is tweened back to zero over a short period of time, roughly 0.25 seconds. The three effects are as follows…

1. Scanner Distortion
It didn’t make sense to me that the scanner display should remain pristine when you’re taking a pummeling. Though the scanner is part of the HUD I imagine it as being embedded in the player’s helmet or something so it should appear to suffer as the player does whilst still maintaining enough legibility to make the game playable. I’ve achieved this by applying a ‘pixelator’ type shader that is based on my ‘teleport’ shader with a few changes. As well as changing the amount of pixelation based on the strength of impact I also add a small amount of brightness and noise which gives the impression of old-school CRT interference.

2. Camera Shake
This effect has become so much a staple of indie games that it’s almost a cliché by now but, what the hell – it looks good! Applying the effect was a bit more complex than I thought as it needs the appearance of randomness without being genuinely random (because a genuinely random shake can appear to stick at times). My final approach was to take a {1,0} vector, rotate pseudo-randomly, and then multiply the camera offset by the strength of impact on the x and y axis. For the pseudo-random rotation I always rotate by at least 90deg from the last ‘shake’ and then add another random amount between 0 and 180deg, this gives the appearance of randomness but always ensures there’s a ‘whole lot of shaking going on’. I also keep track of the ‘static’ camera position so that the ‘shaken’ position is always offset from the ‘static’ position and you don’t get a ‘brownian motion’ type effect with the camera movement which would upset the standard camera taking of the player.

3. Impact Shader
This was the effect that took the longest to get right. In my head I wanted an effect applied to the terrain that was kind of a cross between ‘double vision’ and the ‘vibration lines’ you might see on static illustrations to give the impression of movement. I also wanted the effect to look a bit glitchy.

First step was, whilst the effect was in progress, render the entire terrain to an offscreen image rather than rendering directly to screen. The shader could then be applied to the entire terrain rather than each individual component of it which would be both inefficient and cause visual issues.

I then started by applying a shader that simply rendered the whole terrain in a flat colour with some scaling distortion applied, the scaling varying according to strength of impact. I found I had to apply this shader three times in order to get the ‘double vision’ effect on the top, left and right of each building.

I then tried applying some raster lines to the effect and found this looked best if I applied horizontal raster lines when the shader was distorting vertically and vice versa. This gave a ‘vibration line’ effect around the buildings.

Next I tried randomizing the amount of scaling every x pixels – so there would be more distortion at certain, regular, points. This gave a ‘spiky’ effect to the shader that I thought looked pretty cool.

Lastly I varied the amount of scaling distortion on each axis based on the direction of the player’s travel and also added a certain amount of pixelation, again dependent on the direction of travel. I’m pretty pleased with the effect now though it has taken a hell of a lot of tweaking to get this far. No doubt I won’t be able to resist tweaking it some more either!

Dev Time: 1.5 days
Total Dev Time: approx 44 days

previous | next

mockup_3x
One Of The First Impact Shader Attempts


Something A Little More Subtle


Adding Raster Lines For A ‘Shake’ Effect


Adding Scaling Spikes


Final (No Chance!) Impact Shader, Scanner Distortion & Camera Shake

Jetboard Joust Devlog #36 – What A Performance!

It’s been a while since the last devlog but I haven’t been idle, I decided that before I could start tweaking gameplay again (now that we have abductions and mutations) I should make sure that everything was running as fast and as smooth as possible.

The main performance tweaks involved a bunch of changes to the particle engine which pretty much necessitated a complete refactoring of this part of the game code. This took several days and, whilst I know I have further optimisations to do, the result is an architecture that’s much more flexible and seems to run very well to boot. It could still be improved though. As this was kind of a generic topic I wrote a separate post on it here.

Other performance tweaks involved various memory optimisations, particularly implementing object pooling for commonly used objects. Again, as this was a pretty generic topic I wrote a separate post on it here.

The last thing to be optimised was collision detection and for the record I’ll list the main optimisations I made below. Though these are pretty specific to the way the gameplay and game physics work in Jetboard Joust they could be applied to a bunch of 2D games.

1. Ignore The Real World
Jetboard Joust implements a pretty simple physics model but it is still a physics model – therefore anything that exists in the game world is treated as being constantly under the influence of gravity (ie always falling) unless ‘pushed’ up by another object. This means that a collision check has to be run each frame for each object against any other object that might get in its way. Even though I use a segmented approach for the terrain this can still prove expensive.

When I ran my first diagnostic tests I was shocked to see that around 8.5% of the CPU time in my update loop was taken up by collision detection on the ‘pickup’ items (there are a lot of these created in the game and they can hang around a long time). As these pickup items are stationary most of the time this was clearly a complete waste of cycles!

So what I did was effectively disable the physics on the pickup items once they have come to rest. I can get away with this because I know that once they have come to rest the object on which they rest won’t be removed at any point – all that can happen to them is that they get picked up by the player or disappear if they hang around too long.

This simple optimisation took the CPU useage for this section of the code down to around 0.23% – a pretty hefty saving!

2. Apply Basic Logic, Stupid!
The next chunk of cycles were eaten up by collision detection on the enemies against the terrain. There were a couple of simple optimisations I could make here. Firstly I now keep a record of the highest point the terrain reaches when the level is constructed, if an enemy is higher than this point (as they often are) I know I don’t need to bother checking against the terrain at all. Similarly, if an enemy is travelling right I know I don’t need to bother checking against the right side of terrain objects and the same for the other directions.

3. Cache Me If You Can
I have my own Rectangle class that I use in my code and there were quite a few key places where I was using Rectangle.Width/2, Rectangle.Height/2. I replaced these with a HalfWidth and HalfHeight property that is cached and only updated when the Width or Height of the Rectangle is set – this has potentially saved me many thousands of division calculations per frame.

The game seems to be maintaining close to a 60fps framerate now in most situations though the fact I’m testing on a virtual PC running on a seven-year-old Mac Pro makes it kind of hard to tell for sure. I get occasional juddering but I think this is due to running on an emulated OS.

Oh yeah, I also decided that having the enemy mutations happen offscreen was kind of a cop out (as well as being annoying gameplay-wise) so we now have onscreen mutations!

Dev Time: 5 days
Total Dev Time: approx 42.5 days

previous | next

mockup_3x
Enemy Mutations Now Happen Onscreen

Badly Filmed – But Gives And Idea Of How Smooth Things Feel


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 #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 #27 – Bang Go Some Bugs

Bit of a ‘clearing the decks’ session today as I get rid of a few bugs that have been irritating me. There were problems with the teleport sequence that I needed to fix (the jetboard weapon attachment not getting displayed correctly), the ‘lost the jetboard’ sequence was annoying me (as the main character carried on waving his arm all gung-ho even when it was obvious he was heading for certain death) and I needed some kind of explosion/disintegration effect for a destroyed jetboard.

None of these proved particularly heinous to sort thankfully so I could move on pretty quickly to tweaking the enemy explosions which I wasn’t entirely happy with. I wanted something a bit more dramatic but not too OTT and think I got there in the end – though my first attempts were way to extreme. Took a fair bit of tweaking though.

I tried adding a velocity deviation to the particles in the enemy explosion but I think I prefer it with the particles moving at a more uniform velocity. It’s not ‘realistic’ but it seems to fit with the visual feel to me, slightly more glitchy and geometric in quality.

Dev Time: 0.5 days
Total Dev Time: approx 29.5 days

previous | next

mockup_3x
Improved ‘Lost Jetboard’ – Not So Gung-Ho Now!

mockup_3x
Too Much ‘Shock And Awe’ For George W Bush Even?

mockup_3x
Toned Down – Almost There

mockup_3x
Final(!?) Explosion – More Uniform Particles