Jetboard Joust Devlog #38 – 2D Or Not 2D?

It’s funny how this stuff works. You design sprite A and are perfectly happy with it, then you add sprite B which you feel is even better and sprite A now seems rather lacklustre in comparison. So you go back and tweak sprite A – which is great, only sprite B now seems to have lost its sheen a bit and needs a bit more work. And on and on it goes…

Looking back on this Devlog I’ve been through this process a few times and this week I’ve been bitten by the bug yet again. Even though I know this is a 2D game I was feeling that the buildings that make up the terrain just felt a little too 2D (22D?) and needed something to give them a bit more depth.

I remembered how @PVBroadz had been through similar a process when we were working on Attack Of Giant Jumping Man (he blogged about it here) and I felt a similar solution would work for Jetboard Joust.

So I started redrawing the buildings – keeping the same ‘space aztec’ feel but this time imagining that they were viewed from a kind of flattened ‘side on’ perspective, a bit like Zelda’s ‘top down’ 2D only from the side. As I’m restricting myself to an 8 colour monochrome palette it was tough to get the shading right (really I think the side section should be darker but then I run out of dark tones) but I think the result looks pretty good.

Trouble is, these versions, whilst they certainly looked more solid, seemed too heavy and ‘brick like’ in-game. I attempted to counter this by designing a bunch of more ‘open’ tiles and making sure there was at least one ‘open’ tile between each ‘solid’ tile. The more ‘open’ tiles were a lot harder to get right and I spent a long time fiddling about with the way the shadows worked.

The ‘open’ tiles seemed to work but I didn’t think the arched tiles I had designed (even though I was pleased with them individually) fitted in with the overall, more geometric look of the game. Consequently I decided to bin these (always difficult when you’ve spent some time on something) and create a bunch more based on more geometric forms instead. I also added a subtle one-pixel indent between the ‘solid’ tiles which also seemed to break up the regularity a bit.

I’m pleased with the end result now and think the buildings look much better than they did. There is still room for improvement (isn’t there always) and I think with a bit of effort I could get some really interesting Escher-style connections going on – for now it’s time to park it though!

Dev Time: 1.5 days
Total Dev Time: approx 45.5 days

previous

mockup_3x
First Attempt – Solid, But Too ‘Brick-Like’


More Open But The Arches Don’t Work


I Think This Is It – For Now!


Scrolling Through…

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 #34 – Making Babies

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

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

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

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

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

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

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

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

previous | next


Alien Babies – Panic Animation


Alien Babies – Idle Sequence

Jetboard Joust Devlog #33 – Game On!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

previous | next



mockup_3x
Enemies Now Drop Mini Health Pickups

Jetboard Joust Devlog #32 – Knob Rocket

Rather a frivolous blog post this one but I feel I should document everything, warts and all – and this issue has cost me a worrying amount of time.

I needed to add a rocket pickup so I could limit the use of the jetboard ‘jump’ attack (will write more on this in the next post). This should have been a simple task but unfortunately my ‘pixel rocket’ ended up looking rather too much like a ‘pocket rocket’!

I tried an alternative which I thought was OK but several people on Twitter though it was still too phallic so it was back to the drawing-board again.

Eventually I got there. The issue really was that the ‘shaft’ of my rocket was only two pixels wide – this meant that the end always looked ’rounded’ instead of ‘pointy’. Thickening the shaft to three pixels allowed me to have a pointy end which, I think, removed any sexual connotations for all but the most filthy-minded of individuals (I can’t believe I’m actually writing this).

Oh yeah – I’ve also added a new enemy type, I’m calling this one the Minion!

Dev Time: 0.5 days
Total Dev Time: approx 33.5 days

previous

mockup_3x
Pixel Rocket Or Pocket Rocket?

mockup_3x
The De-Willification Procedure

mockup_3x
Final Rocket Pickup In-Game

mockup_3x
Introducing The Minion

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!


Follow

Get every new post delivered to your Inbox.