Friday, April 29, 2005

The Dragon that follows you!

final fantasy style rpg graphics showing anchor game programming technique

I want to write some code, anchor code. Very simple code, but I'm going to talk about it anyway. What I'm after is having something follow the character. Not in a complicated way, rather at a fixed distance and always behind the character. One might remember early games where you might have flying dragon behind you or an egg that grew up as you fought monsters. It could also be used for a light spell, 10 game units behind the player there could be an orb of glowing light as I've attempted to show in the picture (the sprite is from Final Fantasy, the grass tile I took from Tsugumo's Pixel Art Tutorial). That kind of thing.

Currently I've lost touch with my code. I'm attempting to rectify this but instead of blundering in, I'm going to prototype my function in a C# windows program. I like to do this as it keeps my windows knowledge fresh and always reminds how DirectX is setup and what's useful bits and pieces DirectX has. I find on a big program I totally forget a lot of the basic stuff.

So for the program I want a DirectX enabled area, when I click on it with the mouse then a small dot will appear. Then I click again and another small dot appears. But also a third dot appears - the anchor dot on the same line as the first two dots and behind the current position of the player.

I had no problem getting my small windows program running but I had problems with the maths - hate it so it so much! So I asked on GameDev and got a very quick very correct answer.

I'll give a brief overview of the code in case anyones interested, I was always interesting in how to get DirectX and windows to play nicely together. First let's look at the globals, I'm only going to have three points so I should make an array for them.


private const int maxVerts = 3;
Device device = null;
VertexBuffer vB = null;

CustomVertex.TransformedColored[] verts =
new CustomVertex.TransformedColored[maxVerts];
int numIndex = 0;


So a device, vertex buffer and vert array. These will allow me points to be stored and then rendered. I'm only going to have three points, the first two human entered the third computer generated. The cryptically entitled variable "numIndex" is the vertex index number, the current vertex we want to write. So once we click one we written the first - therefore increase numIndex by one, another click increment it again, then the computer does it's stuff and increments it. One last click and it reverts as does everything else.

Let's look at some of the code. I created a panel and hooked directX up to it. Easy enough. Then in the form designer I double clicked on the panel. This generated a click on panel event and VS.net wrote all the hook up code and deposited me in the OnClickPanel function, ready to write. This is what I wrote:


private void panel1_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
if(numIndex == maxVerts)
{
verts = new CustomVertex.TransformedColored[maxVerts];
numIndex = 0;
return;
}


verts[numIndex].Position = new Vector4(e.X,e.Y, 0,1);
numIndex++;

if(numIndex == maxVerts-1)
{
verts[numIndex].Position =
CalculateTail2(verts[1].Position, verts[0].Position, 10f);

verts[numIndex].Color = Color.White.ToArgb();
numIndex++;
}


OnVertexBufferCreate(vB, null);
}


System.Windows.Forms.MouseEventArgs e this things pretty cool it will tell you all about the mouse which buttons are down the position (which is what I used here) and mouse wheel stuff.

So for the first and second vertices we add a white vertex at the position of the mouse. Then if it's the second click (numIndex == maxVerts-1) the computer calls CalculateTail2 and puts a vertex down at it's return position. The third argument is the distance behind the point that it will place the third point. If it's the third click (numIndex == maxVerts) then the vertex buffer is reset as is the click count, click count now that would have been a good varaible name, oh well too late now.

Let's look at the magic function the computer uses to work out where to place the third. I'm awful at maths, this game from the gamedev message boards some one answered my plea for help.

It find the vector running between those two points and extends it by D to get the third point . . . well I guess this is what it does anyway :D


private Vector4 CalculateTail2(Vector4 currentPos, Vector4 lastPos, float distance)
{
//If they're the same do nothing
if(currentPos.X == lastPos.X
&& currentPos.Y == lastPos.Y)
return currentPos;

Vector4 p3 = lastPos - currentPos;
p3.Normalize();
p3 = currentPos + p3 * distance;
return p3;
}


Finally I'll render the points. Here's the process function that's called every frame.


private void Process()
{
device.Clear(ClearFlags.Target, System.Drawing.Color.Brown,
1.0f, 0);
device.BeginScene();
device.SetStreamSource(0, vB, 0);
device.VertexFormat = CustomVertex.TransformedColored.Format;

device.DrawPrimitives(PrimitiveType.PointList, 0, numIndex);
device.EndScene();
device.Present();
}


To prevent us having problems rendering we only render what we've assigned in the buffer.

final product isn't it pretty


And there we go a little mini-program demonstrating the technique, of course the main thing is the function, which I didn't write :D But oh well. The white dot is the computer one, the black dot nearest the white dot is the second click dot.

Other News

I'm ripping out my camera class and fiddling with it so it will be more useful and less clumsy. That's todays job. Also in the latest DirectX under DXUT there's suppose to be lots of GUI helper files - to help programmers make a quick GUI but I have no idea, at the moment, how to access these, or even if their avaliable through C#. I hope they are I much prefer having some one do all the hard work for me.

I decided I need to go through my code piece by piece and reconstruct it into a new project. When I tried to sub-divide it into namespace before - it's painfully obvious I failed. The current architecture I'm now implementing seems to go against the suggested grain, a big fat singleton that everything's connected to. There are some words on the different types of singleton here in C#.

But everything needs time! Eveything need texture management! Maybe everything needs to know the GameState! Player Account kinda needs to be known by everything!

That's what's happening anyway I think it should be okay. There's nothing more that needs to be in the singleton everything else is handled at a lower level. It will take some time to pull everything across but at least it will reaquaint me with my code. Also as I do this I convert it all to the latest SDK and improve any oversights so it's not a bad thing.

Maybe some day soon I'll even have some kind of game - that would be novel!

No comments: