In November of 2003, I had the bright idea of asking a fellow programmer (Scott Pflanzer) if he would like to make a simple game, since he and I are both interested in developing games, although it's unclear whether or not it could be a living.
I asked him if he would like to make an adventure, action or strategy. He opted for adventure. So, adventure it is. To keep it simple, we decided to make it 2D overhead and base it loosely on the DnD rules. I also wanted it to have live character control instead of click and walk, although it could have both. I wanted realtime dodging of missile effects (not arrows) as well for action possibilites.
The game will also have an editor to allow you to create your own maps and collect them together as a campaign.
We are naming our engine Crawl (no name for the game yet), and I've made this page to take a snapshot of this momentous occasion, also to offer you insight as to how a game can evolve as it is developed.
I am brand new to DirectX 9 so I am learning it all from the ground up. I hope to incorporate as much as I can from my previous work, but it's likely much of it will be redone since what I have done so far didn't obey Design Patterns very well, and hence doesn't allow enhancement without a lot of rework.
As a start, I volunteered to write a demo showing the ability to scroll around a dungeon, while Scott comes up with an editor and map file structure that I can load in.
So, anyway, here is an initial look at the program, and you are welcome to download it and try it here.
December 3rd, 2003
This sample allows you to scroll around a harcoded level using the arrow keys. I hope to get the elastic scrolling just right. Note how the wall and floor blocks are, over the course of 4 blocks, a tiled texture. To make each block a full texture would have made the tiling too noticable.
Crawl1.zip (380K) - just unzip it to a folder and run it, use the arrows keys to move around, and hit Escape to end the program. The source code for the program is also in there, although you won't be able to compile it without linking to the correct libraries (winmm.lib d3d9.lib d3dx9.lib dxguid.lib - that's all of them). Remember this source file - it was just for testing and it will not look the way it is at all after I am done rearranging everything into classes.
I'm learning about DX9 vertex buffers and trying to figure out how I can make the best use of them without being railroaded by their constant nature. I'm also remembering how much of a pain it is to have to open My Computer and navigate to the project folder to prepare packages - I guess I should set up some shortcuts on my desktop or something. And taking snapshots and converting them to jpegs, saving them in my web page folder, sigh :)
No collision detection yet. It will be easy enough to move the block around using the arrow keys, sliding along walls, etc. but I will still need to get a pathing algorithm down so that you can click a location and have your character move there. Oh yeah, that means I have to capture the mouse, too. Yeesh.
Oh, and loading a bitmap with a colorkey (we use 255,0,255, that ugly hot pinky color) and preparing it with alpha values... so we can render objects that don't graphically take up a whole block.
Scott is providing the graphics. He has a character, chest and door graphic ready, but I haven't loaded and rendered them yet. Stand by.
December 6th, 2003
I currently have a simple character moving around, with three others slowly chasing him. There is no collision detection.
I'm realizing that the base movement speed will be very important to keep the game pacing just right. Too slow and it feels like a hinderance. Too fast and it feels like you need to speed through the dungeon. It also depends on everything else that happens - how doors open, chests are opened, etc. I think the speed I end up with will be very important. Perhaps I can just make movement speed an option, and let everyone find their own balance.
... I'm getting collision detection going - but for debugging, it would have been nice to have a floating point representation of the character block so that I would know if the calculations are accidentally letting him inside a wall. Perhaps I'll need ot learn to make use of the debugger better. Still, having it right there on screen would have been nice - thankfully I didn't get any infinite loops!
It keeps getting hung up on the edges, it won't slide right - maybe floats wasn't such a good idea? Part of the logic doesn't allow a block to continue moving into another, and that is what is causing them to not slide across walls - the blocks are ever so slightly inside the wall, which it should be.
Ok, collision detection for sliding is almost working - I need to work in some code that will allow you to slide into narrow passages (I remember this from Gauntlet a long time back - it favored the horizontal axis but not the vertical one. I just need to check the axis other than what the player slid on the last time time). I will also need to stop the player at the intersections, otheriwse he will just slide past it unless the float value falls on the center of the passage exactly. But Gauntlet had a locked stepping rate that put the blocks right on the boundaires. This game uses time based movement and float values for the axes, so I have to stop them midstride on the boundary and recheck it.
Also, how the calculation from 0.0-1.0 that a collision occurs, consuming that time and using the rest in the collision detection on the other axis might be off. I need to make sure it's right because the character is still ending up slightly inside blocks, which makes sliding unpredictable. (Fixed it - I found some bugs in my collision detection code, also some x's that should have been y's. Oops)
I'm now realizing that whatever solution I come up with for sliding between two objects needs to accommodate blocks that could be of anywhere and any size. I should develop that kind of solution instead of assuming that I will always be working with a wall block boundary. Took me long enough to realize that.
The problem I'm dealing with is this:
Imagine a block moving along the blue path from left to right. Actually, the whole time it is trying to move diagonally, as it does when it isn't obstructed by the barriers represented by the thick-lined blocks. Notice how the moving block squeezes between the two barriers and continues beyond, then slides along another small barrier and continues. I want the algorithm to handle it such that if the moving block was attempting to move this far in a single game tick that the collision routine would move the block along every collision, get it between the barriers and beyond, all in that tick's iteration for that block.
I'm not worried at this point about two moving objects colliding, since that is not necessary in the design of this game. For the purposes of this game, when any one block's movement is being iterated, ALL other barriers are stationary, even the moving ones.
So, it appears that the routine has to detect for three conditions:
1. A side colliding
with a side, as when the diagonal path is forced to become a vertical one in
the diagram above, and forced to become a horizontal one twice.
2. A trailing side passing beyond the block it is sliding against, to flag to the routine that the diagonal path may once again be available, as is what happens at the end of the block's movement, and just before and after it slides between the two barriers.
3. When the block's forward corner point lies exactly on an opposing block's corner point, as is what happens just before the block passes between the two barriers. It is important to code it such that the block tries to enter the passage, knowing that that axis of movement was blocked previously. This provides the player with the psychology of being able to slide along a wall to enter a tight opening. If the opening was even slightly larger than the moving block, this check wouldn't be necessary because condition 2 would have occurred followed by condition 1, automatically resulting in the entry. Without this special check, there is no way to guarantee that the block will enter the passage. (Which brings to mind that the last blocked axis must be stored for the next tick to handle the rare case that a block's movement ends exactly on an opposing corner point - on the next tick, the player is still expecting to enter the passage. Otherwise, the block may just slide past the opening sometimes, baffling and frustrating the player)
4. There is one other possibility. A freely diagonally (that is, not along an axis) moving block collides with a block corner to corner. This is different from condition 3 where the block is already touching the corner. The routine needs to be able to calculate that a corner to corner collision actually took place.
Note that in the above example, conditions 2 and 3 happen at the exact same time when the block slides between the barriers. It could just as easily happen separately, but will mroe often happen together with barriers that have a space between them that is exactly the width of the travelling block. The point is, the collision routine has to put priority first on the trailing side becoming even, THEN detect the corner collision and cause the slide.
Ok, so in order to do this I need:
There are a few problems with this algorithm. Some conditions can occur at time 0.0, >0.0, <1.0 and at 1.0. The algorithm needs to properly account for when to detect each condition, otherwise some possibilities could be missedm or infinite loops could be generated.