Wednesday 23 September 2009

Here's the puzzle test thing.

Here's MatchUp. It's been sat on my hard drive for a few weeks now so I figured I'd better put it out there just so I've got someothing to show for my time spent. It's a puzzle game I created to test out my game framework I've been working on. Tried it on as many computers as I could get my hands on but if it does have trouble running on your machine then please leave a comment with a brief explanation and if possible an error code. Alternatively you could leave me a comment to let me know what you think. It ain't groundbreaking but it works and means I can now move on to making proper games. The first of which I've already started but that a story for another post.

MatchUp

Double points if you match the combo with the required multiple on the right side of the screen. The rest is pretty straightforward. Bigger combos mean more points. Bonus 10000 points for clearing the board. Leftover time is converted into points at end of game.

Tuesday 25 August 2009

Remember that puzzle game I mentioned?

Well it's nearly finished. Only 4 weeks overdue. Things never do run as smoothly as expected, especially when life gets in the way. In any case the match 3 puzzle test program is virtually finished. I will be updating in just a few days to post a link to the finished article.

Monday 6 July 2009

Currently...

Well now that I've got a half decent framework up a running I've just started to build a test project. Nothing special, just a simple match 3 game to make sure the framework is useable. So far so good. I'll post a link to the finished project once I'm done. Hopefully won't take long. Famous last words.

Tuesday 9 June 2009

The other thing

While working on my sprite editor I've also been working on a more consistent framework for my projects. Whereas my previous isometric engine utilised OpenGL, it was kind of thrown together with little thought for what was where with the best intentions of sorting it out later. Instead of going through the laborious process of untangling a big mess of code I decided to start from scratch and, armed with the knowledge garnered from writing my isometric engine, I was able to decide on what was needed and what was completely unnecessary. With the new framework I've separated all aspects of the basic structure into clearly defined units.

I have a utilities unit which contains the main Game class. The game class is used for storing common objects that all games would contain;

log file (Class)
quit flag
title
framerate timer (Class)
pause flag

The Utils unit also houses some commonly used functions. All subsequent units have access to the Utils unit.

The Graphics unit houses the Screen class and the Sprite and SpriteManager classes. This is the only place where direct OpenGL calls should be made.

The Input unit is used for interfacing with the mouse and keyboard. I am using SDL for input but all SDL calls are contained here and there is no reason to directly call SDL outside of this unit.

Here's a screenshot of a very simple program written to test the framework. It is approx 200 lines of code in the main program since most of the work is done behind the scenes in the framework or encoded into the sprites using my sprite editor.


(Oh yeah, I borrowed the sprites from the Internets)
Download it here.
Use arrow keys to move one of the guys and be sure to click and hold for flames galore.

Monday 8 June 2009

My sprite editor

Since my last post I've been creating a sprite editor which allows me to load a sprite sheet and section it off into frames. I can then also anchor points so that animations are drawn smoothly and trigger frames so that when I use the animation in the game I can look out for these triggers and generate an event based on the trigger value. For instance a zero would be a null trigger since the default for all frames is a zero. However a trigger value of one might be the shoot trigger. In which case I could generate bullets whenever this trigger frame is drawn. Instead of having the bullets generated at the beginning of the shoot animation I could have them generated at the exact frame where the gun recoils. Another example would be the jump animation. Let's say we've got a Prince Of Persia-esque character walking along then the player hits the jump button and this begins the jump animation. Now in this version there's a few frames of pre jump action where the character compresses his body then explodes into the jump. It would seem a bit odd to have the character jumping the instant this animation starts so instead I add a trigger frame at frame 4 and the animation is much more convincing. Now this could all be hard coded but the problem with hard coding things like this is that it's much more effort and should the need arise to change the animation then the code would need editing and recompiling, also the code tends to look like crap when there's special case stuff like that dotted all over the place.

Saturday 25 April 2009

Boring boring tools

After working on the isometric engine for so long and hitting countless dead ends and brick walls I'm currently taking a break from all that by building some tools for use with the engine. I'm currently working on my sprite editor which will allow me to import a bitmap image, split it into frames, add anchor points to each frame and then save it in my hand rolled sprite format. Alongside that I'm just learning a bit more about OpenGL vertex arrays and seeing if I can utilise them to increase my ever dwindling framerate. Did check out display list but they seem unsuitable what I'm doing not only because they are now deprecated and probably won't be supported at all much longer but also because they only seem to be useful for static stuff. Might be handy for a UI overlay but aside from that I can't find much good for them. I'll try and post a bit more from now on too.

Wednesday 25 March 2009

A minor victory

Apologies for the delay between posts. Had to move flat and so programming took a bit of a backseat. After trying to squash the draw error using various methods I've finally made some progress using masking. I can now redraw the entire area occupied by a sprite correctly with any overlapping objects drawn either behind or in front without any issues. As a result I can also implement a dirty rect system for redrawing objects. The plan is to create a grid of rectangle. When anything moves a flag is switched on the relevant grid locations and all objects that are within those sections are redrawn. Should save a lot of time when it comes to drawing any scene. Current concerns lie with scrolling. If the user scrolls the scene then everything will need redrawing and since the camera will probably lock onto the player this means full redraw with every movement. I'm sure there's a way of shifting the colour buffer so that the OpenGL moves the ready drawn scene and the only redraw will be things coming into view. Right now I've got other stuff to worry about.

Friday 20 February 2009

Can't talk now. Moving

Just finished moving hence there's a distinct lack of updates or programming of any kind going on right now. Hopefully get some work done tomorrow, will update ASAP.

Monday 9 February 2009

OpenGL is here

Finally got round to porting across to OpenGL. It's so much faster. With the same number of objects (78) and no optimisation (i.e all objects redrawn every frame) I'm getting 1300 frames per second in windowed mode, compared to 50fps when using Windows GDI. That's a nice healthy number since my target is 60fps. Still got some bits to do and my textout function seems to take a huge chunk out of the framerate so it runs a lot slower when in debug mode with all sorts of data on screen. Although 1800 won't be the final framerate since I'm expecting to have hundreds of objects on screen at the same time so this will obviously slow things down but it does mean I've got a lot of room to play. Once I've got it running properly with that many objects I'll start adding the selective redraw stuff and maybe double linked lists to speed up the sorting algorithm. My friendly host JDarling from EonClash has given me some pointers on linked lists so I'll be reading up on that soon enough. I'll post some screens and a new download very soon.

Friday 6 February 2009

Nearly done

After much messing about trying to calculate the correct section of image to cut out I finally managed to get it working on one specific object and best of all I can have objects overlapping as much as they like and it still looks correct. Next is to make it so only objects that have changed are redrawn and I can carry on and look to porting it to OpenGL. As I said before, I can hopefully do away with the expensive sorting algorithm with costs N*N-1 (N=Number of objects) checks to correctly sort everything without the danger of overdraw. I was going to use a double linked list instead of the dynamic array that I've got at the minute but it was taking a long time to get right and kept throwing up bugs when it came to swapping objects around. I guess that's the danger of linked lists, you either get them right or leave well alone. Trouble with the new method is it's fine for the one object I've been testing but if I make all objects use the same method it slows stuff down way too much which is why it's so important only certain objects get a redraw. Guess I'll do the "dirty" object stuff next then make all objects use the same method.

Thursday 5 February 2009

Getting there

Finally got the chance to squash this bug and so far it's looking hopeful. In fact, the redesign has meant that I may be able to speed the draw code up. The reason for this is that I was forced to find a way of preventing objects competing for the front of the queue. It only happens in certain circumstances but is a major problem if I'm to retain the freedom offered by unusual dimensions and locations for any object. If for example only 3 objects are on screen but object1 should appear in front of object 2 and object 2 should appear in front of object 3 and object 3 should appear in front of object 1 it causes one of the objects to pop out from behind an object that is supposedly obscuring it Scroll down to "Big Mistake" post to see a screenshot of the bug in action. The solution which means hopefully faster redraw is as follows:

  • Loop through the list of objects onscreen.
  • At each object quickly loop through all other objects and check for overlaps (2D overlap with actual sprite, not a 3D collision) with surrounding objects.
  • If there is an overlap with an object then check to see if this object is in front of current object about to be drawn.
  • If overlapping object is in front then cut out section of overlapping objects sprite that actually overlaps our object's sprite and draw it over the top.
  • Repeat for all overlapping objects and when finished move onto next object.
This means that anywhere on screen we can draw an object and it will automatically be drawn correctly. Effectively I only have to draw objects that have moved or changed frame and anything not changed does not need redraw. This of course is much faster than redrawing everything onscreen every frame. It also means I haven't got to run sorting algorithm for any objects really since the order that objects get drawn isn't important. All I need to do is check what's onscreen and redraw stuff that's changed. That's the theory anyway. Might be more difficult in practice especially when I come to putting this into OpenGL.

Tuesday 3 February 2009

Possible solution

After spending yesterday thinking of the best solution to my sorting problem I have decided the best way of solving the problem would be to perform sectional redraws of objects that have objects in front of them. This would mean that certain objects would be partly redrawn multiple times which seems a waste of graphical grunt but i'm hoping that once i've converted to OpenGL it'll offer enough spare juice on the majority of computers not to be too much of an issue. My only other solution would mean a complete redesign of the code from the ground up and the possibility of not working at all. I'll implement the new method today so watch this space I guess.

Monday 2 February 2009

Big mistake

After squashing the collision detection bug I thought I'd be able to start making a usable engine using OpenGL but I've discovered a show stopping bug and am now comtemplating how to proceed. Here's a screenshot of what's gone wrong.As you may have noticed, the draw order is all buggered. There's a very good reason for this and it isn't really something I saw coming. I did ponder very briefly if it was possible for this to occur but figured if it could happen I'd deal with it when it did, and it has. In essence: Each object is at the bottom of the list (nearest the screen) but is also behind the object at the top (furthest from the screen) of the list and so things poping out from behind other things when they shouldn't. No object is decisively in front so the sorter orders them incorrectly. Back to the old drawing board.

Sunday 1 February 2009

New screenshot


Here's a new screenshot with a couple of new objects I added. I drew them a few weeks back for a mockup but have now encoded them as objects and dumped them into the program. Remember, each item on screen is a separate object. That means every floor tile and both the TV cabinet and the tv. Though I realise I could speed things up a whole lot by compositing the floor into one image at startup and redrawing that before placing all other objects on top.

Saturday 31 January 2009

Depth sorting = easy when you know how

Just finished adding quick and dirty load and save routines. Just means I can place some objects, save them and it will automatically load them back in when the program starts. Anyway, the main thing I wanna talk about in this post is depth sorting. My ideal solution would have been to have each object calculate a ZOrder based on it's current position and then sort the object list and draw. Like I said, this would have been the ideal solution. Instead I've got a solution that works but is not as cut and dry as the previous method. Before I start I want to explain why this has been such a problem. Most isometric programs are tile based which means all objects occupy the same amount of space and any object that is larger than a standard tile is divided into two or more objects. What I needed for my engine was something much more versatile. Something that would accept objects of any size and any location, not just stuff that was for example 32x32x32 and ultimately only ever moved across one tile at a time. After countless experiments attempting to obtain a unique ZOrder based on the X,Y and Z and after many more tests the Width,Height and Depth also. None of this worked and despite many tutorials giving off a supposed correct formula it still didn't work in all situations so I plugged away experimenting until the solution struck me. I have no idea how many people have used this same method but it is not one that i've come across yet, however I have a feeling the ArmyOfTrolls game EdgeRetroHouse had a similar way of doing things even if the actual methods were never published. Once I'd got the method it seemed so obvious, just wish I'd thought of it sooner.

The Method - Requires that no two objects ever intersect.
If (Object1.X>=Object2.X) and (Object1.X>Object2.X+Object2.W) Then Object1InFront=True
Else
If (Object1.Y>=Object2.Y) and (Object1.Y>Object2.Y+Object2.H) Then Object1InFront=True
Else
If (Object1.Z>=Object2.Z) and (Object1.Z>Object2.Z+Object2.D) Then Object1InFront=True

Note: I have already set up a DrawList which is populated by objects that are on screen. This ensures anything offscreen is not part of the sort process. All visible objects are added to the DrawList but are not in order. The DrawList is then sorted.

Object2 is always after Object1 in the DrawList. If Object1InFront=True after our checks then we can swap their position in our DrawList. So next time round "Object1" will actually be Object 2 and vice versa and the same test will result in Object1InFront=False. I will be happy to provide some source code if there is sufficient demand.

Woe is me. I found a bug.

While attempting to fix the blue cube sorting bug I discovered a more serious problem with my collision detection which I should have realised would happen when I wrote the code. Since collision detection occurs when the corner of an object intersects another object it would seem that all we have to do is check all corners of two objects to check whether they are colliding or not. This works perfectly for bounding boxes in 2D but when it comes to 3D it's not so easy. If one object sufficiently large in the X and Y planes but relatively thin in the Z plane and the other object is large in the Z plane but smaller in the X or Y plane then the program will allow the two objects to intersect without noticing a collision since no corners are within the other object. Here's a wireframe diagram of what I mean.
See what I mean? Even though the objects are clearly colliding there isn't a single corner on either object that is within the other object and so a collision is not detected. Will look into some collision detection stuff for 3D at some point. Coming next is my depth sorting.

Friday 30 January 2009

New version

Posted an updated version of my prototype today with mouse scrolling which you can get here. Just hold down left mouse button and move it to scroll. Make sure you press D first to see the draw list fill up and empty out as objects come into view. Pretty neat. There's a read me with all the controls inside. Remember this is only a test program so the controls are not particularly well selected. Here's a screenshot with some objects stacked on top of each other and still being drawn in the correct order, which is something I'll go into with my next post. BTW, the blue cube and the two chests have incorrect dimensions so may result in depth sorting issues. This is not a code bug, but a bug in the object which I'll get round to.
Run IsoTest.Exe

Controls

Hold left mouse button and move mouse to scroll map

Up = Move object north
Down = Move object south

Left = Move object east
Right = Move object west

Q = Move object up
A = Move object down
There is a known bug sometimes when an object is on top of another object which causes the objects to flicker.
It is known, and I know why it's happening so I fix it when I get round to it.

M = Select next object

O = Change object type (If object is changed and ends up becoming intersected with another object as a result
(i.e object suddenly gets bigger and is "inside" another object) the object will not move until it is no longer
inside the other object(i.e is changed to a smaller object to when it go stuck).
Best used when object is away from surrounding objects.

1 = Increase width of object
2 = Decrease width of object

3 = Increase height of object
4 = Decrease height of object

5 = Increase depth of object
6 = Decrease depth of object

7 = Increase anchor X position
8 = Decrease anchor X position
Anchor is the drawing offset of the object's bitmap, it should be the pixel that corresponds to the rear bottom left
corner of the object. Best not to touch this as it will bugger up the drawing position of the object.

9 = Increase anchor Y position
0 = Decrease anchor Y position

D = Enable debug mode
This shows the draw order of all objects(Constanly changing)

All graphics are mine so please don't steal my poor programmer art.

Thursday 29 January 2009

Obtaining screen coordinates

In order to convert an X,Y,Z coordinate into X,Y screen coordinates I needed to decide which axis was which in terms of isometric direction. Using the cartesian system the X axis runs horizontally across the screen and the Y axis runs vertically up and down the screen so something that worked logically with that in mind seems the best method to use. The following diagrams illustrate the decision I had to make regarding the 3 axes of an isometric or more importantly the Y and Z axes.
The X axis is the same in both directions however the Y and Z axes are reversed in Method 2. Method 1 is the standard rotation used in 3D graphics with the Z axis going "into" the screen and as such would seem the obvious choice for my purposes. As a break from tradition I decided to go with Method 2 for the purposes of my isometric engine since when it comes to the perspective I'll be using for the project it makes more sense to imagine the objects or tiles to be viewed from above for the purposes of converting from 3D to 2D. I'm having trouble explaining why that is but it makes a lot more sense to work in X and Y rather than X and Z when it comes to simply moving objects around on a flat surface. Hope I made this clear. Anyways, the maths behind converting these coordinates is as follows:

Screen.X = X-Y

Screen.Y = ((X+Y) Div 2)-Z The Div is a simple divide but it also rounds down the result into an integer value. Very handy. Divide by Zero errors still apply.

This results with slightly skewed but usable screen coordinates. The only values I need from this calculation even values anyway so the fact certain values are displaced is irrelevant. Early on I was moving objects 1 isometric unit at a time but because of the staggered manner of an isometric plane when converted to screen coordinates it meant objects would jump slightly once per 2 unit movement and I spent a lot of time trying to get the perfect conversion formula until I realised that none of this mattered and it actually looked a lot better if all coordinates were first rounded down to multiples of 2.

X = (X Div 2)*2

It actually doesn't matter so much if the Z coordinate is rounded since any change to Z move the object up or down the screen in a straight line so the movement is smooth anyway but if I didn't move it in multiples of 2 it would move a half as slow as X or Y movements. Now that I've got the calculations for 3D isometric to cartesian coordinates the only problem is the origin of all these values is 0,0 on the game window which effectively means 0,0,0 in isometric is in the top right corner of the game window and worse 0,10,0 is actually offscreen so with a slight addition to my formula we have a working screen coordinate generator.

Screen.X = Offset.X+(X-Y)
Screen.Y = Offset.Y+ ((X+Y) Div 2)-Z

Offset is a TPoint (X,Y: Integer) so I initially set this to 400,200 and our object at 0,0,0 appears in the middle of the window. It also means I can increment the offset values and get a scrolling effect and provided I have a clipper so only objects that are within the game window get drawn I have the groundwork for an effective draw routine.

Wednesday 28 January 2009

And so it was written...

Well an obvious starting point for an isometric engine would be an object class for use on all isometric objects. I've decided to call it TGameObject and looks a little something like this.

GUID: Integer This is a globally unique identifier. It retrieves it's value from a simple GUID object that generates unique indices for each object. Handy for locating objects and comparing objects.
Name: String The name of the object of course. This is not unique and many objects may share the same name.
Position: TVertex
This is the location (X,Y,Z: Integer) of the object in the game space not the screen coordinates.
Dimensions: TVertex The width, height and depth of the object.
Image: TImage For the time being this is a simple pointer to our TImage object which basically stores the entire bitmap of this particular object. Sure beats having an image stored with every object as that would result in a huge memory footprint pretty damn fast.
Direction: Byte No more than 8 directions but probably only 4 for most objects
Animation: Byte No more than 256 different animation for any object type
FrameIndex: Byte No more than 256 frames per animation
Not implemented yet but eventually this will mean the program automatically select the correct frames based on three things: Direction, Animation and FrameIndex.
Anchor: TPoint (X,Y: Integer) This is the image offset that defines where the image is drawn in relation to the screen coordinates when the image is draw i.e The rear bottom left corner of the object.At the moment I'm only using static single frame objects so the Anchor can be stored directly with the actual object. However, once I am using animated objects the anchor position may change from frame to frame so that the animation is smooth and ultimately the Anchor point will be stored with the image and animation information.

This is my basic structure for all isometric objects. I will make additions as I progress but for now this is enough to move and draw objects in order and at the correct positions relative to their calculated screen coordinates. Next time I'll go into calculating screen coordinates and then onto depth sorting.

Saturday 24 January 2009

About the prototype

My current prototype is a very simple program using the Windows GDI to draw stuff to screen. Once I've got the isometric engine running I intend to use my 2D OpenGL wrapper to make the most of 3D accelerated graphics cards that most PC's are using. When it comes to drawing stuff, the GDI is extremely slow compared to OpenGL or DirectX and doesn't allow all the cool features that graphics cards are capable of (alpha blending mainly) but for the time being it allows me to experiment without worrying too much about initialising windows, loading textures into video memory and all the other boring stuff that comes with using either of the main APIs. I just want to get the basic core of it up and in time I can port it to OpenGL and maybe make a really cool game.
Here's some pics of where I'm at or you can download the actual program using the link on the right.

Development goals

I have attempted various isometric projects in the 12 years since I began programming but there was always a rather large stumbling block for me when trying to approach the problem; depth sorting. After spending the last month working on my latest isometric engine with several clearly defined goals I have decided to publish my experiences in this blog in the hope that someone (maybe even you!) will learn something from it and I can feel all nice inside when they (that's you) send me a nice email thanking me for enlightening them on a subject that in my experience has very little in the way of tutorials or reference material. My goals, for your dilectation are as follows:

  • Objects can be anywhere within the play space (X,Y and Z)
  • Objects can come in any size (Width, Height and Depth)
  • Objects cannot intersect
  • Objects will collide using bounding boxes
  • All objects will be ordered correctly depending on position and size
  • Tiling is not required though it is possible
I am writing the engine in Delphi (Pascal) but for the most part I will try to convey techniques using pseudo code and diagrams rather than platform specific code. I am already partway through the development process and as such a lot of the following techniques I have already coded and tested so the following posts will be used to illustrate my methods so far.