

quote:
First bit of advice: The design is basically the game. I wrote Emoticon a while ago, and while it was functional, the design was pretty poor. I was afraid to add new features because it might screw something up. Instead of trying to hack it back into working order, I rewrote, and in around 2 weeks, I had a game which surpassed the original both performance-wise and completion-wise. Don''t be afraid to rewrite, it is one of the best things that ever happened to Emoticon.
2) Avoid having public variables. If it looks like they would be useful, then you have probably done something wrong. There are about 3 public variables in Emoticon, MousePos, MouseButtons and MouseShift. They are only put in this way because there can only be one mouse ever.
It would only take a tiny bit of fiddling to get two separate games running split screen independantly of each other. Most of the map editors code is shared with the game engine, and it would also be possible to have a map editor and a game running concurrently split screen with minimal effort.
3) Don''t hardcode anything. I haven''t exactly followed this advice (the position of the buttons in my menu is hardcoded)... but it is still good advice. Try and load all data from external files.
4) Write modules/classes so they can be used between all the different programs related to your game. A couple of generic things are really useful, I have modFileFormat which gets included with anything that needs to read/write a game specific format. It provides all the functions I need for all my formats.
5) Write good tools. I dedicated a couple of days to getting my tools just right, they need to be quick to use and be friendly for making tiny tweaks. Case in point: The Font Editor is used for defining the sizes of each character in a font. This involved loading a font bitmap and going through each character and setting a rectangle to cover the whole thing. After doing this for 2 fonts, I realised that it was a very repetitive process, so I put in a button which would automatically find the boundries of a character and put the rectangle around them. Manual tweaking is still possible (for stuff like spaces), but the time saved is great.
6) One thing I did differently to most VB games is use my own graphics file format. This resulted in slightly smaller file sizes (it wasn''t compressed, but it wasn''t bloated like bmp files). I''m not sure if I would recommend it or not. It has limited benefits, but also limited negatives. The format was fairly friendly for my graphics packer, which made creation and extraction of the graphics file easier. The only thing which was a bit harder was writing my own function for loading the graphics onto a surface, it wasn''t much of a biggie, but it isn''t written as well as I would like so it is slightly slower than the usual loading from a bmp file. If you intend on doing a bit of image pre-processing in game (such as changing colours of units), then it would probably make things a bit nicer. Also, if you want to include some type of compression, then go right ahead. I don''t have a heap of graphics, so I don''t really care to do it
7) Decide how flexible you want the game to be and stick to that. Originally, Emoticon was going to be run on its own VM for the ultimate customisability... while it would have been cool, I doubt I would be finishing such a game very soon given that I''m a one man team. Flexibility is great, and usually goes hand in hand with good design, but it also takes time to get it just right.
8) Log files. Include a log file from the very beginning of your project. That is, a function which will write something to the log file such as "Initialising Graphics Engine..." type thing. These can be invaluable if you ever get a freak crash or problem during start up. Because these are outside tight game loops, you can afford to make these detailed at the expense of speed. Have nice error reporting functions which describe what the error was, where it occured and what the plan of action is . E.g: "Error: Device Lost in modGraphics.BltFast. Restarting Graphics Engine..."
9) Stop bugs early. If you have a bug, stop everything else and fix it first. The more you code, the more that bug is being worked into your code and the harder it will be to find and fix.
10) Compile with Control+F5 all the time. This will catch a lot of errors and stop a couple of stupid compiler bugs from cropping up. It is a little bit slower, but it will pick up errors before it actually runs instead of booting you out of your game halfway through to tell you that there is a syntax error.
11) A useful thing I did was to have a conditional complilation mode where the game would play in 1024x768 resolution. Instead of showing extra map and stuff, I filled the extra space with debug info. This is really useful - it doesn''t interfere with the game, and can tell you what is happening behind the scenes - what the AI is thinking or whatever.
Ok, that is enough general tips, now the structure. Here is what I have:
Forms:
frmMain:
This form does nothing. Just provides a hWnd for DirectDraw. It is bright green so I can tell if it is showing
Modules:
modAI:
Handles enemy level AI. Called once a frame and at the beginning of the game. It just gives orders to units, it doesn''t know how to actually act them out.
modFileFormats:
Loads/Saves all file formats the game uses. A lot of these file formats aren''t used in the actual game but only for tools, but they are still here.
modGameConsts:
All constants which apply in lots of places I declare here. These are public constants, and while I warned against public Variables, I would happlily argue that these are fine. Public variables are bad because you can''t have 2+ instances of them. There is no need for two instances of a constant because... it is a constant.
modGameData:
This stores information and statistics about all the different units and stuff like that. Works with modFileFormats to load the info and then provides it on demand. The stuff here is the info which is true for *all* units of a particular type, not individual units. So the animation frames to use are stored here, but the actual animation frame being displayed by a particular unit is stored elsewhere.
modGameEngine:
This is where most things happen. This module handles the logic behind creating a map, selecting units, ordering units, making units follow orders and drawing the map. Note that this is the logic behind drawing the map, not the actual drawing, it says what to draw where, but doesn''t know how to draw anything.
modGraphics:
This module is a DirectDraw wrapper, I use it for most of my projects, it is able to load my custom file format too.
modGraphicsOrganiser:
This module handles all the different graphics I actually use. Because everything is packaged together, the order of graphics in a package can change. This module will line up a request with a valid surface to use.
modInput:
Mouse and Keyboard input is caught here.
modMain:
Housekeeping sub. Has stuff like the Log file functions and most importantly, "Sub Main". This means that if I wanted to include a splash screen or something, I would call it from this module, it dictates the highest flow of the game.
modMainMenu:
This module will display the main menu and return the menu item clicked. That is all
modMapEditor:
This module will display the map editor and let it do its business. Once the user clicks ''Exit'' it returns to whatever called it.
modOptions:
This module displays the options menu and handles the setting of the options. Woo.
modPathfinding:
Feed this module a map and a point. Tell it how many units will be using the path. This is called each frame with a number telling it how many cycles it can do, once it has used up those cycles, it returns. Next frame, it is called again and resumes from where it was in finding a path (usually it takes about 2-3 frames). It can handle multiple requests for paths too. Once all the units are at their destination, they tell this module, and when all the units are done, it will erase the path from memory.
modUDTs:
This is where I define all the UDTs the game uses, the main UDT is udtMap, one of these holds an entire game. I''ll post a snipped version of it here so you can see what type of stuff it has:
Type udtMap
Map() As udtSquare ''The map
Size As udtPoint ''Size of the map (in squares)
Scroll As udtPoint ''What to offset drawing by (in pixels)
Bullet() As udtBullet ''Bullets on the map
Object() As udtObject ''Objects on the map
Unit() As udtUnit ''Units on the map
Selection() As Long ''Units selected
Marker() As udtMarker ''Markers being shown on the map
Path() As udtPath ''The paths in use (paths as in pathfinding)
AIMasterPlan As udtAIMasterPlan ''The mind of the devious AI
Tick As Long ''What frame of the game we are in
MapName As String ''Name of map
MapDescription As String ''Description of map
WinningState As udtWinningState ''What the player needs to do to win etc
End Type
One thin I have snipped out is that for each array there, it actually reads:
Blah() As Whatever
UBoundBlah As Long
Instead of using UBound(Blah), I use the variable. When I go to Redim something, it looks more like this:
UBoundBlah = NewSize
If UBound(Blah) < UBoundBlah Then
Redim Preserve Blah(UBoundBlah + BLAH_OVERDIM)
End If
This dramatically cuts down the number of Redims I do with a tiny memory hit (I''ve also left out the ''getting smaller'' code). Depending on the array, the _OVERDIM value can range from 1 to 50. Smaller for things that rarely change and larger for arrays which are constantly being resized.
The other benefit of a having everything in a udt is ease of writing code to save/load. A sample function from modFileFormat:
Public Sub SaveMap(Map As udtMap, FileName As String)
On Error GoTo ErrorHandler
Dim FileNum As Long
FileNum = FreeFile
Open FileName For Binary As FileNum
Put FileNum, 1, Map
Close FileNum
Exit Sub
ErrorHandler:
ErrorHandler FileNum, "modFileFormats.SaveMap", FileName
End Sub
It is very similar for the other file formats.
modUI:
This module can display buttons, labels and images. It also handles their behavior. For all of the buttons, there is a function pointer stored with them (found using the AddressOf operator). When they are clicked, the function is called. Pretty much identical to the way VB buttons work except these are created through code and need to be constantly redrawn.
quote:
At the moment, VB is the only language available to me, so thats going to be the language that I''m going to make stuff in.