Name change and Funding
Hey guys, I've not posted about Stonegard in a little while as I've been working mostly on aspects which aren't hugely interesting as well as working hard in my day job. One major change I have made is the actual name of the game. After some research I found that the name 'Stonegard' was actually used by a now defunct nordic rock band. So to stay on the safe side I've changed it to 'Kings Forge'. As for development, I'm coming to a point where I need some help from musicians and animators. Currently the game has no music and I have no music talent to speak of and I am beginning to require animations for combat that are far beyond my ability as a programmer, unfortunately these do not come cheap. So I've created a funding page on IndieGogo to help raise some money to both allow me to spend more time preparing an alpha release and to hire contract musicians and animators. If I reach the target of $16k I will happily be able to spend my full time on the game and all those who gave more than $5 will receive a free copy of the game when I reach an early alpha release. This is effectively a cheap preorder of the game as the price will go up from $5 when it reaches alpha release. You can find the funding page here. If you really like what you've seen please contribute if you can, it will really help the development of Kings Forge and if you have already. Thank you very much! I've nervously recorded a short video which goes over some of the major features of the game and also shows off some of the stuff I've added and the excellent new textures by Mattey.
You can watch the video it here.
Hardware Geometry Instancing in XNA 4
The Reason
First let me give you a bit of a back story on why my game uses hardware geometry instancing. Recently while developing my game I have come across the need for a little bit more detailed objects than cubes. Such as grass, tables and lanterns. The nature of my game means that players can spam the world full of these objects. Which in turn means I need a pretty fast way to draw many of the same meshes at different positions and some other object specific attributes such as lighting data. Without the massive performance loss from drawing them all individually. Drawing them individually would be slow because it would be a draw call per object. If I have 1000 copies of this object on screen. That is 1000 draw calls for drawing that one object in many places, which is a lot of resending of data to the GPU. Now, before I tried hardware instancing. I tried a bit of a different method that was a lot more memory intensive for both GPU and RAM but reduces the draw calls dramatically. Essentially what I did was per chunk(my game world is split into 32x32 chunks) have a vertex buffer and index buffer for each unique object(i.e. grass, lanterns, ducks statues) and store all the vertices and indices for each location where the object was positioned. This meant that drawing a unique mesh on each Chunk was one draw call. But it was also storing many copies of the models vertices and indices to display the object in many different places. On top of this it was quite slow to rebuild the buffer when I wanted to add or remove a location for the mesh to be shown. As it would have to re-offset many indices and add/remove many of the vertices for either operation. This fast became a terrible idea.
So I began to look at a better instancing method to display thousands of copies of meshes with as little data and draw calls as possible. With some research I found Shawn Shawn Hargreaves's post on the DrawInstancedPrimitives method within XNA. This was added in XNA 4.0 and makes Hardware instancing a much nicer affair within XNA than it was in preceding versions. Essentially what it allows you to do is send two vertex buffers bound together to the GPU rather than one. Why would you want to do that? Well the second vertex buffer contains attributes that are unique per instance. Rather than per vertex. They come through to your Effect in the same way with the rest of the vertex data(like Position, TextureCoords etc) which makes it really simple on the Effect side of things. On a basic level you can send a list of world matrices in the second buffer and transform the vertex positions from the first buffer to position many different instances around your world. As DrawInstancedPrimitives basically runs through the number of instances supplied and assigns the vertex data from the second buffer to that instance.
The Tutorial
So lets jump right in and see how this works in code. If my above explanation didn't make it very clear, don't worry hopefully this will! But fair warning this tutorial is meant for those who have at least some experience in 3D rendering with XNA. First of all you'll want to create a new project to try this in. Since we're drawing things in 3D we'll need a basic camera class so we can supply the view and projection matrices properly to our mesh. You'll probably have your own camera class but if you don't here's a very simple one you can drop into your project to use:
public class FreeCamera
{
protected Matrix ViewMatrix;
protected Matrix ProjectionMatrix;
protected Matrix RotationMatrix;
protected GraphicsDevice Device;
Vector3 _Target;
Vector3 _Position;
Vector3 _Rotation;
Vector3 _Up;
protected float Speed;
float _Near;
float _Far;
public Matrix View { get { return ViewMatrix; } }
public Matrix Projection { get { return ProjectionMatrix; } }
public float NearClip { get { return _Near; } }
public float FarClip { get { return _Far; } }
MouseState OriginalMouse;
public FreeCamera(GraphicsDevice device, Vector3 position, Vector3 target, float aspectRatio, float near, float far)
{
Position = position;
Rotation = new Vector3(0, 0, 0);
Target = target;
Speed = 30;
_Near = near;
_Far = far;
Device = device;
_Up = new Vector3(0, 1, 0);
Speed = 100f;
Rotation = new Vector3(0, 0, 0);
OriginalMouse = Mouse.GetState();
// Setup FOV, aspect ratio and clipping planes
ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspectRatio, near, far);
UpdateView();
}
// On changing position change viewmatrix
public Vector3 Position
{
get { return _Position; }
set
{
_Position = value;
UpdateView();
}
}
public Vector3 Target
{
get { return _Target; }
set
{
_Target = value;
ViewMatrix = Matrix.CreateLookAt(Position, Target, new Vector3(0, 1, 0));
}
}
public Vector3 Rotation
{
get { return _Rotation; }
set
{
_Rotation = value;
RotationMatrix = Matrix.CreateRotationX(_Rotation.X) * Matrix.CreateRotationY(_Rotation.Y);
UpdateView();
}
}
public Matrix World
{
get
{
return Matrix.CreateTranslation(Position.X, Position.Y, Position.Z)
* Matrix.CreateRotationX(_Rotation.X)
* Matrix.CreateRotationY(_Rotation.Y)
* Matrix.CreateRotationZ(_Rotation.Z);
}
}
public void UpdateView()
{
Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, RotationMatrix);
Vector3 cameraFinalTarget = Position + cameraRotatedTarget;
Vector3 cameraRotatedUpVector = Vector3.Transform(_Up, RotationMatrix);
ViewMatrix = Matrix.CreateLookAt(Position, cameraFinalTarget, cameraRotatedUpVector);
}
public virtual void Move(Vector3 vector)
{
// Move the cameras position based on the way its facing
Vector3 rotatedVector = Vector3.Transform(vector, RotationMatrix);
Position += Speed * rotatedVector;
}
public virtual void Update(GameTime time)
{
// Free movement
float dt = (float)time.ElapsedGameTime.Milliseconds / 1000f;
// Rotation
MouseState currentMouseState = Mouse.GetState();
if (currentMouseState != OriginalMouse && Keyboard.GetState().IsKeyDown(Keys.Space))
{
Vector3 rotation = Rotation;
float xDifference = currentMouseState.X - OriginalMouse.X;
float yDifference = currentMouseState.Y - OriginalMouse.Y;
rotation.Y -= 0.3f * xDifference * dt;
rotation.X += 0.3f * yDifference * dt;
Mouse.SetPosition(Device.Viewport.Width / 2, Device.Viewport.Height / 2);
Rotation = rotation;
}
OriginalMouse = Mouse.GetState();
// Key press movement
KeyboardState keyboard = Keyboard.GetState();
Vector3 direction = Vector3.Zero;
if (Keyboard.GetState().IsKeyDown(Keys.W))
Move(new Vector3(0, 0, -1) * dt);
if (Keyboard.GetState().IsKeyDown(Keys.S))
Move(new Vector3(0, 0, 1) * dt);
if (Keyboard.GetState().IsKeyDown(Keys.A))
Move(new Vector3(-1, 0, 0) * dt);
if (Keyboard.GetState().IsKeyDown(Keys.D))
Move(new Vector3(1, 0, 0) * dt);
}
public virtual string DebugInfo()
{
return "Camera Position: " + Position.ToString();
}
}
So with the camera class added we need to create a instance of the Camera within our Game1 class. If your using my Camera class just add it as a member to the Game1 class and initialize it in LoadContent() with:
Camera = new FreeCamera(GraphicsDevice, new Vector3(0, 10, 0), Vector3.Zero, GraphicsDevice.Viewport.AspectRatio, 0.1f, 1000f);
As well as adding Camera.Update(gameTime) to Game1's Update method. This is the camera setup and ready to go.
The first thing we're going to need is an actual mesh to instance. For this tutorial I'll be using a Christmas Duck created by Harm Delva. Which you can download at the end of the tutorial in the finished project (HardwareInstancingExample). Once you have your mesh, add it and it's texture to the Content project. The next step is to load the mesh in and grab all its vertices and indices and put them in a vertex and index buffer of our own. This way we can get at them easily when it comes down to sending it to the GPU to be instanced rather than cycling through mesh parts. To do this you can use the following method I wrote which will work on meshes with 16bit indices. Such as our example Duck. We also want to create a seperate class called InstancedModel so its easily reusable on different Models. So create a new Class file called "InstancedModel.cs" in your project and drop the below code inside:
class InstancedModel
{
VertexBuffer VertexBuffer;
IndexBuffer IndexBuffer;
Texture2D Texture;
public InstancedModel(Model model, Texture2D texture, GraphicsDevice device)
{
Texture = texture;
// Get array of vertices and indices from model
VertexPositionNormalTexture[] vertices = null;
ushort[] indices = null;
GetModelVerticesAndIndices(model, out vertices, out indices);
// Create buffers from them to use when drawing
VertexBuffer = new VertexBuffer(device, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
VertexBuffer.SetData (vertices);
IndexBuffer = new IndexBuffer(device, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly);
IndexBuffer.SetData(indices);
}
public void Update()
{
}
public void Draw(Matrix view, Matrix projection)
{
}
///
<summary> /// Gets vertices and indices making up a Model.
/// </summary>
///
///
///
private void GetModelVerticesAndIndices(Model model, out VertexPositionNormalTexture[] vertices, out ushort[] indices)
{
List verticesList = new List();
List indicesList = new List();
foreach (ModelMesh mesh in model.Meshes)
foreach (ModelMeshPart part in mesh.MeshParts)
{
// Go through mesh parts building up a list of vertices and indices used for each part.
VertexPositionNormalTexture[] partVerts = new VertexPositionNormalTexture[part.VertexBuffer.VertexCount];
part.VertexBuffer.GetData(partVerts);
ushort[] partIndices = new ushort[part.IndexBuffer.IndexCount];
part.IndexBuffer.GetData(partIndices);
indicesList.AddRange(partIndices);
verticesList.AddRange(partVerts);
}
vertices = verticesList.ToArray();
indices = indicesList.ToArray();
}
}
Nothing crazey going on here. We are just defining the class for our Instanced Models. We have a vertex and index buffer ready for the models information and a method to get them from the model. With a constructor that populates the data for us and an Update and Draw method that we will fill up shortly. But before we go any further we need to create a instance of this in our Game1 class so go ahead and create a member called InstancedModel InstanceMode in the Game1 class and initialize it in the LoadContent method like so:
///
<summary> /// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
Camera = new FreeCamera(GraphicsDevice, new Vector3(1.5f, 0, -10), Vector3.Zero, GraphicsDevice.Viewport.AspectRatio, 0.01f, 1000f);
Camera.Target = new Vector3(1.5f, 0, 0);
// TODO: use this.Content to load your game content here
Model duckModel = Content.Load("snowduck");
Texture2D texture = Content.Load("christmas");
InstancedModel = new InstancedModel(duckModel, texture, GraphicsDevice);
}
Also take this time to add InstancedModel.Update() and InstanceModel.Draw(Camera.View, Camera.Projection) to Game1's Update() and Draw() methods. This is probably a good time to compile and make sure there is no mistakes if you are following a long and not using the completed project. When running it will not show anything as we haven't started displaying our instances yet. Now onto the actual instancing. The first thing we need is a new custom vertex format. This will store data relevant to each instance of the model. For this tutorial I am simply going to store a World matrix and a Colour for each instance. So create a new class file called InstanceDataVertex and inside it paste this:
public struct InstanceDataVertex
{
public Matrix World;
public Color Colour;
public InstanceDataVertex(Matrix world, Color colour)
{
World = world;
Colour = colour;
}
public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
(
// World Matrix Data
new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 5),
new VertexElement(sizeof(float) * 4, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 6),
new VertexElement(sizeof(float) * 8, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 7),
new VertexElement(sizeof(float) * 12, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 8),
//Colour Data
new VertexElement(sizeof(float) * 16, VertexElementFormat.Color, VertexElementUsage.Color, 0)
);
}
If you've not dealt with custom vertex formats before this will look like a bit of a strange beast. Vertex formats allow you to store your own data per vertex in order to send to your shader. Normally they would hold Position, Normal and Texture Coordinates but in this case we are holding the World matrix and colour of an instance. The VertexDeclaration basically tells XNA and the GPU what your vertices contain and the given offset within the vertex data in bytes to get to them. However there is no VertexElementFormat for 4x4 matrices. So instead we declare 4 vector4's which we will bring back into a Matrix within the Effect itself. If you'd like to know more about custom Vertex Formats in XNA you can look here for a nice explanation of them.
Now we have a format for our instances we need a second Vertex Buffer in our InstancedModel class. Which will hold the instance data vertices. We will also add some temporary vertex data so we know it is working when we come to draw it. So add these additions to the top of your InstancedModel class and you should get something like so:
VertexBuffer VertexBuffer;
IndexBuffer IndexBuffer;
DynamicVertexBuffer InstancedVertexBuffer;
Texture2D Texture;
public InstancedModel(Model model, Texture2D texture, GraphicsDevice device)
{
Texture = texture;
// Get array of vertices and indices from model
VertexPositionNormalTexture[] vertices = null;
ushort[] indices = null;
GetModelVerticesAndIndices(model, out vertices, out indices);
// Create buffers from them to use when drawing
VertexBuffer = new VertexBuffer(device, VertexPositionNormalTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
IndexBuffer = new IndexBuffer(device, IndexElementSize.SixteenBits, indices.Length, BufferUsage.WriteOnly);
// Create temporary data
// Duck is massive so create scale matrix
Matrix scale = Matrix.CreateScale(0.2f, 0.2f, 0.2f);
InstanceDataVertex[] data = new InstanceDataVertex[]
{
new InstanceDataVertex(scale * Matrix.CreateTranslation(new Vector3(0,0,0)), Color.Red),
new InstanceDataVertex(scale * Matrix.CreateTranslation(new Vector3(1,0,0)), Color.Green),
new InstanceDataVertex(scale * Matrix.CreateTranslation(new Vector3(2,0,0)), Color.Blue)
};
// Create instanced VertexBuffer with some temporary data
InstancedVertexBuffer = new DynamicVertexBuffer(device, InstanceDataVertex.VertexDeclaration, data.Length, BufferUsage.None);
InstancedVertexBuffer.SetData(data);
}
All I am doing here is creating another vertex buffer as discussed above and populating it with some instance data. I create a matrix for this data giving each instance a smaller scale as the model is fairly big, and giving them each a separate position and colour, so later we know they have different attributes. It is important to note also that I use a DynamicVertexBuffer rather than an ordinary VertexBuffer. This is because with a DynamicVertexBuffer you can use Set multiple times if you have the same amount of elements in your vertex data and it is much faster to recreate the buffer entirely when you add or remove an element. So we now have our two vertex buffers, one with the model's vertices, one with instance data and a index buffer of the model's indices. What's next? We need to write an Effect(or Shader) for it. So create a new Effect file in your Content project and call it InstanceEffect.fx. This effect will be very simple and be the following:
float4x4 View;
float4x4 Projection;
Texture Texture;
sampler TextureSampler = sampler_state { texture = ; magfilter = LINEAR; minfilter = LINEAR; mipfilter= LINEAR; AddressU = wrap; AddressV = wrap;};
struct VertexShaderInput
{
// PER VERTEX DATA
float4 Position : POSITION0;
//float3 Normal : NORMAL0;
float2 TextureCoords : TEXCOORD0;
// PER INSTANCE DATA
float4x4 World : TEXCOORD5;
float4 Colour : COLOR0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Colour : COLOR0;
float2 TextureCoords: TEXCOORD0;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
// Use per instance World matrix to get World Pos
float4 worldPosition = mul(input.Position, transpose(input.World));
// Transform with camera view and projection to get screen pos
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
// Send texture coords and per instance colour to pixel shader
output.Colour = input.Colour;
output.TextureCoords = input.TextureCoords;
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
// Get texture pixel
float4 colour = tex2D(TextureSampler, input.TextureCoords);
// Multiply by per instance colour value
colour *= input.Colour;
return colour;
}
technique Technique1
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_3_0 VertexShaderFunction();
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}
As you may notice there is a few changes between the default effect file and this one. So lets run through the changes top to bottom. First of all I have removed the World matrix parameter as the World matrix will be coming through our vertex data and not as a parameter. I have also added a Texture and TextureSampler which will receive the duck's texture and allow us to texture our instances with it.
VertexShaderInput has had a few parts added. As you can see I've split it into data that comes from the vertices of the model and data that comes from the InstanceVertexBuffer. We receive the Position, Normal and Texture Coordinates as you normally would with an Effect. However we also receive extra data from the InstanceVertexBuffer. Which is our per instance data. In this case we've sent through our World matrix(Remember all those texture coordinates in our Vertex Format? Well here they are back into a Matrix) and a colour for each instance of our ducky. With VertexShaderOutput we simply send relevant data to the PixelShader for it to do its work. Which is the colour and Texture Coordinates. For the vertex shader function the main thing that's changed is we now use input.World matrix to transform our vertex rather than a World matrix sent as a parameter. We also setup the output so our pixel shader gets the texture coordinates and colour it needs in order to correctly texture the mesh.
Forthe pixel shader we simply get the pixel we want from the texture then multiply it to get our per instance colour. Since we set each Instance data to have a different colour. The multiplying of the texture colour with the colour will allow us to see different coloured instances. The last important part of this effect is vs_3_0 and ps_3_0. It is important to note that this kind of instancing requires shader model 3 in order to receive the combined vertex buffers. Now we're almost ready to draw! We just need to flesh out the draw method.
Before we write anything in the draw method. We must load the effect file we have just created. Simply create an Effect member called "Effect' in the InstancedModel class and load it in the Game1 class then pass it through InstancedModel's constructor with an extra parameter. The first and most simple thing we need to do in our InstancedModel's Draw method is setup our shader parameters. Since their is only three. We only need to add the following which is the camera's view and projection matrices and the texture we want to apply to the mesh.
public void Draw(Matrix view, Matrix projection)
{
// Setup effect parameters
Effect.Parameters["View"].SetValue(view);
Effect.Parameters["Projection"].SetValue(projection);
Effect.Parameters["Texture"].SetValue(Texture);
foreach (EffectPass pass in Effect.CurrentTechnique.Passes)
pass.Apply();
}
Now we need to set our vertex and index buffers for the GraphicsDevice. Since we have two vertex buffers we need to use VertexBufferBinding when setting the Devices vertex buffer. This binds their data together in order to be drawn on the per instance basis.
public void Draw(Matrix view, Matrix projection)
{
// Setup effect parameters
Effect.Parameters["View"].SetValue(view);
Effect.Parameters["Projection"].SetValue(projection);
Effect.Parameters["Texture"].SetValue(Texture);
foreach (EffectPass pass in Effect.CurrentTechnique.Passes)
pass.Apply();
// Setup vertex buffers and index buffers for the device.
GraphicsDevice device = Effect.GraphicsDevice;
device.SetVertexBuffers(VertexBuffer, new VertexBufferBinding(InstancedVertexBuffer, 0, 1));
device.Indices = IndexBuffer;
}
Now we have the vertex buffers set. All we need to is draw it with DrawInstancedPrimitives(). Which is pretty similar to most of the other GraphicsDevice.Draw() methods except it takes an extra parameter on the end which is the amount of instances to be drawn. Which will be the vertex count of your InstancedVertexBuffer since that contains the data for each instance in it's stored vertices. So add the following code and you're ready to run!
public void Draw(Matrix view, Matrix projection)
{
// Setup effect parameters
Effect.Parameters["View"].SetValue(view);
Effect.Parameters["Projection"].SetValue(projection);
Effect.Parameters["Texture"].SetValue(Texture);
// Setup vertex buffers and index buffers for the device.
GraphicsDevice device = Effect.GraphicsDevice;
device.SetVertexBuffers(VertexBuffer, new VertexBufferBinding(InstancedVertexBuffer, 0, 1));
device.Indices = IndexBuffer;
device.RasterizerState = RasterizerState.CullCounterClockwise;
device.BlendState = BlendState.Opaque;
foreach (EffectPass pass in Effect.CurrentTechnique.Passes)
pass.Apply();
device.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, VertexBuffer.VertexCount, 0, IndexBuffer.IndexCount / 3, InstancedVertexBuffer.VertexCount);
}
You should see 3 ducks which are tinted red, green and blue! If you have any problems, it'd be a good idea to scroll to the bottom and download the finished project and see what differs between your version and the finished one. Note if you used my camera class you can rotate the camera by holding space while moving the mouse . You can also move the camera with WASD.

So we've got some ducks displaying with some unique properties. Colour and Translation. However the point of instancing is that you can have many meshes. As it only keeps the data for one copy of the mesh and a the individual data of each instance. So lets go ahead and add a couple of thousand more ducks in. Earlier we created the data for the instances like this:
// Create temporary data
// Duck is massive so create scale matrix
Matrix scale = Matrix.CreateScale(0.08f, 0.08f, 0.08f);
InstanceDataVertex[] data = new InstanceDataVertex[]
{
new InstanceDataVertex(scale * Matrix.CreateTranslation(new Vector3(0,0,0)), Color.Red),
new InstanceDataVertex(scale * Matrix.CreateTranslation(new Vector3(1,0,0)), Color.Green),
new InstanceDataVertex(scale * Matrix.CreateTranslation(new Vector3(2,0,0)), Color.Blue)
};
But this time we're going to replace this and create us an army of ducks/meshes. Its worth noting that I am not going to cover making any kind of manager for instancing. As how you add and remove instances is really up to you. But since we use a DynamicVertexBuffer you can recreate it for changes in size of the Vertex array and just use Set() and Get() to retrieve and alter it. Anyway on to creating an army of ducks. Simply replacing the above with:
int width = 80, depth = 80;
InstanceDataVertex[] data = new InstanceDataVertex[width * depth];
for (int x = 0; x < width; x++)
for (int z = 0; z < depth; z++)
data[(z * width) + x] = new InstanceDataVertex(scale * Matrix.CreateTranslation(new Vector3(x * 2, 0, z * 2)),Color.White);
// Create instanced VertexBuffer with some temporary data
InstancedVertexBuffer = new DynamicVertexBuffer(device, InstanceDataVertex.VertexDeclaration, data.Length, BufferUsage.None);
InstancedVertexBuffer.SetData(data);
This gives us an army of 6400 ducks. Each duck is 1843 triangles. That's 6400 * 1843 = 11795200 triangles! Running at 60FPS. Depending on your GPU you could easily crank it up before you had a drop in frame rate as well.
Below you can find the finished project with an army of ducks at the ready and FPS counter so you can have a rough idea of performance. Thanks for reading now go implement it in your project!
If you have any questions please leave a comment and I'll get back to you as soon as I can.
Download: HardwareInstancingExample
Things to keep in mind:
- This sort of instancing requires the user to have a Shader Model 3 graphics card. Some people still don't have these. Although if they are playing games on their PC. It's most likely they do.
- To implement this in your own game. You'll want to write some kind of manager that allows you to add and remove instances easily.
- You can add any properties you want per instance into the custom vertex format we created during the tutorial. But the more properties you have the more memory is used. This is especially a concern when you have tens of thousands of instances.
- It was pointed out to me by a friend that TEXCOORD8 doesn't actually exist as it only goes to 7. So you actually lose the end row matrix data in the effect. However this isn't hugely a problem for the transforms used within the example and you can simply move each TEXCOORD index down in the effect and vertex format.
A new perspective
As usual between the large gaps of time in which I seem to post blog updates. There has been a lot of new features and even perspectives(don't worry we're not getting philosophical) added and changed. I was also lucky enough to be interviewed about my humble game for Indie games week over at ZConnection. I also started a new job at Solstar Games as a programmer working on the Server and Game Editor of Realm Crafter Professional, which is a great MMO middleware. I've received a warm welcome from the community and have been chipping away at the todo list. Although this means I will have less time to develop my game, which I have decided to start calling Stonegard. It shouldn't impact hugely on my progress. But onto the game!
One of the largest aspects of the game to be changed since my last post has been the camera angle. The player now surveys his bountiful lands from the angle you might expect in a game like Diablo albeit with a bit more freedom to zoom and rotate. This may at first seem like a strange move. However to understand this decision we need to cast our minds back a little. When I first started working on Stonegard it was intended to be a isometric RTS of sorts with similar building mechanics to Minecraft . With the additional idea that you can create and manage NPC's to some degree to help you. The main reason I began messing about with 3D for the game had been because I quickly found that a 2D isometric world made it very difficult for the player to distinguish depth since all tiles are the same size despite being different distances away from the camera. Which is a stark contrast to the real world where things further way you perceive as smaller.
Now skip to the present and I decided I had been too influenced by Minecraft. Which had caused me to stray away from my original goal for Stonegard. This was especially true  with changing the game to a first person view once it had been 3D-ified. On top of this, it is very difficult to manage your NPC minions from the first person, you wouldn't really have a great view of your surroundings and you would have to point where you wanted NPC's to go for example. Which would quickly become cumbersome. From the new view point the player can both select and order NPC's with ease. It also gives a better view of his/her kingdom and immediate surroundings. The obvious problem that comes to mind is "What about tunnels? Surely if they go under ground you can no longer see them!". The answer to that is layers! A bit  like the ones in photoshop, if you like. The player can either have autolayering enabled, which will chop down the world to the height of where their character is currently standing or manual which they can use page up and page down to increase the height of viewable layers. This allows them to have a full view of the world and also gives them a clear view of themselves in indoor structures. To make walls much easier to acknowledge the top of the block becomes black when the layer is cut off above it. If you don't quite get the jist of my explanation, here's a picture of at work to feast your eyes upon.
This has lead to a few internal changes to the game and quite a few benefits technically. Since the game doesn't show nearly the amount of chunks to the player it had done before. Very little  needs to be loaded both client and server side per player. Which in turn means being able to have a lot more players per server for a smaller RAM cost per individual player because there is a lot less data concerned with what is around them. On top of that it pushes the bar down quite a bit in terms of what computer specs can run the game since its doing a lot less rendering, processing and using less memory on the whole.
All the in-game menus have had a pretty large overhaul. This has been coming for some time since I wrote the new Main Menu and Join Game screens, which lead me to write a GUI libary specifically for. This has been expanded quite a bit to allow draggable windows and parentable controls. All the standard game menus have now been ported over to this and benefited mainly to make dealing with multiple menus and moving them about much less of a hazard as it had been with old GUI system. The new system works wonderfully and has made organising both for the player and in code much less of a issue. It has also lead to working on some massive improvements with the chat system. Such as wrapped multiline text, Â individually coloured messages and multiple channels which currently consist of Local, Global, Kingdom and Private. All current in-game menus can either be opened via hotkeys or the icons at the bottom left as well.
So looking forward to the future. I am currently implementing a much nicer Animation libary to account for playing individual animation per bone. Which was a large flaw in the current system. This will be to allow multiple animations such as swinging a sword while walking. Meaning I don't need to make up many weird combinations of animations for all the possible things that can happen at once! Which is great and should lead to much more smooth transitions between animations with specific blending. I've also begun working on the capturing of land and the points system for Kingdoms. But for now I hope you enjoyed me ramblering about my game and if you have any questions please leave a comment.
Further progress to my game
So it's been some time since my last post. But I've been working feverishly away on my game. The main reason I haven't posted in awhile is because I wanted to wait until I had enough to talk about from a technical and game stand point, so I could delve into how I achieved some of the things within my game. Although this will not be quite as in depth as my smooth lighting post. If you were to play(which you can't yet!) the game the biggest visual difference you'd first notice is that the textures have changed pretty radically, for the better!
A friend of mine, Mattey has begun making some really great textures for blocks at a higher resolution and they look great! I'm no artist and it's really made the game look much nicer. Since I don't use a texture atlas's for the blocks any more the higher resolution doesn't look horrible and grainy at long distances or sharp angles because I can easily support texture filtering and mip mapping. Without the annoying bleed from having mip maps on a texture atlas where the border of a tile leaks into another due to the down sampling. I really like the vectory/bold shades of colours that Mattey has come up with and I think they will hopefully add a lot to the finished games light hearted aesthetic. The cost of using individual textures rather a atlas is that you do end up with a lot more state changes for the GPU. I've tried to minimise this by batching all non-transparent block drawing to be done by each texture. So it iterates through all the chunks drawing blocks related to one specific texture. This is so it will do the minimum about of texture swapping. The game runs fine without this. But I'm thinking ahead somewhat when there's a lot more than the current 30 odd block types. Though I don't think this will be a huge performance bottle neck in the future.
Although I have and plan on adding features that are quite radically different to Minecraft, such as item building and the kingdom system(more on this in a later post).  One aspect I really like about Minecraft is the lighting. This has by far taken up the majority of my time since my last post. The basic idea is pretty simple and my previous post  discussed how I get the array stored lighting data onto my geometry and smoothed the result somewhat. However the hard part for me has been creating a method fast enough to propagate light correctly from singular block changes for both the sun and light emitted from sources(such as torches). So that it can be done in real time without a noticeable jitter for the player and the effects of this propagation appearing instantly on the geometry. I tried a plethora of approaches,  most of which either didn't have the correct result. For instance one method I tried would not remove all sun light from an enclosed area such as a house, which left nasty trapped bright spots in a room. Or they would have the desired effect but be far too slow to do on the fly. I ended up using a cellular approach where light spreads to weaker cells, this keeps happening until there are no more weaker cells to spread too. This turns out to be pretty dam fast. For individual light sources it is a god send because the more saturated with light an area becomes, the faster adding additional light sources becomes. This is due to the cell not having to propagate as much since it is already surrounded by brighter neighbours. This means I can have a lot of light sources. Like having lava emitting light. Which I didn't think I'd ever be able to get it fast enough to do.
You might of noticed in the last two screen shots,  there are some creature. Good eye soldier, I've added NPC's(Non Playable Characters). They come in two basic flavours:  Simple and Smart. Both types of NPC's use Object Orientated Bounding Boxes(OOBB) and can collide and interact with blocks in the same method as players. Such as jumping over blocks, swimming or falling into fiendishly placed rivers of lava while I'm taking screen shots(see above). The difference between the two is that Simple NPC's do not use path finding. Instead they just move towards their given destination, jumping over obstacles and trying to slide around walls. Where as Smart NPC's use 3D path finding to move to their target, they don't  jump off cliffs like lemmings, they don't stop at a wall you've built in front of them.They will do their best to find an alternate entrance to stab you in the back(assuming their aggressive). Smart NPC's path finding is relatively quick  and is done on the server using A* path finding. However it does not need to be done for simple creatures like sheep which are very common within the game world and could potentially take up a lot of time being processed for minor results. This is why the Simple NPC class exists. Their movement is incredibly fast to work out and still gives them a decent chance of reaching their destination. The majority of NPC's in the game do and will inherit these behaviours(Some do not such as Ghosts, which pass through walls). For example currently Sheep  inherit from 'SimpleNPC'  which allows them to wander aimlessly and flee danger where as Guards inherit from 'SmartNPC' allowing him to avoid falling off cliffs or other daft things on his journey to rescue you from being attacked. There is currently 3 animals, 2 monstesr and 1 boss within the game. However I will be adding a lot more as my development progresses.
I touched on collision briefly above, but I had quite a few issues getting the smooth collision I wanted for both NPC's and players. Particularly oddly shaped NPCs. When I last posted I was using a ray casting method that meant if you were clever about it you could get close enough to blocks to actually see through them. I really was not happy with this at all. So this week I spent a lot of time coming up with a better method. Players and NPC's now use OOBB's fit to their size and shape for collision. This prevents either from getting  inside blocks or through holes and gaps they are not supposed to. For instance sheep are slightly too long to fall down 1 block gaps and chickens are just the right size to go through 1 block gaps. The main issue for the player I had with collision was getting them to slide properly against walls. That may sound pretty strange, you don't often walk around sliding off walls in real life. But imagine this situation. When you run directly at a wall in a game obviously you will stop. However if you run at angle, say 40 degrees you'd actually expect to move along it rather than just stopping, the handling would feel very sticky and would become frustrating very quickly for the player, especially with added stresses such as being shot at while trying to move out of cover. The new collision I've written came out much better than I hoped and it feels really smooth! It only took a few changes to get NPC's using the same idea, woo! It has allowed me add steps and support for collision with different sized blocks which was pretty dodgy with my previous implementation. It took no time at all to add in previous features from my old collision system such as swimming and the climbing of ropes and ladders.
The underlying GUI system has been pretty poor within the game thus far. I had bolted on a lot of features and it was in need of some love. So I've pretty much overhauled the entire thing and it now supports Window's and controls can be parented to them as well as being parented to other controls. This has made making a lot of the menus in the game a lot easier. This is useful especially for future features I plan on adding. But for now I've added a nice new main menu with  news read and displayed from the web and a animated skeleton chilling by his tree in the background. The logo is very much a place holder. So if you'd like to help out with it, drop me a email.
Since I have been running an online test server. After the 1000th compile it had gotten to be a pain typing in either IP for local or internet servers. So while I was doing the GUI update I also decided to add a working server list for multiplayer which lists all online available servers. Which can be ordered by a few columns to find the one you would like  to join or you can connect directly via IP. This still needs some work. I plan to add more categories to sort by, multiple pages, favourites and most likely a search by server name. So players have no trouble finding others to play with.
I also decided to redo the sky. Something about the colouring of it didn't look right at all. From looking out my own window I noticed that the sky(without the clouds) clearly isn't one colour, which it is in the game. It actually goes from white on the horizon to a sky blue colour during the day. So within my sky shader I added a gradient to do the same and this really makes the sky look much better both during the day and night. If your currently working on something similar, try it out! It's a very simple change that really looks great. From time spent testing things within the game I had also noticed my clouds actually had quite a few seams. On top of that they didn't look right at all since they were being projected onto a sphere. So I wrote a bit of a different system, that uses a plane above the player instead. The plane follows the camera but is kept at a constant height. However the cloud UV's get offset by the camera position so its pretty much impossible to tell the clouds are ominously following you. This really improved them in my opinion. The end result is a pretty different sky to what I've shown in my last post and Youtube videos and in my opinion vastly better looking.
The majority of the other changes have mainly been greatly improving the games performance of both the client and server  and added a skinning system to make it easier for Mattey to drop in new textures. I've also been working  on house and NPC loading for procedural villages for the Human NPC faction which is also not fully implemented yet. So hopefully that'll be my next post. Ideally with much less of a gap in between posts. Hopefully you enjoyed my updates. If you've got any questions on the implementation of things or anything else about this post. Please don't hesitate to post in the comments. I try to answer all comments within a day or two.  Thanks for reading. Also thanks to the Redditor's who commented on my last post and came up with a much more satisfactory bloom method!
My Minecrafty game continues
It's been awhile since my last post and especially my last post to do with my MineCraft inspired game.  This is mainly due to little progress for the game up until recently. Due to a strange bug I encountered causing missing surfaces occasionally on the side of chunks. This took some time to diagnose and fix. As well as a rewrite of some classes to do with it. Which has inherently made the chunk system much more optimised and speedier than its previous system. The bug caused a massive lack of motivation for me due to the time it did take to fix. So I spent awhile working on other ideas but I am happily back to developing this one and I have made some really nice progress. Enough to write a blog post about, so here we go.
Smooth Lighting
A sort of Ambient Occlusion looking effect is the first feature I'm going to talk about. As its the most recent in my mind because it was added just last night. I say "sort of ambient occlusion" as its not really ambient occlusion, its more of a per vertex smoothed light. Much like the Smooth Lighting mod Notch implemented into his game. Here's a comparison shot first of all so you can see the difference. Then I'll go into detail on how it actually works.
Hopefully you can see the vast difference in the above screen shots. If you take a look at the smoothed one(bottom picture). The blocks are much softer defined. Due to the shading in the corners where blocks meet instead of the harsh contrasts you get with per face lighting(top picture).
So how does this work? To understand my new lighting, you need to understand how the old system worked. The old system consisted of having light value per face. When a chunk is initially generated or changed. Lighting data is generated for it in a 3 dimensional byte array. Which stores a light value for each block(0 being black and 255 being completely lit). Each vertex is capable of holding a 'Shade' value, which is a float that can be between 0 and 1. This value is taken in a HLSL pixel shader and multiplies the texture colour making it darker or lighter depending on the value. For instance a shading value of 1 would be a fully lit surface and 0 would be completely black. Although each vertex is capable of holding its own individual shade. The old system got light values by face. Rather than by vertex. So it would get the light value from the block across from where the face is facing. In the shader it also applied a simple directional light to help give the cubes a bit more of a shape. Below is a rough diagram of what I mean.
The new system is based off of this. But each vertex is given a individual shading value instead of it being per face. To get each vertexes shading value. I get the faces light value. As done before. But then depending on the way the face the vertex belongs to is facing and the corner of the face the vertex is. I get the face light values for its neighbours, add them all together and average them out. This gives a smoothish transition between dark and light areas . Especially shadows, but also gives a nice effect on corners where one of the faces sampled is actually inside a block and thus the darkest value possible for light. Giving a dark shading on interior corners where blocks meet. Which is what gives it a sort of Ambient Occlusion look. Â Here's a picture of the same structure but with smooth lighting instead.
In my opinion the new system is a great deal better than the previous one. However there are some disadvantages to it. The main one is that it takes quite a long time to calculate it. Compared to the old system.This is because instead of getting one light value. You are fetching 4 instead.Although this isn't a hugely expensive process by itself. You are getting this many, many times so small changes add up. This can amount to a large amount of CPU time spent getting light values, because of this is the game does not run nearly as well on older weaker CPU's with this new system. The only way around this is perhaps some further future optimising which I have a few ideas on and allowing players in the options menu to enable or disable it depending on their specifications.
New Chunk System
The previous system I have talked about in this blog was beginning to become a bit of the pain. Every time one block was changed within a chunk. It meant the entire chunk had be regenerated. This simply would not work when I wanted to add sun light and later down the road, light sources. These can cause a situation where a few blocks over different chunks need to be regenerated whenever a single block is changed to correct lighting errors. Although I won't go into depth in this post. I massively rewrote this to hold all the vertices and indices used to make each block of the mesh in a dictionary, with the key being their position within the chunk. This meant I did not have to perform the CPU consuming task of rebuilding each cube every time any block in the Chunk is changed. But rather just the block and its neighbours and then compile all the vertices and indices from each cube into one big list to put in a dynamic vertex buffer which takes very little time in comparison.
The other big problem with the old chunk system was mip mapping. The old chunk system relied on a Atlas texture. Which is basically a large texture with all the possible block textures upon it. Then each vertex would be given UV coordinates for its specific block texture within this. The problem with that is areas at sharp angles or far away from you get their texture quality sampled down by mip mapping, the borders between the textures begin to bleed into each other because of this. Which isn't a huge problem if everything in your atlas is the same sort of colour. But for a game like this where you might have brown dirt next to orange lava. You will notice weird orange lines far out on the surfaces of your chunks from the bleeding of the borders of each block within the atlas texture. I looked at a few ways of solving this. But ended up splitting the chunk into 1 vertex buffer per texture. So each texture had a specific vertex buffer. This allowed me to give them individual texture files so there could be no bleed at all. I did worry that the large amount of extra draw calls could be a problem, but so far it hasn't proved detrimental to performance.
Gameplay Additions
The additions I have made so far are quite numerous so I'll only cover the main ones.
- Crafting System - I have changed this quite a bit from the initial way I had set it up. Originally within your inventory you would set items on a 3x3 grid. Much like Minecraft to craft your items. Now however, on the left hand side of the inventory all craftable items appear in a list based on what you have in your inventory. I think this gets rid of some of the difficulty of looking up recipes that games like MineCraft have. Which helps smooth the learning curve and allows players more time actually playing the game.

- Breaking Blocks - Up until now blocks have been broken instantly dropping the items to the floor. Now they have each a set amount of hit points you must bring down to zero with a tool before the break. Showing a cracked texture over them to show your progress, breaking them. Not only this but you can pause for several seconds and carry on mining as the damage will stay on the block for a set amount of time. This also allows other plays to carry on mining the block or to help you mine a particularly resistant block. The crack textures are place holders for the moment.

- Ranged and Melee weapons - The basis for these are in and you can damage other place holder NPCs and players. They also have room for on hit effects for things such as life steal or setting someone on fire. Which will be expanded on for special items later. Projectiles will also get caught in obstacles they hit if they do not impale their target first.Â

- Â Dropped Items - Much like Minecraft item's can now be dropped on the floor and picked up by players. They have basic physics so they will fall if you remove the block beneath them. They are represented by a billboard of its UI icon and play a sound when picked it up.Â

- Transparent Blocks - You may have noticed this from the above screenshot. But I have added transparent blocks, the change in the Chunk system has helped a lot with this. Transparency is done through alpha mapped images. Although there are some glitches in drawing order its difficult to really order blocks which are part of the same mesh and they are barely noticeable.Â

Well that's about it for this update. I hope you enjoyed it. If you didn't you probably should have stopped reading at some point. If you have any questions post a comment and I'll get back to you as soon as possible.
XNA Buffered Input / Text Input
This will be a quick post but it might be useful to some. I assume due to XNA being for multiple devices for some reason it doesn't support buffered input. Buffered input being entering a sequence of keys and getting them out in the order you entered them. This is useful for things like text boxes, which would almost always come up if you are making a PC game. There is some hacky ways you can do it with the Keyboard class. But from searching on the internet I could not find a satisfactory way to do it with the Keyboard class. Instead what I did find while searching through similar projects which I knew had text entry. More precisely the Infiniminer source. I found that they used platform invoking to hook into some windows DLLs. Allowing them to mediate between the messages received by the Game Window. This method actually works really well. The following Solution is an example that shows you how to do this using the EventInput class(from Infiniminer) with a tiny addition showing you how to buffer the input and add additional functionality such as backspace.
Here's the source:
Screenshot:
Big Update – 3D and more!
Over the past few weeks my has had some radical changes for the better. The game started off as isometric, however after some thought and quite a bit of testing. I found for the end user that building in a isometric world with many layers of height is some what tricky and becomes difficult for the player fast. So I decided to change my entire game over to 3D. I am still using XNA and the change didn't take all that long at all. I had to do a fair bit of reading up on related 3D matters and I created an experiment project. So I didn't mess up my games one. After some experimenting I got a working chunk system similar to my Minecraft clones.
This progressed pretty quickly into a more functional class with texture mapping and some other optimizations until I had something like this:
After some performance testing and playing about I was fairly secure in the performance and feasability of what I wanted to do. So I went ahead and decided to swap out both the Map and Actor managing classes of my game. So I could keep the core game logic and such. Which is mostly server side anyway. Due to the isometric nature of the game everything was already pseudo 3D both on the server and client so a lot of the methods that needed to be emulated/replaced by my new classes were fairly easy adjustments. For example dealing with the map format was the same as it has XYZ block values. This made the map manager a fairly easy change. Replacing the actor manager was slightly more complex as I had more things to worry about such as bone based animation among other things. So I rebuilt the class from scratch until it was performing all the roles I expected it needed to fore-fill. Although I had a few bugs and mishaps with scaling and other things from modelling packages and my own game.
Due to the change in media a lot of XML data had to be changed and added to. As well as media which was a bit of pain as I am no artist. Which you can see by the giant black stick man. However I managed to make some place holding media at least. The XML was an easy enough change however the media I am still at this point replacing a lot of the content I had created in 2D in 3D form.
Once I had everything functioning as it did with original isometric map. I pushed forward with an idea I had for item crafting. Basically I wanted to allow the player to create their own items within the games context and art style. The fact that world is all block like and I had written a chunking system earlier lead me to the idea that item themselves could be made out of various coloured blocks. Then scaled and attached to various bones on an actor. So I went ahead with this idea. I wrote down a rough idea of what I wanted and came up with a rough version rendered over the map by fiddling with the depth buffers. This was fairly hazardous and a quite inaccurate so seeking other solutions. I found render targets did the job much better and then I could just render the block I was sculpting to a texture then display the texture to the screen. To create a view port of sorts.
I then created a pallete for the player to choose colours of blocks from so they could create their items a bit like a '3d paint' and later added a window using the GUI system(Nuclex) used in my game. So users could add descriptions, names and offset their items positions as well as the network functionality and server side I needed to store the items players will create.
From playing about with it I noticed quite a big issue was that I had added no way to preview it on an actor before you submitted it to the server. Which is quite impractical. So I added a preview button allowing the user to toggle an actor in the view port wearing the item in the slot you had selected for it and proceeded to polish a few elements of the components such zooming and better rotation via middle mouse.
For those that are interested I have also recorded a video of crafting a fairly simple helmet. Which you can find here.
The other huge update I made to the game has been physics. I started off with a small experiment project as before with converting it to 3D and tried a few different physics engines both native c# ones and wrapped C++ ones like Physx. However I settled on using BEPU Physics. The performance from it seemed great for what I intended for it and the implementation of it into any project is pretty easy. Its design seems very well thought out and clear and its also open source. So if I come to a point where I really need a feature or a fix I can at least attempt to fix it myself.  After some debating I decided to implement the physics server side. Which is unusual for most games. As physics can incur a lot of performance and memory use. However it does help prevent movement cheating and easily synchronised simulations if its all happening on the server. With the players input being sent to it for movement and other things. The isometric equivalent to this previously worked somewhat the same with the path finding being worked out server side. As I only really intend to use the physics for character collision and a few other neat things. That I'll hopefully be showing in the future. The performance hit for the server will hopefully not be too great. As I don't want it to be too expensive for people to host their own servers on VPS's. I'm still a little unsure if this was the right decision. But I am prepared to change it if its not.
There's been a lot of text and pictures and hopefully you got through it. I have done a lot in the last few weeks and I have been holding back blogging about it back as I am unsure anyone will even read this! Though my site does get quite a few hits for my XNA tutorials. Â However if you like the looks of the game hopefully you'll come and play it when its ready. More updates soon!
A* Pathfinding in XNA
Source Example at the bottom
In my game I use A* path finding to help my entities and players move across the maps accurately. A* is an algorithm that searches an area, moving towards its end goal using a scoring system and a bit of guess work(heuristic). Without checking all the squares on the map(Dijkstra algorithm). This creates quite a fast method for finding paths across even fairly large maps.
To create my path finding I followed a great article which can be found here: http://www.policyalmanac.org/games/aStarTutorial.htm This is a really good article to get you started with the implementation A* in any language. So if you are unsure of A* and want to learn more. I'd read it first before proceeding.
Rather than implementing it straight into my game I created a side project so I could make sure its working without any part of my game interfering. Using a simple grid representation of a 2D world. The tiles were coloured depending on how they were used by the pathfinder or what they are on the map e.g. Red for obstacles, white for open space, light blue for checked areas, dark blue for tiles add to the closed list and green for the end path discovered.
After following the above mentioned article I noticed two main performance problems with my code. Which would prevent me from using it in my game.
Binary Heaps
One is mentioned in the actual article and it comes around maintaining the open list. During the algorithm you need to keep the lowest cost node when checking neighbouring nodes easily at hand so you can move to it next. This is because it is the best choice and puts you closer to your goal destination. Although because you may be keeping many, many, many nodes in your open list. Possibly upwards of 10000; sorting them isn't really an option the sheer amount can take a lot of time not to the mention the amount of times the sort needs to happen.
The article proposes using binary heaps. A binary heap is a tree like structure where the lowest or highest depending upon what you need. Is always on top. Where as the order of the rest of the tree is fairly scrambled. Which in this case isn't a problem because we only need the lowest cost node. In fact its better this way and here's why; When you add a node, it gets stuck on the bottom and then you gradually loop your way checking to see if it has a lower cost than its parent and swapping them if it does. You make very little comparisons unlike comparing near the entire array with most sorting methods. The same is true when removing nodes. But sort of reverse, instead you swap the lowest item in the tree(end item in the array) with the one you want to remove then simply resort it using a similar method as adding a node.
Binary heaps made an incredible difference to the speed of my path finding. The current map's size in my game is 256x256 tiles. Moving from one side to the other with a conventional sort method for the open list was basically impossible as it spent so long doing it. I never actually saw the end to know how long it would take, it took that long!. However I did try moving half way across the map and it took any between 50 to 3000ms on average. Depending on what was in its path. Which is not sustainable in a real time game environment. However with binary heaps, it takes on average 40ms to scale the entire map from 0,0 to 256,256 with 90% of the map covered in obstacles! Assuming there is a path. Which brings me to my next optimisation.
Its Endless!
The second performance problem I came across is if the path is not actually reachable. This can happen if the actual end node is a obstacle(which can be easily fixed by just checking that when you start path finding). Or if there is some obstacle, for example a diagonal river running from one corner of the map to the other and your destination is on the other side of it. In a game environment these circumstances can come up often. I tried a number of ways to resolve this. The first method I used was a quick fill in the path finding method. To make sure the path was reachable. However this is far too slow to do each time.
However you can use quick fill in a pre-calculated manor. Which is not useful for my game due to constantly changing  obstacles but may be useful for yours! During the loading/creation of your level you can use quick fill to split your map into regions. Regions are areas that cannot be reached by one another and should be quite easy to work out with a filling method. When you go to path find you can simple check these region arrays or whatever method you are using to store them and make sure the start and end points of your map are not in different regions. Tadaa! However the problem I have with regions is that my map can be built on and changed by the players and NPCs. This means that I have to recalculate regions every time this happens. Which is not really performance centric when a lot of that is going on in a standard game play session.
So the way I ended up dealing with impossible paths is by allowing only for a certain amount of items in the closed list. So when its added a certain amount of nodes to it. It will just stop searching. Although its not the best method because it means it could miss possibly a very long and indirect route to its goal. It does stop the path finding from hanging as it checks the entire map before rolling over and exploding.
If you made it through all that writing then well done to you sir! Here is a video of it in use both in my experiment project and the final implementation of it in my game. Below that is a Visual Studio C# project for you to tear up and use as you wish.
Videos
Source
XNA Isometric Maps
Isometric maps can be a tricky affair in games. But once you've got the basics its incredibly easy to expand on. In this short article I am going to talk about how to do basics of the isometric maps in your game. Including positioning tiles, depth sorting and camera movement. I will include small amounts of code as we go through to help make things clearer. These samples are in C# for XNA. Though you can quite easily translate them to your given platform and language. Though this article requires a basic knowledge of XNA and C# to fully understand it.  The source project of the finished code is available at the bottom.
The basic idea of drawing the isometric tiles is that you overlap them. What this means is a standard tile doesn't actually fill the entire texture. For example the below tile is 128 by 128 pixels. This is because my game uses blocks rather than flat tiles, if your game world is made up of flat tiles you can simply use a tile that is half the width as its height e.g. 128*64. This allows for the tilted perspective of the tile. The 4 corners of the texture are made transparent so when they are drawn they cannot be seen.
At this point it might a be a good idea to create a class with the name you want for your isometric map class. As we are going to delve into some code. For the ease of this article. The the available tiles for your map will be kept inside a List<Texture2D> collection and will be referred back to by a index variable in a Block class(class holding attributes of each block). So we need to first of all make 2 classes. 1 to handle the actual map and 1 to hold data for singular blocks. Like so:
class Map
{
List Tiles;
Block[,] Blocks;
int Width;
int Depth;
public Map(ContentManager content, int width, int depth)
{
Width = width;
Depth = depth;
// Populate your tiles list with your textures here
Tiles = new List();
Tiles.Add(content.Load("sampleblock"));
// Initialise block 2D array
Blocks = new Block[Width, Depth];
}
///
/// Called during Game update method to update
/// map and input.
///
public void Update()
{
}
///
/// Draws map
///
/// <param name="batch" />
public void Draw(SpriteBatch batch)
{
}
///
/// Destroys resources used by map
///
public void Close()
{
}
}
class Block
{
public byte Tile;
public Rectangle Position;
public Block(byte tile, Rectangle position)
{
Tile = tile;
Position = position;
}
}
This is a fairly basic class and there should be nothing new here. We have a class for managing our map and blocks. In the map class we have a List of textures to use as tiles and a 2 dimensional array to represent the map. The next step is working out the position of the tiles. At the moment we are only account for a flat isometric map and we'll add height in another tutorial. To work out the position for each tile. We must loop through each of them in the constructor and assign them a position as we initiate the element in the 2 dimensional array 'Blocks'. This is done fairly easily. We know that rows in a isometric map are roughly diagonal of each other and that the tiles fit together by adding half the width and half the height to the current position of a Block because of their perfect perspective. This is all we need to do along a row to position it.  We can then just increment through the blocks using this idea to position them correctly.
// Initialise block 2D array
Blocks = new Block[Width, Depth];
// Used as a base width and height for varying sized tiles
int baseWidth = 128;
int baseHeight = 64;
// Position blocks
Rectangle position = new Rectangle(0, 0, Tiles[0].Width, Tiles[0].Height);
for (int x = 0; x < width; x++)
{
position.X = (baseWidth / 2) * x;
position.Y = (baseHeight / 2) * x;
for (int z = 0; z < depth; z++)
{
Blocks[x, z] = new Block(0, position);
position.Y -= (baseHeight / 2);
position.X += (baseWidth / 2);
}
}
Now we have our positions for our blocks. All we need to do is render it. To get them in the right order so they overlap properly may sound tricky however its actually pretty simple. All we need to do is make sure we draw them in a order where the blocks towards the top are drawn first and the blocks towards the bottom are drawn last. So they are drawn over blocks behind them. We need to draw them in the Draw method of the map. So we start with the top row and increment through the columns of that row. So they become obscured by blocks in front of them. Then we have our basic flat isometric map drawn on screen.
///
/// Draws map
///
/// <param name="batch" />
public void Draw(SpriteBatch batch)
{
for (int x = 0; x < Width; x++)
for (int z = Depth - 1; z > -1; z--)
{
Block block = Blocks[x,z];
batch.Draw(Tiles[block.Tile], block.Position, Color.White);
}
}
You should now have something that looks like the picture below. If you implement your new map class into the game1 class created by XNA by default.
Notice how you can only see the side of the map? This is because currently we are at 0,0 camera position on our map. So lets change that by adding camera movement to our map class. The camera movement works by offsetting the position of the map during the draw method. To do this all we need to do is add a variable to our class called Offset which will be a Point and give it a initial value of 0,0 in its constructor. Then in the draw method we need to take the block.Position and add the offset to it. So that the blocks will be offset when drawn by the amount in our Offset variable, however we still can't move right? That's where key input comes in.
///
/// Draws map
///
/// <param name="batch" />
public void Draw(SpriteBatch batch)
{
Rectangle drawPosition;
for (int x = 0; x < Width; x++) for (int z = Depth - 1; z > -1; z--)
{
Block block = Blocks[x,z];
drawPosition = block.Position;
drawPosition.X += Offset.X;
drawPosition.Y += Offset.Y;
batch.Draw(Tiles[block.Tile], drawPosition, Color.White);
}
}
Now for the key input. In the update method for your map class you can take key input and change the offset X and Y accordingly and this will move your map/camera around allowing you to view your map. This is pretty simple so here is a snippet to move the camera with the WASD keys. Which should give you enough of an idea on how to change them yourself.
///
/// Called during Game update method to update
/// map and input.
///
public void Update()
{
// Move offset according to key press
KeyboardState state = Keyboard.GetState();
int speed = 10;
if (state.IsKeyDown(Keys.W))
{
Offset.Y += speed;
}
if (state.IsKeyDown(Keys.S))
{
Offset.Y -= speed;
}
if (state.IsKeyDown(Keys.A))
{
Offset.X += speed;
}
if (state.IsKeyDown(Keys.D))
{
Offset.X -= speed;
}
}
That is all the basics covered for creating your isometric map. The map class is very simple to add to your Game class. Simply initiate it in the LoadContent method and call its Update method in the Game Update method and its Draw method in the games Draw method. Like so:
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Map Map;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
Content.RootDirectory = "Content";
}
///
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
///
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
///
/// LoadContent will be called once per game and is the place to load
/// all of your content.
///
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
Map = new Map(Content, 128, 128);
// TODO: use this.Content to load your game content here
}
///
/// UnloadContent will be called once per game and is the place to unload
/// all content.
///
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
///
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
///
/// <param name="gameTime" />Provides a snapshot of timing values.
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
Map.Update();
base.Update(gameTime);
}
///
/// This is called when the game should draw itself.
///
/// <param name="gameTime" />Provides a snapshot of timing values.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
Map.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
Download
Download Source
Required:
Visual Studio 2010 Express(Or above)
Extensions/Issues
This is obviously very basic and there is a lot you can do to improve upon it. I may write some further tutorials on how to do some of the following subjects. But main areas of extension are:
- Culling - Drawing all the blocks on a large map will be very slow and you should try to write a culling system that only draws blocks currently within your screen space.
- Height - At the moment the map has no easy way to put blocks higher than the floor without creating oddly sized blocks. You can add a third dimension for this and change how the initial position is worked out in the map constructor to account for this with something like:
for(int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
{
position.X = (baseWidth / 2) * x;
position.Y = ((baseHeight / 2) * x) - (baseHeight * y); ;
for (int z = 0; z < depth; z++)
{
Blocks[x, y, z] = new Block(0, position);
position.Y -= (baseHeight / 2);
position.X += (baseWidth / 2);
}
}
Past Work – Online Role Playing Game
This is a project I spent about 9 months in total working on during my free time. While attending college. Although I didn't turn it into a game. It had all the features I intended it to. Though I never got round to creating the actual content such as art and maps.
Both the server and client are written in C#. The client uses the C# wrapper for Truevision3D for rendering and collision detection. Everything else is created from scratch while writing the game. The server is actually split into two. One server for the zones and account management and  another for handling the AI path finding, which receives requests from the main server. The main server actually allows for as many path finding servers as you like because of this request based method. Which makes having a lot of AI fairly scalable for the server as they can be located on separate machines and networks. Please note the media in the following screenshot's were place holders.
Features:
- Client - Server Architecture: The game was completely networked for exclusive multiplayer functionality. The idea was that it'd be hosted centrally by players or me. So all functionality and game logic has been implemented on the server side. Such as AI, combat and scripting. With very optimised networking to allow for large volumes of concurrent players with a fairly efficient server and scripting system.
- Day and Night: The game used a centralised time from the server. The client used this to initiate a smooth day to night and night to day transitions which moved the sun, moon and the colour transition of the sky. Below is a shot of it in action.
- Items and Attachments System: Item templates are held in XML with attachment groups and texture groups information. Allowing for easy access of item information which in turn made writing them from scratch a very easy and uniform affair. Attachment groups are used for such things as weapons, clothing and armour. They list meshes which attach to bones on the character and texture groups for clothing and re-texturing of specific parts of a character. This is also used for customization with hair, beards and default clothes. Below is an example of a player with multiple textures, hairs and a sword.
- Map Editor: The client loads maps created with Planet X Map editor. The client is also able to export certain map data for the server. Examples of this are path finding boundaries and spawn points for NPCs. So much of the games content can be easily created using the Map Editor. The only things that are separate from this are scripts and template data for actors and items.
- Effects System: Animated meshes and particles can be assigned to player as attachments and in locations on the map through the scripts and the map editor. These can be used extensively for spells, skills and similiar features. Creating bright and luminescent effects such as fireballs that track the enemy or fountains erupting water within map architecture.
- Scripting: The server allows extensive use of C# for scripting for almost all aspects of a game. Including actors, AI and items. The server compiles the C# to an assembly. So scripts can run at a native C# speed and can inherit and use classes already built into the server. Allowing for speed and full C# functionality. As well as easy access to new functionality written into the server and other scripts.
- Dialogue System: Dialogues are created server side using scripting and can have many components such as item slots, options and many other features allowing the creation of quests, helpful information and shops with ease and complete customizability.
Videos
Below is some tests of shaders I wrote in HLSL for the sky and clouds.























