Category Archives: Game Development

This is my dev blog for what will start as a remake of the Amiga K240 but will end up extending and updating the game, the new game is currently called L480!

The game:
K240 was a 4x style game where you settled on asteroids and which you mined to build ships and missles.
These were then used to expand out into the universe.

The Tech:
I’m using C# and monogame for the main development framework.
On top of that I have a set of systems and tech that I call the Sentia framework.
These include my own UI system (called SUI), 2D tiling engines (both basic and isometric), and a number of other basic ones like state machines and world systems.

What these blogs will contain:
I will be talking about the progress in developing the game but also how I’ve written the various game systems.
Now these might not be the best way to develop a game, or the most efficient and might change in time.
Its mostly just how I want to develop this title.

Things I want to try doing:
I want to develop the game in a way to allow for easy modding, both new buildings but hopefully being able to replace huge parts of the code game.

Why not use a pre-made engine?
Mostly because I emjoy system dev and my systems work how I like to develop, where with engines like Unreal and game makers like Unity you are forced into a specific way of developing.
On top of that most of what I’m writing is game code, I already have most of the code systems that I need to develop.

What about artwork:
I will mostly be starting with using the orginal games graphics as a base and either updating them or redoing from scratch.

Target platforms:
C# (with mono) and monogame support multiple platforms, but to start with I will only be caring about Windows.
This is because Windows is what I typically use and its my main dev platform.

Current progress:
Test world
This is an image from my test world, I use this to test basic rendering.


Tags:

This is one of XNA’s most powerful features and one of its hardest to start working with.

So for example we are going to create a new class that will hold a texture and some additional details, such as the number of frames and the size of the frames, and could also include some data such as data read from the texture the end class will look like this:

namespace GameLib
{
	public class TextureWithData
	{
		public Rectangle FrameSize;
		public object ProcessedData;
		public Texture2D Texture;
		public Point FrameCount;

		public void ChangeFrame(int x, int y)
		{
			FrameSize = new Rectangle(x * FrameSize.Width, y * FrameSize.Height, FrameSize.Width, FrameSize.Height);
		}
	}
}

Now because of the texture we will have to have an “process” class and an in game class, above is the in game class, this is the process class:

namespace PipelineLib
{
	// Because of the Texture2D we end up needing these 2 classes that mostly match each other.
	// The attribute at the top tells us what class it will end up being.
	[ContentSerializerRuntimeType("GameLib.TextureWithData, GameLib")]
	public class TextureWithDataContent
	{
		public Rectangle FrameSize;
		public object ProcessedData;
		public Texture2DContent Texture;
		public Point FrameCount;
	}
}

Now note the ContentSerializerRuntimeType at the top of the class, it tells xna what in in game class will be. It has both the full path to the class (including the namespace) and the namespace as a second param. Also note that this function doesn’t have the helper function but does have the same named variables.

The next point is where these classes go:


Note that the 2 classes have gone into there own libraries, the reason for this is the gameLib is needed in the pipeline and in the game, so we have to have them in separate libs or we will get cyclic references.
On the subject of references, the pipelineLib includes a reference to the gameLib, and the content Project has a reference to the pipelineLib.
The Game has a reference to the gameLib.

Now for this example there are 2 ways for us to generate the data, one is in the importer and one is in the processor.

First of all I will show the importer:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;

using TImport = PipelineLib.TextureWithDataContent;
using System.Drawing;
using System.ComponentModel;

namespace PipelineLib.ProcessorAndImporter
{

	// This importer will create the texture2D but please note this won't create mipmaps, or compress the texture.
	// This means it does not need a processor.
	[ContentImporter(".png", DisplayName = "ImporterOnly Importer")]
	public class ImporterOnlyImporter : ContentImporter<TImport>
	{
		public override TImport Import(string filename, ContentImporterContext context)
		{
			// Here we are going to use a mix of Windows GDI/winforms programming and XNA
			// Please note that XNA has different Color to winforms Color

			// Load the Texture into a GDI bitmap
			Bitmap bitmap = (Bitmap)Image.FromFile(filename);


			if (bitmap != null)
			{
				// Create a Texture2D content
				Texture2DContent texture = new Texture2DContent();
				PixelBitmapContent<Microsoft.Xna.Framework.Color> newBitmap = new PixelBitmapContent<Microsoft.Xna.Framework.Color>(bitmap.Width, bitmap.Height);

				// Here is coping the data into the texture from the bitmap, so here would be a great place todo your checks and fill out the extra data
				for (int y = 0; y < bitmap.Height; y++)
				{
					for (int x = 0; x < bitmap.Width; x++)
					{
						System.Drawing.Color source = bitmap.GetPixel(x, y);
						Microsoft.Xna.Framework.Color dest = new Microsoft.Xna.Framework.Color(source.R, source.G, source.B, source.A);
						newBitmap.SetPixel(x, y, dest);
					}
				}

				texture.Mipmaps.Add(newBitmap);

				TImport data = new TImport();
				data.Texture = texture;
				data.FrameSize = new Microsoft.Xna.Framework.Rectangle(0,0,bitmap.Width / 4, bitmap.Height / 4);
				data.FrameCount = new Microsoft.Xna.Framework.Point(4, 4);
				return data;
			}

			throw new Exception("Failed to load the texture or process something");
		}
	}
}

Note in the code the hard coded frame size, this is because importers can not have additional properties.
once this is complied you can use it with the following settings:

So if we want to do a processor here is the same code for the processor:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

using TInput = Microsoft.Xna.Framework.Content.Pipeline.Graphics.Texture2DContent;
using TOutput = PipelineLib.TextureWithDataContent;
using System.ComponentModel;
using System.Diagnostics;

namespace PipelineLib.ProcessorOnly
{
	/// <summary>
	///
	/// This should be part of a Content Pipeline Extension Library project.
	/// 
	/// The Bonus of using the processor is that it can have addtional properties
	/// </summary>
	[ContentProcessor(DisplayName = "PipelineLib.ProcessorOnly.ProcessorOnlyProcessor")]
	public class ProcessorOnlyProcessor : ContentProcessor<TInput, TOutput>
	{
		[DisplayName("Sprite Width")]
		[DefaultValue(1)]
		[Description("The size of each sprite's width within the sprite map.")]
		public virtual int FrameWidth { get; set; }

		[DisplayName("Sprite Height")]
		[DefaultValue(1)]
		[Description("The size of each sprite's width within the sprite map.")]
		public virtual int FrameHeight { get; set; }

		public override TOutput Process(TInput input, ContentProcessorContext context)
		{
			if (FrameWidth == 0)
				FrameWidth = 1;

			if (FrameHeight == 0)
				FrameHeight = 1;

			// we get the Texture2DContent in, so we can get the colour data from the first mipmap on the texture
			// This is a little more complex as we don't know the source format of the texture.
			BitmapContent content = input.Mipmaps[0];

			// I'm assuming the pixel is in xna colour format
			if (content is PixelBitmapContent<Microsoft.Xna.Framework.Color>)
			{
				PixelBitmapContent<Microsoft.Xna.Framework.Color> bitmap = content as PixelBitmapContent<Microsoft.Xna.Framework.Color>;


				for (int y = 0; y < bitmap.Height; y++)
				{
					for (int x = 0; x < bitmap.Width; x++)
					{
						Color source = bitmap.GetPixel(x, y);

						// Do your tests here!
					}
				}

				TOutput data = new TOutput();
				data.Texture = input;
				data.FrameSize = new Microsoft.Xna.Framework.Rectangle(0, 0, bitmap.Width / FrameWidth, bitmap.Height / FrameHeight);
				data.FrameCount = new Microsoft.Xna.Framework.Point(FrameWidth, FrameHeight);
				return data;
			}
			else
			{
				throw new Exception("Texture is in the wrong format");
			}
		}
	}
}

This allows us to have custom properties:


Finally in game we can now load this data and show it:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using GameLib;

namespace InDepthPipeline
{
	/// <summary>
	/// This is the main type for your game
	/// </summary>
	public class Game1 : Microsoft.Xna.Framework.Game
	{
		GraphicsDeviceManager graphics;
		SpriteBatch spriteBatch;

		TextureWithData m_Data;
		Rectangle m_Position;
		Point m_Place = new Point(0, 0);

		float m_Timer;
		float m_WaitTime = 0.25f;

		public Game1()
		{
			graphics = new GraphicsDeviceManager(this);
			Content.RootDirectory = "Content";
		}

		protected override void Initialize()
		{
			base.Initialize();
		}

		protected override void LoadContent()
		{
			spriteBatch = new SpriteBatch(GraphicsDevice);

			m_Data = Content.Load<TextureWithData>("TestTexture");

			m_Position = m_Data.FrameSize;
			m_Position.X = 100;
			m_Position.Y = 100;
		}

		protected override void UnloadContent()
		{

		}

		protected override void Update(GameTime gameTime)
		{
			// Allows the game to exit
			if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
				this.Exit();


			m_Timer += (float)gameTime.ElapsedGameTime.TotalSeconds;

			if (m_Timer > m_WaitTime)
			{
				m_Timer -= m_WaitTime;

				m_Place.X++;

				if (m_Place.X >= m_Data.FrameCount.X)
				{
					m_Place.X = 0;
					m_Place.Y++;
				}

				if (m_Place.Y >= m_Data.FrameCount.Y)
				{
					m_Place.Y = 0;
					m_Place.X = 0;
				}

				m_Data.ChangeFrame(m_Place.X, m_Place.Y);
			}


			base.Update(gameTime);
		}

		/// <summary>
		/// This is called when the game should draw itself.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		protected override void Draw(GameTime gameTime)
		{
			GraphicsDevice.Clear(Color.CornflowerBlue);

			spriteBatch.Begin();

			spriteBatch.Draw(m_Data.Texture, m_Position, m_Data.FrameSize, Color.White);

			spriteBatch.End();

			base.Draw(gameTime);
		}
	}
}

This loads the file, and then shows the texture in an animated format using the helper function.

Linked here is the source for the solution: solution


Tags: ,

There are many ways to create 2D arrays in C# so I decided to take a look at 4 different methods and see which one was the fastest.

The 4 types that were chosen:

  • List of lists(List< List < > >)
  • Jagged arrays ([][])
  • Multidimensional arrays ([,])
  • 1D array using maths to find the place ((y * size) + x).

1000 x 1000 sized arrays were created and tested, these tests included Creation, Filling, finding 1 value (at position 500×500) and iterating across the whole array, time is in milliseconds.

 

Results

Windows7
List of Lists
   Create: 0    Build: 29.0016
   Find 1: 0   Iterate: 15.0009
Multi Dimensional
    Create: 0    Build: 12.0007
    Find 1: 1.0001    Iterate: 11.0006
Jagged
    Create: 0    Build: 8.0004
    Find 1: 0    Iterate: 6.0004
1D Array
    Create: 0    Build: 8.0004
    Find 1: 0    Iterate: 6.0004

WP7
List of Lists
   Create: 64    Build: 261
   Find 1: 1   Iterate: 142
Multi Dimensional
    Create: 4    Build: 120
    Find 1: 0    Iterate: 120
Jagged
    Create: 0    Build: 64
    Find 1: 0    Iterate: 46
1D Array
    Create: 0    Build: 64
    Find 1: 0    Iterate: 46

XBOX 360
List of Lists
   Create: 5    Build: 185
   Find 1: 0   Iterate: 139
Multi Dimensional
    Create: 1    Build: 120
    Find 1: 0    Iterate: 136
Jagged
    Create: 1    Build: 64
    Find 1: 0    Iterate: 62
1D Array
    Create: 1    Build: 64
    Find 1: 0    Iterate: 62

 

From the numbers is looks like C# internally works a Jagged array as a 1D array and does that math for us and so from a speed and easy of use point of view it seems Jagged arrays win out.

 

Huge thanks to MadNinjas of #XNA (irc.efnet.net) for running the code on the other platforms!

[edit]
It seems I had mixed up the multi dimensional and jagged arrays in my code so my numbers were wrong, this is now fixed.


I thought I would post up a quick tool I have written to make it easy to animate and create my sprites for my games.

This is written in C# and it using XNA for the drawing of the sprite example, time line and animation preview.  It helps that I’m using XNA for my Indie game development. I’m also using the great Dock Panel to give me dockable forms.

For starting a tool like this I typically make sure I get the data class (at least the members) right then add the needed methods that are needed while working on the tool.

Now for saving and loading the created animations I just use XML, this because its really easy to serialise classes to XML in C# and it means if anything goes wrong its easy to open the file and edit it.  As we know loading XML in our game can be slow so the best idea is to create a custom content importer to get it in game quickly.

 

So with out any more waffling here is the video (yes that is me talking):

 


So you have decided to make a computer game, that’s great the question is what game do you want to create first?

Most new developers will answer that they want to create the game they have always wanted to.

This is the first problem, as while you are full of enthusiasm and energy you also lack experience. Game development is hard and time consuming, far more then you would expect when first starting out and as such you are unlikely to pull off your perfect game first time, your first few games will end up buggy and barely working and most people give up before getting anywhere because they tried to do more then they are currently capable of.

So where do you start?
Do a small simple game, something that will allow you to learn the basics of game development with out the worry of trying to build your perfect game. This could be something as simple as pong or Tetris, which will teach you how to draw graphics, handle input and basics game systems.
Once you’ve finished your first few games you will not only have a better understanding of how to make a game but you will also have more enthusiasm for it.


Tags: