How To Write a Game
This is a HUGE topic. There are probably as many answers to this question as there are programmers. I am going to include three points of view here: kdtop's (that's me--a newbie), Jean Louis's and jwvanderbeck's (both long time Genesis veterans). Good luck!
First, decide what kind of game you want. If you are looking for a 1st person shooter (FPS), they you may want to work closely with the GTEST code, and simply create a new level (mod) with your unique actors, textures etc. Advantanges of this approach include inheriting a full working program. For example, understanding the physics needed to bounce a grenade down a stairwell can be complex. But by using the GTEST code, in conjunction with the GEdit editor to create the needed entities etc., one doesn't have to worry about it. Someone else already figured it out. Furthermore, many hacks have been posted to make the game cooler by adding features. Disadvantages to this approach include that the GTEST code is not a user-friendly place to learn Genesis3D coding. Use of the Reality Factory engine (an expansion of Genesis3D) might be another option to get a FPS game up and running.
The second approach is to start from scratch, and build your own game using the Genesis3D function calls. This gives you full control of the game, but requires much more low-level understanding. With this approach, you can make any type of game you want--I've even seen posts from someone working on a racing game. Several introductory mini programs have been put out to help users get the basics down. I started with ProjectZ and found it quite helpful. Here is a micro application I have included as a tutorial
A final note: take time to read from the Genesis3D forum. I found many people with the same questions I had, and I was able to learn from their hard work.
And now, below, is an introduction to the Genesis3D engine from someone much more knowledgeable than myself. And then, following Jean's advise is a tale of development by jwvanderbeck that was quite helpful to me. Now take it away, Jean....
--Kevin Toppenberg, MD (kdtop)
The following was ripped right from the
Jean Louis Web site. This site is full of helpful tutorials, and newcomers would do well to check them out.Contents:
Genesis3d is a Wild Tangent product. Please visit the Genesis3d web site for more information.
Introduction
Genesis3d is a 3D rendering engine that target the independent game developer market. It comes in a package including a SDK (Software Development Kit) with binaries and source code (C/C++ platform), a set of tools described below, a demo software (GDemo) and a playable demo (Gtest), both with source code. The Genesis3d package is released under an "open source project" license. Please read the license included in the package. An active developer's community you can find on the Genesis3d web site supports the open source project.
The current version of this package is 1.1. No future version of this package is forecasted so far.
However, 3 other official projects are issued directly or indirectly from Gensis3D:
WildTangent Web Driver, Jet3D and the latest Destiny3D.
Description of the Genesis3d package
The Genesis3d SDK (Software Development Kit) contains the dll files that allow you to develop your own 3D application. It also includes the 3D rendering engine in a Visual C++ project form.
This VC++ project is made of the whole source code and libraries that Eclipse used to compile the engine. What does this mean for you? The ability to modify the Genesis3d engine to improve or customize it according to your needs (please, read the included license about engine modifications).
Source code location: ..\Genesis3d\Open Source\Source.
Binaries location: ..\Genesis3d.
Actor Studio (AStudio.exe) is a tool that allows you to convert the actors you created with 3DStudio Max (v2.5 or 3.0) or other 3D modeling software in the Genesis3d actor file format (.act). You also can include motions, skins and materials.
Source code location: ..\Genesis3d\Open Source\Tools\mkactor.
Binaries location: ..\Genesis3d.
Actor Viewer (ActView.exe) allows you to visualize the Genesis3d actors and to play their animations.
Source code location: ..\Genesis3d\Open Source\Tools\ActView.
Binaries location: ..\Genesis3d.
Texture Packer (tpack.exe) allows you to edit a Texture Library (.TXL files; the default texture library is located in "..\Genesis3d\Levels\gedit.txl"). You can also drag and drop new BMP textures inside Texture Packer in order to add your own textures and create your own TXL texture libraries.
Source code location: ..\Genesis3d\Open Source\Tools\TPack.
Binaries location: ..\Genesis3d,
..\Genesis3d\Levels (for TXL files)
World Editor (gedit.exe) is the world builder editor. It allows you to create the virtual 3D world your application will load. You will build the 3D world geometry, set the lights, actors, models, program their different motions... etc.
Source code location: ..\Genesis3d\Open Source\Tools\Fusion2,
..\Genesis3d\Open Source\Tools\TPack.
Binaries location: ..\Genesis3d.
How do I go from Genesis3d to my 3D Game?
You will need to create actors, textures, 3D worlds, music and to program the "logic".
To build actors, you will need a 3D modeling software. The most obvious solution is 3DStudio Max 2.5 or 3.0 because Genesis3d have some 3DS Max/Genesis3d file converters. The second reason is because 3DS Max is one of the best 3D modeling/animation software on the market (this is my
opinion). A cheaper solution is to visit Klaus Zerbe's web site. There, you will find his TrueSpace/Genesis3d file converter and a free TrueSpace1.04 version modeling software. You can also use other 3D modeling software like MilkShape3D or Animation Master.
To create your textures, I would recommend using PhotoShop or PaintShop Pro. They have to be 8bit (256 colors) bmp format with a resolution of 32x32, 64x64, 128x128 or 256x256 pixels.
You will use GEdit to build your maps or levels. GEdit is generating BSPs map. BSP's are mainly use to create indoor maps. It doesn't include terrain generation for outdoor scene, but when you will be experienced enough, you will find some "tricks" to build areas that looks like outdoor scenes.
However, you can use some tools like GenSurf to create terrain for Genesis3D or, if you are a C++ guru, have a look at GenScape, a C++ implementation of terrain for Genesis3D.
Then, you will need a programming API to develop the program itself. Even if a few "wrappers" using other platforms exist out there, I recommend you to use Microsoft Visual C++ 6.0 or later (notice that the earlier versions of VC++ will not work properly with Genesis3d). Wrappers are available for Borland C++Builder and an ActiveX implementation of Genesis3D allows you to use it in Visual Basic for example.
GTest is an example project that covers most of the aspects of Genesis3d programming. This project is located in ..\Genesis3d\src. You will find also a few examples, smaller and maybe better for beginners, like ProjectX or ProjectZ in the Genesis3d forum.
Posted: 2002-07-10 22:04
I just found this from when jwvanderbeck posted it on his Incagold site. I keep archives of all of my email, so even though this was over a year ago, I still have it. That's an extra lesson, free of charge. Enough preamble, this thing already has an intro of its own: (Note: this was posted by Defender)
*****
This project history spans about two and a half years of development. Its intended purpose is to help newer programmers to understand the lengths of time that must be invested to program a game, and to demonstrate the amount of "boring" code that must be written as a base on which to build the "cool" stuff.
Bear in mind that this was programmed in C++, and that I have been using C for six years, C++ for five. I also have previous experience programming games, so this is not my first project. If you do not know the language, of course, you must learn it before you can begin. Also, if you have not programmed a simple game (like Pong or Tetris) before, it is highly recommended that you do so before attempting a larger project. Even Pac Man and Donkey Kong are more challenging to program than most people would guess.
In addition, bear in mind that I am the only person whose work is included in this project, and that I am not paid to do this, so I cannot give it my full attention. If you have a team, or are able to devote forty hours each week to your project, it would not be unreasonable to expect much more rapid results.
* I had to pick an engine. This took months, and I picked G3D because it had all the baseline stuff I absolutely demanded, a few extras that were kinda nice, and a decent set of minapps, tutorials, and community. Also, it compiled easily, and changing the API to suit a project's requirements was not difficult. I decided to use an opensource engine over a professional one because using a professional engine meant that I'd just be making a mod, which isn't nearly as diffcult, educational, or impressive to potential employers. Also, using an engine that I could modify meant that I could add features if I wanted to.
* Got the DX 6.2 SDK CD from MicroSoft. Also checked out OpenGL.
* I had to find a suitable minapp. I checked out ProjectX, ProjectZ, and a few other G3D minapps and analyzed them. In the end, it was between ProjectX and ProjectZ, and X started not compiling, probably due to me doing something dumb like not putting libs or includes in the right places. In any case, OO support seemed like a smart idea, so those two factors caused me to use Z.
* The first thing to do, was, of course, get everything set up so that I can modify things and add features easily. I put everything into nice directory structures, tried making a very MINOR engine mod (changed the debug output text a little bit), and checked to see that the new engine linked in properly. It did. I made my first backup.
* I then had to play with Z a little more than I already had, to get a better feel for it. Then I had to tear it down into little chunks, and rebuild it in the form and structure that I thought would work best. After years of tinkering with Wolfenstein, a little QuakeC, and making a few Quake2 cooperative-mode mods, I had a good idea of what I wanted...(Otherwise, I would've had to do MORE research!)
* Wanting a console-like feel ("console" meaning "Nintendo/Dreamcast/Playstation"), I had to add support for joysticks/gamepads. I bought a MicroSoft SideWinder, and tinkered with it in the DX environment for a while until I understood how to use it properly.
* Programmed joystick support into my application.
* I made a distinction between ClientFrames and ServerFrames, banking on it being useful down the line. Quake 2 does this for a GOOD REASON, so I thought I should probably do it too.
* Installing basic controls, I decided that walking through walls was "bad" and needed to be stopped. I made simple clipping code to stop characters when they tried to go through walls. I then enhanced that code to cause objects to slide along walls instead of stopping dead upon collision. Lots of testing had to be done.
* Looked into modeling software. Downloaded MilkShape 3D, a simple bone-based editor, and made a simple model and some basic animations to be used in testing. I then had the game load up the ProjectZ level, and substituted my new actor in for one of the stock ones.
* I found that my actor was aligned incorrectly. I figured out an efficient way to change the vectors so that the actor would look right, and implemented it. Swapping vectors around wasn't slow, but was still a waste of time, so I thought that perhaps I'd fix it later so that I didn't have to do that on every frame. At the time, though, it worked well enough and wasn't important enough to warrant the attention and effort required to fix it.
* I decided that load time was too long with so many entities in the level because actors were being reloaded each time a new object was spawned. However, the number of entities was not unreasonably high. This meant that the load time had to be decreased WITHOUT dropping the number of entities. I made a simple-but-inefficient caching mechanism (big array of pointers to actor definitions), and I made it in such a way that it could be replaced by a more efficient scheme later on without much trouble. Also, no part of the code (aside from actor-loading) would have to know how this storage was achieved, or interact with it in any way except by calling the GetActor() function I had made to retrieve from cache (or load into cache if not found) an actor definition. Loading time dropped dramatically.
* While I was there, I decided to make a level-of-detail system. This way, rendering time would be saved by not rendering complex models for far-away actors without detracting from visual quality. I made a few different versions of my actor (mainly just re-colored it) and tested this feature EXTENSIVELY. Eventually, I had a system whereby there were several distance-zones, and if an actor's origin moved far enough out of one zone, his detail level would change based on that distance. I implemented five levels of detail, and changed my caching structure to reflect that. Before each serverframe (not clientframe, because I determined this to be a waste of time), the entity's LOD would be determined, and, in the event of a change in LOD, his old LOD actors' flags would be set to 0 (don't draw, don't collide, etc.) and his new LOD actor's flags would be set to whatever flag set that entity normally used. I still had only one real model, and it was rather high-poly, but just having the system working was enough. Making alternate models could wait until there was a story and some content for my game.
* Animations were choppy, since they were only changed on serverframes. Without disrupting the serverframe-controlled model, I made animations interpolate on clientframes using G3D's SetPose() and BlendPose() API calls.
* Animations had to be loaded in-game too often. This caused irritating pauses in gameplay, so I made a caching system for animations. This was easy because I had already made an extremely similar one for actors. I just had to make the animation-chaching structures, copy the actor-caching functions, remove the LOD code, change the function names, and it was ready.
* The player was being spawned at (0, 0, 0) in worldspace. This was obviously unacceptable, so I made a simple "ZPlayerStart" entity to determine where the player would start. Of course, putting down multiples of this entity might have caused slight weirdness, but, again, the solution was adequate for that stage of the project, so I moved on. Later, when it was more important (relative to the other items on the to-do list), I would return to it.
* Made a simple, 1-level menu using the engine's built-in version of printf(). This menu allowed me to start (or reset) a game, turn on/off engine debug info, end my current game, or quit from the program entirely. The menu did not pause the game.
* Framerates were pretty poor, because I had made a fairly high-poly actor, and it was being placed pretty densely around a simple-but-open room. I implemented RenderHint boxes. Doing this involved examining the engine to see whether it was using world coordinates, actor coordinates, or something else entirely. Eventually, through extensive debugging and some trial-and-error work, I got it to work. Now, actors who were completely obscured were quickly eliminated from the rendering tests, and framerates shot way up.
* I made certain entity types move around. They just slowly moved eastward, so it was nothing complex. Doing this, however, made me notice that their clipping boxes never updated. They could not walk through me or through walls, but I could walk through them and they could walk through each other. I could not walk through the place where they spawned, though, and neither could they. So although they moved, the sort of "force field box" around them was never updated and so stayed planted in their spawn locations. This was a real pain to fix, but eventually it worked.
* I made players and monsters out of multiple actors, because G3D doesn't do well with partial-body animations. I found that any bones that an actor had that were not included in an animation were simply assumed to be set to the actor's base "skeleton" postion. This made it impossible to animate, for example, the arms and legs of an actor independently of each other.
* After slicing up my actor, I made code so that, on every clientframe (and serverframe), my base actor (the legs) would place itself in the world, and my attached actor (the upper body) would attach itself. I set up a system whereby a body could be built of up to five pieces, and each piece could either attach itself to the entity's world coordinate origin, or to one of the bones of a lower-numbered piece. If the need arose, I could easily change the number of pieces by modifying a single constant value, which I kept in g_const.h with all of my other constants.
* Although segmented actors worked, the animations did not. It took some extra work to make chopped-up animations work properly for my actors. Eventually, though, I got it.
* At this point, I rearranged the project. Unless you have a very clear plan of how your code will be laid out from the get-go, you'll probably need to rearrange things several times. This isn't too tough, but make sure you back everything up first. It's only a slight headache, and the clarity and modularity that your code will have if you do this correctly is well worth it!
* I made code to let you step over things in your way/climb up stairs. And tested.
* Changing certain .dlls seemed to cause trouble. I tried to upgrade from the Genesis 1.1 engine to 1.2, which was a bad idea. I hadn't modified the engine at all yet, so that wasn't the problem...It was just that the new engine should, logically, have better features, be more efficient, or something along those lines. I couldn't get things to work together, though, so I moved back to 1.1, and I've stayed there ever since. As it turned out, the next version of the engine after 1.2 was no longer opensource anyway, so it was not suitable for my needs.
* I backed up all of my working .libs and .dlls, not wanting to have that headache ever again.
* Made the camera view lock on to the bone called "c_eye" in the player character's actor. I made a system to search a character (who, remember, canbe made of up to five actors) for the first occurrence of a bone with any given name, which was used in this process.
* Made my own overhead cam, kind of like the one in Metal Gear Solid, except that this camera would rotate with you, so that the "upward" direction on the screen always corresponded to "forward" from the character's perspective. Tested.
* Made a chasecam, like the one in Jedi Knight.
* Made the external cam views (overhead, chasecam) default to first-person cam if space got too tight.
* I was not happy with the way that walking was handled, so I recoded it. In doing this, I combined the two special movement types (sliding along walls & stepping over things/climbing stairs). I tested this a great deal, but somehow overlooked an obvious bug. However, the system seemed to work well enough.
* I set up a separate list of actors in the entity structure, one for "physics" calculations (used by serverframes) and one for "display only" purposes (used by clientframes)...This was essential for making sure that framerate does not impact physics at all. At least, for the way I wanted to do it. Using physics actors could be very important for prediction in client-server games, depending on how I want to implement it. Also, for triangle-precise collisions (which I intended to make later on), having a minimal physics model would be nice.
* I changed my collision scheme to allow you to collide with other people in the level, but to have only one single bbox per person. And tested. This required some serious work, because collision bboxes are attached to actors in G3D, so this meant that one actor would have to have the collision box for the whole entity. The real work here was in setting up the actor.
* In some games, if your character stands on a stairway, you can see that one of the character's feet will be raised or lowered to meet the stairs. This looks really cool, so I wanted to do it. I made a simple system for determining how high off the ground a bone was. Naturally, the bone would be found on a physics actor, not a display actor, since this change in pose would surely affect combat physics and thus had to be reflected in the physics logic.
* Deciding that I would need to make my own levels to test my more advanced features, I learned to use the map editor that came with G3D.
* I didn't like it, so I studied the map editor's import feature in the source code and made it highly editable so I could use WorldCraft instead.
* I set WorldCraft up, getting texture converters and making a new .FGD, then made simple maps and converted until I had a working system. I also got WALLY, a Quake texture editor, so that I could put my Genesis textures into WorldCraft.
* Having already made plenty of maps in WorldCraft, I didn't have to learn it. I simply made a small, basic test level with a few features like stairs and holes in the floor that were too small to fall through, and other things like that. These features were put in very deliberately to assist me in testing the level.
* I made a "crate" actor to use in my level, and put a few in.
* Researched sound effect-playing stuff, was pleased to find tommorris' MediaPak, because it had great features, probably worked, and was designed for ProjectX (therefore should be easily adapted to ProjectZ)...
* Downloaded, implemented, studied, modified, tested, reimplemented, retested MediaPak. Until it finally worked SMOOTHLY and without any bugs that I could possibly trigger. I didn't actually do anything with WAV files, but I did test MP3s and AVIs.
* I let you push other actors around. The system was simple, and not totally realistic, but adequately traded off between realism and user-friendliness so that you could do things like push a crate into a corner without too much trouble.
* I made actor-caching and motion-caching more efficient by changing from an array of pointers to a binary tree. In the process, I wrote a macro to create binary trees as classes. These tree classes were not very pretty, but they did the job and didn't leak memory. Being hacky isn't really a problem, because I don't have to worry about them actually working correctly, and because I can always write another (better) binary tree class if I want one.
* I then made the very simple brush-model entities known as doors.
* Made them STOP when they hit things instead of floating magically through them.
* Researched and fixed numerous bugs in G3D's model-collision code. Also made my own upgrades.
* Made models push actors in simple ways.
* Dealt with all sorts of nightmarish bugs that came out of this. Some of them, even though I've fixed them, still confuse me and I still have no idea how they came to be. I also don't know what I did that fixed them. But the important thing is that they don't come up any more.
* Annoyed that G3D could only handle single-brush objects, I made a system to cause multiple brushes to act like a single solid piece. Even very low-poly games use bmodels made of multiple pieces, so I thought that it would be ridiculous for me not to. In addition, it seemed very limiting to confine myself to one-piece bmodels. It seemed that fixing this now rather than later would be a good idea.
* Incorporating this multi-brush concept, I made the models push in much more complex ways, added gradual acceleration, deceleration when pushing heavy masses, etc. Of course, grouped bmodels all moved as one, as per my system.
* Made buttons that triggered doors. Made complex wait-before-close, wait-before-next-button-press stuff. Allowed actors like boxes to be pushed onto buttons, thus pinning them down. Made special "touch" property to all entities.
* Built a simple AI graph for monsters to use. I didn't have monsters, but I tested the map anyway. I used a simple breadth-first search to establish the shortest route from point A to point B (if such a route existed), bearing in mind several "constraints" in the form of flags. After much testing, it finally gave correct answers to all of my requests. The graph itself was comprised of a loose series of points that the user placed on the map during the design phase. These points would be linked to each other by a monster-walk simulator.
* Knowing that I would need more precise collision-detection for when monsters fight (though there were no actual monsters yet), I geared up to code some triangle-triangle and ray-triangle intersections I had researched from Tomas Moller's archive. Before actually coding it, though, I looked for collision libraries. This idea was a fairly new one when I thought of it originally, back before Half-Life or Quake 2 came out, but since then, many games have used it. I found ColDet before starting to code the feature, and thereby (hopefully) saved myself the effort of reinventing that particular wheel. I decided to put off linking ColDet into the engine until later, when it would be easier to test. Hopefully, having a few basic fighting motions would make testing these collisions easier.
* In order to chase the player around the AI map, monsters would need to know where the player was. After all, just giving the monsters the coordinates of the player wouldn't really help, since the AI graph wasn't based on coordinates. It was based on a series of pre-placed nodes, and getting from one node to another required use of the precalculated pathing data. So I needed a system to determine where the player was. The most logical system seemed to be that the player would be assigned the closest node to his current position, and the nodes that could vie for this title would be the player's original node and all nodes connected directly to it. When the player first spawned in the level, all nodes would compete to see who had the shortest distance, but that only happened ONCE, so it wasn't too bad.
* Found a bug in stair-climbing while trying to track the player on the AI map. Fixed that bug, though it took 2 hours and used up that whole day's development time.
* Recoded the AI graph completely so that it would build itself as a tight, dense, grid-based scheme to allow monsters higher-resolution understanding of levels, thus enabling better AI in the future. Also, map designers no longer have to add a million nodes manually...Instead they just add one node, which then spawns the rest around it recursively. Nodes can only connect to other nodes that are near them, in order to cut down on the possibility for each node to have a great number of connections. Also, the connections were broken up by rough compass direction, so that searches could attempt the obvious, straight-line paths first instead of spiraling out clumsily.
* Lastly, each node was given a "room" assignment, and any node that connected to another node from a different "room" would be marked as a special node. All special nodes in the same room as each other have the shortest paths to each other precalculated for each of three monster "profiles"...A profile is a set of constraint flags. This way, since most monsters have the same movement restrictions, a few precalculated paths across rooms (from one entrance to another) can be made that will save a great deal of calculation later. If a monster needs to cross the whole map, for example, that monster needs only to calculate (in real time) how to get to the exit of his current room, and then add on to that path the shortest series of precalculated paths to get to the final room in his journey, and then calculate how to get to the desired point within the final room. This makes traversing the large hallways of a level as simple as taking a single step within a room, so that long-distance walks can be calculated in very little time for any monster that fits any of the precalculated profiles.
As you can see, there are no monsters, even at the end of the first two and a half years. And as you may have guessed, it may time for a second rearranging of the project, possibly breaking certain things off into separate libraries, so that when future users make mods, they don't have access to things that they shouldn't be modifying. Also, although much of the code toward the end of the process is geared toward monsters, the support base is still not solid enough to start implementing them. All that has been established so far is a basic world with some physics sketched out. If your idea for a game could be adequately described as "Half-Life with new guns and monsters" or "A Quake 1, 2, or 3 TC," then it would be far more efficient to make a mod or a total conversion, because the time and effort required to set up the basics of the game are so great that they are only worthwhile if you're trying to make a saleable product (or get a job by presenting your game with your resume), or if some essential aspect of your game is fundamentally incompatible with any existing game that you would be willing to mod.