Mini-Game: Dwarf vs Zombie (Part 1)

by Chris at 10:00 am

Introduction

In anticipation of the release of Diablo III I’ve decided to write a mini-game in the likeness of the Diablo genre. I’m going to (attempt at least) write a small game that features a 3d Point’n'Click - Hack’n'Slash interface. With any luck it will be as fun as the origonal :D.

Considering I don’t actually know how long it will take to implement this mini-game, I’m going to move away from the three article limit, and just keep going as long as it takes.

Articles
   Part 1 - Stuff to download, getting into the development
   Part 2 - Setting the Scene, and Model Drawing

Downloads
   Source: Click Here
   Windows Binaries: Unavailable
   Linux Binaries: Unavailable

Preparation

Developer Kit
   SDL

Virtualization
   VMware Player
   Fedora 9 VMware Image

Image / Texture Editor
   GIMP

3D Model Viewer
   Milkshape 3d

Models
   Psionic’s 3d Game Models (Dwarf, Zombie)

Textures
   CG Textures

Starting Development

I was thinking of learning the new interfaces to DirectX 10 for this article, but after downloading a good 400Mb, I tried the first sample and found that you need Vista to use DirectX 10. Since I am only running XP, I thought it was a pretty rude attempt at forcing me to spend $300 on a new operating system. So, I went the other way.

I have decided to try my hand at some cross platform development and write this mini game in OpenGL, and make a compilation for linux. I’m too lazy to make my system dual OS at the moment, so I thought I’d get the compilation working with VMware. Only problem with VMware is that it’s not possible to actually run an OpenGL game when Windows is the host. Luckly, my brother has Fedora 9 as his main operating system, and has the graphics all working.. so all I need to do is get it compiled, send it over, and cross my fingers that it runs :).

Playing with Models

So, one of the first things that I did when I decided to go ahead with this mini-game, was to go out and have a look at what I could get in the way of free 3d models. I’m sure that there are plenty out there, but it’s hard to find with all the things you get using a google search. Anyway, Psionic’s models seemed to have enough stuff for me to make a game where you get to run around hacking up zombies. That should be good enough to play with.

Starting the Coding

Pretty SquaresOk, so, most games start with a kind of idear about where they are going from the start. Today I feel like coding from the hip, and making a game with the few resources that I’ve got. I want to have an isometric type feel to the game, along the lines of the Diablo series, but also use the nifty features of a 3d card. First thing’s first.. get an isometric looking tiled ground onto the floor.

I found that simply drawing a set of regular old squares, and placing the camera at a particular distance worked a treat. The distance was mostly trial and error.. 100 units away at an even 1:1:1 x:y:z ratio, pointing back at 0… or in code gluLookAt(57.73,57.73,57.73,0,0,0,0,1,0).

Looking at what I did with the tileing thing.. the code could be fairly similar for a heightmap, which gives a more 3d type feel. I considered using a heightmap for about 2 seconds.. then I rethunk what I wanted to achieve. I really dont think that it’s possible to make a game that is as fast paced and simple to play if you have to worry about the next mob being hidden behind a hill that you can’t see around. You would need to move the camera to look around every corner, making the whole process a lot slower. A fixed camera removes one level of complexity from the game, I figure a flat terrain is a small price to play for a little more fun. This is a case where using a 3d technology just because it is there could make the game less fun.

Hunting for Bugs Among Penguins

Actual Linux ScreenshotNow, having made some pretty textured squares work on windows, we just simply compile the same code for Linux, right? if only it were that simple.

I quickly loaded up vmware and made enough modifications to the code to get it compiliing. Admittedly most of the errors were caused by those things that are different between windows and linux, so I fixed the application entry points, file paths, file case sensitivity, and added a couple of #ifdef _LINUX and #ifdef _WIN32 statements, and we were able to compile.

Once it finally compiled, I sent the resulting app to my brother and crossed my fingers… segfault. Fixed another windows path error ie \\ => /, sent it again.. screen with nothing on it. After a bit of back an forth, we finally had some pretty textured squares show up, and code that would work in both linux and windows.

Picking a Winner

Finally, now that we have the drawing code working, it’s time to put in a little interactivity. Behold.. the red square that follows your mouse around like a little puppy dog.. oh the wonder :)

When I started looking at ways of translating a 2d screen location into a 3d world location (so that I could draw the red square).. I found that there were three main ways that people implement picking.

Crazy Maths-Centric Solution1) Create a “Picking Ray” from the origin (0,0,0), through the screen relative coordinates (usually in the range x = -1 to 1, y = -1 to 1, z = 1.0), transform by the world / MODELVIEW matrix, and then determine which objects it hits using some ray tracing maths. I could see this method working in theory for this game, but when I looked at the maths my head told me that I would have to switch to something harder than coffee to understand.. so crazy maths-centric solution - out.

Cool OpenGL Solution2) Use the gluPickMatrix function to create a small area around the mouse cursor, and render all the ‘hitable’ objects. Then, if we have enabled glRenderMode( GL_SELECT ); we will be able to find a set of named objects that were rendered. From what I read, there was a maximum number of objects that this would work with.. and since I want to pick one of about 300 squares I thought that there should be an easier way.

Simple, but not best solution3) Using the glReadPixels, get the Z depth of the pixel closest to the screen (ie. the one that is under the mouse cursor). Then using gluUnProject, find the 3d position of the point. I then used this point to determine the point on the ground that the mouse was pointing at, but you could also use it to determine which object was selected by it’s location. The only problem with this method is that,unlike the other methods, it will only allow you to find out what the front object is. Any objects behind the front one will be ignored.
I went with option three for the picking. Here’s the code below.. small is good.. not sure how fast it is tho.

GLdouble model[16], proj[16], pos[3] = {0};
int view[4];
float fDepth;
glGetDoublev(GL_MODELVIEW_MATRIX, model);
glGetDoublev(GL_PROJECTION_MATRIX, proj);
glGetIntegerv(GL_VIEWPORT, (GLint*)view);
glReadPixels( m_MouseX, view[3] - m_MouseY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &fDepth);
gluUnProject(
   m_MouseX, view[3] - m_MouseY, fDepth, model, proj,
   (GLint*)view, &pos[0], &pos[1], &pos[2]);