¡Nuevo! En español. (Spanish translation by Andrés de Pedro)




GameDevLessons.com has migrated to HobbyGameDev.com - please update links!




Chris DeLeon's GameDevLessons.com Newsletter

Vol 5 - August 8, 2009


Hello!


I'm Chris DeLeon (about me), and thank you for joining me for my monthly videogame development newsletter, vol. 5. This series is one of the ways that I aim to help new game developers get started, while helping current game developers take their work in new directions.


Lately, Andrés de Pedro has been generously translating the GameDevLessons.com newsletters into Spanish. Boletín 1 and Boletín 2 are already completed, with more on the way soon. If you have any Spanish speaking friends that would be interested in these resources, please take a moment to pass links along!



Table of Contents


I.) Past Editions, Subscribe


II.) Beginner - Programming Fundamentals

Programming Fundamentals in Game Context

Whitespace

The Comment

Names

Sequence

Functions

Includes

Variable Declaration

Common Types

Assignment

The Object

The Array

The If Statement (Conditional)

The Else and Else-If Statements

The While Loop

The For Loop

Example Game Source

Compiling on PC/Windows

Compiling on a Mac

Compiling on Linux


III.) Intermediate - Level Design

Level Design Philosophies

Architect's Design

Fireman's Design

Curiosity Lure

Reverse Breadcrumb

Arena Traps

Puzzle Based

Disguised Linear

Hybrid

Rapid Prototyping Methods for Spatial Levels

Node Network

Division of Space

Pipelining

Mimicking

Blueprint

Area Sketching

Mixture


IV.) Advanced - Knowing When to Hack

Hacking as Rushed Programming

Serious Pros Hate It

Videogame Development Pros Know When to Do It

Once, It Was the Only Way

Tradeoffs and Circumstances


V.) Up-and-Coming Developer Nominations

Off to the Right Start? Want Free Publicity?



I.) Past Editions, Subscribe


Keep up with each new newsletter - free!


To read previous editions, or subscribe: http://gamedevlessons.com/?page=free


If you found this link someplace other than your e-mail inbox, and would like to be notified when the next edition is available, you can join my spam-free mailing list. It only takes a minute, I will never send out more than one e-mail each month (only to announce these newsletters), and it's easy to unsubscribe at any time.


The newsletters are not intended to be cumulative - so you shouldn't need to read all previous editions to understand this one - but the different topics in each may be helpful to you. In particular, if you're new to my newsletters, I recommend Newsletter Vol. 1 for its non-technical conceptual introduction to programming, as well as its links to free resources for image editing, audio work, 3D modeling, and other game development asset creation.


II.) Beginner - Programming Fundamentals


Programming Fundamentals in Game Context


The goal of this section is certainly not to immediately transform someone with no prior programming experience into a game programmer. That takes time and practice, reading and trying, experimenting and thinking, over a period of weeks (basics), months (intermediate), and years (expert). This is not intended to take the place of a good book on programming, or practice - it's here for warm up, review, or to complement other resources that are out there by providing a connection to how the most common code structures are used in videogame development.


My hope is that I can plant seeds of familiarity, and establish context of use for the various elements of programming. (Lost already, or a bit unclear on what programming is? Check out Newsletter Vol. 1!)


The following examples are given mostly in C code, taking advantage of a little bit of the flexibility given by a C++ compiler. C++, Objective-C, ActionScript 3, and Java use the same or nearly identical structures for the same functionality, and those are the major programming languages used to develop today's console, downloadable, mobile, and web videogames.


Finally, the text in this section introduces a lot of material, in a very short space for the amount presented. If you're new to programming, it will take more than one read, but there's a good chance that you'll pick up something new each time. Remember: programming is how every videogame on the market (Wii, online, mobile, 360, PS3, SNES, Atari, Arcade...), every piece of software you use (Office, Windows, FireFox...), and every electronic device works. There's some patience involved in understanding how all these things work. Stick with it - you'll be glad you did!


Whitespace


What it is:


Whitespace refers to the gaps between letters within program code, whether represented as tabs, spaces, or new-line breaks (as from the Enter key). Many modern programming languages treat all whitespace the same, meaning that whether you skip lines, indent a certain distance, put two spaces instead of one, or use tabs instead of spaces, the program code will work exactly the same way.


How it looks:


for(int i=0;i<5;i++){showNumber(i);doOtherThingToo();}


...works the same as, but is not as easy on human eyes as...


for(int i = 0; i < 5; i++) {

showNumber(i);

doOtherThingToo();

}


Example of a use in videogames:


When a program's source code doesn't compile correctly, especially for a beginning programmer, it's frequently due to a mismatch between braces (the { and } symbols). Effective use of indentation to indicate how many pairs of braces are around code helps keep track of where braces should close. All errors in programming code are reported by the compiler using line numbers, which are only useful in leading the programmer to the problem if the code is broken onto new lines after each individual instruction is ended by its semicolon.


The Comment


What it is:


Text visible only to the human reader, that the computer ignores when it's time to generate ("compile") a program from the program code.


How it looks:


// Text after 2 slashes on the same line is a comment


/* ...and so is anything typed between the slash-star and the star slash. This type of comment, unlike the double-slash style, works on multiple lines. */


Example of a use in videogames:


If you program something at the start of a project, then return to that part of code weeks or months later, you may have trouble figuring out what you were intending when the original code was written. Does the collision detection algorithm assume two objects weren't already overlapping in the previous frame? Is there a limit to how many badguys the game's graphics code is intended to render at once? Comments are a perfect way to record this thinking alongside the code it's relevant to, to ensure that it's passed along to your future self, or anyone else that might wind up reading the code.


Names


What it is:


It is up to the programmer to create names for most things used in a program's code - names to keep track of numbers that are being used differently, to refer to text phrases that serve different purposes, and names for different chunks of code to succinctly describe their functionality. The computer doesn't care what these names mean to people ("drawStuff", "ElvisPants", and "BV3_aUiP0" are all equally valid) - but their consistent usage in different parts of the program is how the programmer stores, changes, and checks values for different purposes.


Even though the computer can't tell the difference between a function for updating the screen called "UpdateScreen" and one called "DogsGetExcited", the former is a smarter choice because it reflects how the programmer is using the label. Note that whatever names you use inside your program are 100% invisible to the users and the outside world - they're just a way to stay more organized about the numbers you're shuffling around.


How it looks:


moveBadguys(); // good name for a code chunk


int playerPositionX; // clear name for a number


abc123(); // terribly unclear name


int r; // bad. radius? red value? radiation? roundness?


Example of a use in videogames:


If you're good with naming all the numbers, code sections, files, and other labels needed by your program, the code can become impressively clear to anyone browsing through it. That means less time is needed for writing extensive comments to explain exceptions or clarify meaning, and far less time will get drained into untangling confusion (or problems arising from confusion) based in poor name choices.


Sequence


What it is:


With only very rare exceptions (ex. very advanced topics related to PS3, XBox 360, and high-end computer programming), program code executes only 1 instruction at a time, 1 step at a time, top-to-bottom just like English text is read. Every instruction goes on its own line, for sake of human readability, and must end with a semicolon, for sake of machine readability.


How it looks:


doThing(); // happens first

doOtherThing(); // then this

lastThingHappening(); // happens last


Example of a use in videogames:


moveByPlayerInput();

detectCollisions();

drawEverythingToScreen();


...is a smarter order than...


detectCollisions();

moveByPlayerInput();

drawEverythingToScreen();


...because in the second ordering, character positions aren't updated to account for collisions that could have happened by the player's input until after the current frame is drawn to the screen. That means the player way wind up seeing things overlapping one another, which could have been easily avoided by simply switching 2 lines of code!


Functions


What it is:


A mostly self-contained solution to a recurring problem. In its simplest form, it's simply a group of code that can be called from any other place in code, any number of times, with a one word label. More involved functions can accept input values for use in calculation, and/or can output new values reflecting the results of its processing. The parenthesis pair always show up after a function name when it's called; if it is a function that takes input values, those values would be specified between the parenthesis.


How it looks:


Declaration

void doThing(void) { // a function with no input/output

// ...code goes here...

// every time the function is called

// this code will execute, top-to-bottom,

// from the function's starting brace "{"

// to the function's ending brace "}"

}


Call

doThing(); // does the "code goes here" from its braces

doThing(); // does that again (we called it again)


Example of a use in videogames:


Grouping related code together into functions helps organize code into more readable sections A function called drawStuff() might contain calls to all other draw functions, such as those used for drawing the background, player, enemies, powerups, weapon projectiles, and health information, which in turn could call other functions that handle the details of how to display the necessary images in the necessary places. This approach enables you to separately take a detailed or big picture look at different parts of the program, breaking the functionality up into understandable chunks. It also centralizes code that's needed multiple times into 1 place, where it can be fixed or updated only once if something is found to be broken in its behavior.


Includes


What it is:


Technically, it takes the contents of another file and dumps them word for word into the file that features the include statement.


Practically, it determines which pre-made functionality you have access to using. It works this way because most of the files we include are ones that define pre-made functions for us to call in our programs - the include statement automatically injects those definitions to the top of our file. Programming languages come with many libraries prepared for things like displaying text, reading keyboard input, accessing network hardware, and performing comparisons/manipulations of text.


How it looks:


#include <stdio.h> // lets us write text on the screen

// "stdio" stands for "STanDard Input Output"


...later in the code...


printf("This will show up, thanks to stdio.h!");


Example of a use in videogames:


Additional libraries can be downloaded from the internet (like Allegro, SDL, or DirectX in this case) that enable you to make simple function calls to load image/audio files into memory, change the screen resolution, display images to the screen, play sound effects, and handle fluid keyboard/mouse/joystick input. People have earned their PhD's from finding faster ways to get a computer to draw a line - don't waste your time trying to re-invent the wheel, when generations of computer researchers have been tackling very hard problems so that you won't have to. Instead, find and include libraries that have their brilliant solutions inside them! This allows you to focus your programming on what your videogame does differently with those graphics, sounds, and input events, instead of how to simply get them to work.


Variable Declaration


What it is:


A Variable Declaration is a line of code that sets aside a named container for a value. It's up to you as the programmer to come up with a name that you think is suitable. That value is often a number, a letter, a series of letters ("string"), or object (group of numbers, strings, and/or other objects) - to be saved, updated, and checked within code.


How it looks:


int health; // Lets us store/change/check 1 number

int lives; // To store/change/check a different number

// int stand for INTeger (meaning: a whole number)


Example of a use in videogames:


Every distinct horizontal position - how far a player, badguy, powerup, or particle is from the left side of the screen - must be tracked with a distinct variable.


Every distinct vertical position, too.


The same goes for how much health each character with health has, how many characters are alive at once, how much magic power the player has left, which powerups the player has in inventory, what level the player is on... if it's something that has to be remembered even temporarily, and may not always be the same number, it needs a variable. You'll be declaring lots and lots of variables.



Common Types


What it is:


A "type" is any form of variable. Some of the most common are int (integer, non-decimal number), float (floating point, refers to a number with accuracy finer than whole numbers), and char (character, i.e. letter).


How it looks:


int thisIsAWholeNumber;

float thisCanBeADecimalNumber;

char someonesFirstInitialCanBeSavedHere;


Example of a use in videogames:


The number of lives would be an integer, since it is counted in discrete units. A rocket projectile's speed and position would be floats, since for smooth motion with acceleration finer variation is needed than whole numbers allow. A player's initials on a high score screen would be stored as char.


Assignment


What it is:


The equal sign in programming, unlike the equal sign in math classes, is not the same to both sides of an equation. In fact, it isn't used to write an equation - it's used to create a statement of assignment. Where there's a single equal sign, whatever is on the right side gets evaluated (added together, multiplied out, substituted in, etc.) then stored into the variable to the left of the equal sign. That is, a new value is assigned to that variable name.


How it looks:


int temporaryNumberStorage; // creates a variable label


temporaryNumberStorage = 5; // saves 5 to that variable

// read it as, "store 5 into temporaryNumberStorage"


// This next line is an example of what NOT to do:

5 = temporaryNumberStorage; // meaningless! BAD!

// Say, "store temporaryNumberStorage into 5"

// That sounds like nonsense, right?

// What does it mean to save anything into 5?

// Your computer doesn't know, either :)


...another example...


int num1;

int num2;


num1 = 10;

num2 = 35;

num1 = num1 + num2 - 2;

// num1 winds up 43 (from 10 + 35 - 2)

// num2 stays 35, because it's right of the =


Example of a use in videogames:


Setting a player's number of lives (assuming "int lives" has been declared earlier in the code):


lives = 7;


Subtracting 1 life:


lives = lives - 1;


Giving 2 extra lives:


lives = lives + 2;


Beware that the following line does not actually change the value of lives, since there is no equal sign acting as an assignment operator (=):


lives + 1; // Does not change anything! No = sign!


Since that previous method of adding or subtracting involves typing the variable name twice, there's a slightly faster way that programmers invented to mark that addition or subtraction that saves into a variable with the assignment operator (=):


Subtracting 1 life:


lives -= 1;


Giving 2 extra lives:


lives += 2;


You can write it either way. "Var = Var + num;" is the same as typing in "Var += num;" and that also works for multiplication (*), divison (/), and subtraction (-). Lastly, the addition or subtraction by 1 is so common in code that there's a way to do that without using the assignment operator:


Subtracting 1 life:


lives--;


Add 1 life:


lives++;


(That's where the programming language C++ got it's name. It's the same as the C programming language, but with stuff added on top.)


The Object


What it is:


A way to organize multiple variables together into a meaningfully named grouping. As with function names and variable names, the programmer invents these names, ideally choosing a name that reflects how the group of variables is intended to be used. In C, it shows up as a struct, which only contains a grouping of variables, but in C++ and most other more recent languages it can be class, which has the ability to also group functions, plus a few other benefits.


How it looks:


struct character {

int health;

int x, y;

};


character thePlayer;

character badGuy;


thePlayer.x // variable for the player's x position

badGuy.health // variable for the badguy's health value


Example of a use in videogames:


Objects - whether structs in C or classes in newer programming languages - are essential to keeping organized a project grows to include many different kinds of characters, environment pieces, data formats, and other conceptual groupings of variables. The example above is a very simple, fairly typical use, but could be expanded to account for each character's image, mood, momentum, rotation, animation frame, inventory, etc.


The Array


What it is:


An array is a way to store a sequence of variables, such that they share a common label (think street name) but different index numbers to distinguish them from one another (think house/building address).


How it looks:


// The number in [brackets] declares the array's size.

// Array addresses start at 0, so the highest number

// we can use is 1 less than the size of the array.

// Defining array size [3] gives us [0],[1], and [2].


int numbers[3]; // creates memory for 3 int variables

numbers[0] = 1000;

numbers[2] = 70; // acts as 3 separate numbers!

numbers[1] = numbers[2] + numbers[0];


// numbers[0] winds up as 1000

// numbers[1] winds up as 1070

// numbers[2] winds up as 70


// 3 separate numbers, 1 common label


Example of a use in videogames:


Any time there are many of something, and each something behaves the same way or based on similar rules, there is probably an array or similar data structure involved. Particle effects, enemy characters, units on the battlefield, projectiles, and so on are often tracked using arrays, utilizing The Object structure of a language to group each individual thing's variables together.


An array of letters ("characters" or chars) forms a "string", or word/phrase which can be used as a name, displayed on screen as text, etc.


The If Statement (Conditional)


What it is:


Checking whether one or more mathematical comparisons or functions evaluate to true, and only doing a section of code if it is. Valid comparisons include:


a < b (a is less than b?)

a > b (a is greater than b?)

a <= b (a is less than or equal to b?)

a >= b (a is greater than or equal to b?)

a != b (a is not equal to b?)

a == b (a is equal to b? Remember, 1 equal sign is assignment!)


Multiple statements can be combined via boolean logic


(a < b) && (b > c) meaning (a < b AND ALSO b > c?)

(a < b) || (b > c) meaning (EITHER a < b OR b > c?)


How it looks:


if(lives > 0) { // "if the player is alive"

// ...move and draw the player here...

} // otherwise code skips ahead to here


Example of a use in videogames:


Killing a character when it runs out of health, forcing the player to stay on screen if the x or y positions go outside an acceptable range, checking whether a gun needs to be reloaded before allowing it to initiate the reload animation/code, etc.


The Else and Else-If Statements


What it is:


Using a section of code only if the result of an if statement turned out false.


How it looks:


if(lives > 0) { // "is the player alive?"

// ...move and draw the player here...

} else if(continues > 0) { // "has continues?"

// ...go to the continue screen...

} else { // "if the player isn't"

// ...play sad music...

// ...go to game over screen...

}


// Note that you can have as many else-ifs as needed

// You can even just have an else right after an if

// The presence of any else or else-if is optional

// If there is an else, it must come last in the chain


Example of a use in videogames:


It's extremely common to use this type of series of evaluations in games for a computer controlled enemy to evaluate circumstances with a pre-determined priorty, to handle a series of circumstances that might cause a collision to detonate a projectile, or to handle menu item selection.


The switch-case sequence (not covered here, but easy to find on the internet) is an alternate construction available if the else-if chain is checking matches against consecutive integers (is it 1? otherwise, 2? otherwise, 3? etc.).


The While Loop


What it is:


It works a lot like an If Statement, except that when it closing brace is reached by the code, it checks the While condition again. When the while condition is still true, it goes through the code between its braces another time; if the while condition's comparison expression is false, then code continues after its closing brace.


How it looks:


while( gameHasBeenLost == 0 ) {

useMouseInput();

moveEnemies();

updateScreen();

if( health < 0 ) {

gameHasBeenLost = 1;

}

}


Example of a use in videogames:


Its most common usage is shown immediately above - the game's logic and screen updates occur constantly within a while loop, until something happens within the program (a key is pressed, a menu item is clicked, lives run out, etc,) causing its comparison expression (here "gameHasBeenLost IS EQUAL TO 0") to no longer be true.


Take heed that with any loop, the risk of an "infinite loop" - code that never stops executing - appears if nothing inside it happens that will turn its expression condition false. If your program is being run in an old terminal, and seems to be stuck, CTRL+C will bail from it. If all else fails, CTRL+ALT+DEL (PC Windows) or Force Quit (Mac) will easily and safely terminate a program that is trapped in an infinite loop.


Note that the above usage is no longer common in certain newer languages, particular ActionScript 3, which instead handles game logic best in the form of setting up a timer to call a particular function some number of times per second. (Not shown here.)


The For Loop


What it is:


The For Loop groups together a common and very useful pattern of programming: set up a variable to be used in a while loop, declare the comparison expression for the while loop to evaluate, and do something each time through the loop to affect the loop's variable. It's commonly demonstrated as an easy way to count from one number to another, but it can also be used to scan across every letter in a word, check every pixel of an image, or call a function on every badguy/item in the world.


How it looks:


for(int count=0; count<100; count++) {

// ...do something here...

// it will happen 100 times.

}


...that behaves exactly the same as this...


int count=0;

while(count<100) {

// ...do something here...

// it will happen 100 times.

count = count + 1; // Remember! Same as "count++;"

}


Example of a use in videogames:


Going through each badguy and updating their position, where each badguy is an object in an array, by calling a function on the badguy in the array position denoted by the for loop's counting variable.


Example Game Source


Simple Breakout Game Source


To play, move your mouse to position the paddle, and click to reset the ball when it is off the screen. Press the Escape key to quit. The zip file includes pre-compiled binaries for both Mac (breakout-mac) and PC/Windows (breakout.exe) - just double click those to play. The instructions to recompile these programs on your own are below - so that you can experiment making changes to the code to see how it works.


Compiling on PC/Windows


Download Dev-C++ 5.0 beta 9.2 (4.9.9.2) (9.0 MB) with Mingw/GCC 3.4.2. After it's installed, inside Dev-C++ go to "Tools" then "Check for Updates/Packages", then under "Select devpak server" choose "devpaks.org Community Devpaks". Press the "Check for Updates" button, then check the boxes to install Allegro (the library for audio, input, and graphical functions) and Allegro Supplement (documentation and sample files). After that, open up the breakout.dev file I've included, which already has the Allegro library added to the Parameters section of Linker under Project Options (as "-lalleg"). Then use the menus to go to Execute, Compile & Run. Any time you make changes to the program source, you can update the game itself by repeating that last step to Compile & Run.


Compiling on a Mac


Download Xcode for Mac-only Development from Apple's website to get all developer's tools installed. Also download the Allegro source for Linux (I found that here). Double click that downloaded allegro tar.gz to turn it into a folder, then use the Terminal to 'cd' command your way into that new allegro-4.2.2 folder (need to learn the Basic Terminal Commands?), then type the following lines into the terminal to install Allegro:


chmod +x fix.sh

./fix.sh macosx

make

sudo make install

sudo make install-man

sudo make install-applehelp

sudo make install-framework

make

sudo make install


Followed by using the Terminal to navigate into the folder containing the Breakout game sample source. Then type in this command:


g++ main.cpp core.cpp -o breakout-mac `allegro-config --libs`


NOTE that the ` is a BACKTICK on the same key as tilde (~), NOT a single quote/apostrophe from the same key as the parenthesis (").


To edit the code, open main.cpp using any plain text editor (TextEdit, TextWrangler, DashCode...). To recompile the program to reflect changes made to main.cpp, repeat the step above for typing "g++ main.cpp...[and the rest]" in the Terminal.


Compiling on Linux


If you're using Linux, I think you can figure this out. :)

Pro Tip Hint: check out the instructions for the Mac section.

III.) Intermediate - Level Design


Level Design Philosophies


Every decision in a level's design is a conscious act by the level designer.


Levels aren't made by placing walls; levels are made by planning. Once a level developer is accustomed to the toolset at hand, and the underlying game engine, emphasis shifts from placing "walls" to placing "rooms," and from placing "enemies" to designing "encounters."


Odds are, you've never played more than one published title that used the same underlying level design philosophy. What works in one game, given its AI, weapons set and player interface generally does not translate well to another title in the same genre. Goldeneye N64 levels make poor Doom levels; Doom levels make poor Unreal Tournament levels; Mario levels wouldn't work for Sonic and Sonic levels wouldn't work for Mario.


Why bother with level design philosophy at all? Why not just make maps that are different every time? Just like there are conflicting philosophies that don't work well between games, for every game there are some overriding points that can be kept in mind to make the most of the engine. Here we'll look at a few particularly different ways of thinking about level space, since by separating them out, we're better able to switch between them deliberately as best fits the current videogame project's needs.


Architect's Design


Some games focus on environmental realism, to the point that most of the levels are designed to feel like they are almost incidental to the gameplay experience taking place there (ex. Hitman, Rainbow Six). For these games, most of rooms, hallways, and open areas feel like they were laid out without special emphasis for the player start, ammo/health boxes, or enemy placement locations. An architect by training is most likely to design this type of map, so we'll call it the "Architect's Design." It provides a strong sense of immersion when it's done well, since real buildings aren't laid out linearly for mission objectives, but it can make for awkward flow that confuses first time action players.


Fireman's Design


Other titles focus on flow of action. Halo is the unmatched example of this design strategy, using Architect's Design to compensate for the disarray of the battlefield. The player is rarely left wondering where to go next, since there are typically shots, yelling, and action taking place where he/she should go. We'll call this the "Fireman's Design," since it results in the player rushing from point to point to "put out fires." This requires a considerable amount of event scripting, and doesn't leave much of an opportunity for the player to rest. This risks hurting replay value by making interesting things happen predictably the second time around, but it can offer an extremely cinematic experience (ex. Medal of Honor, Call of Duty franchises).


Curiosity Lure


Some games lure the player around via exploration. Tomb Raider and Descent both relied at least in part on this "Curiosity Lure" (the player's left thinking "maybe this pathway leads to the exit?"). Without careful attention to attractive landmarks in the distance, and clear visual distinction between different rooms, it can lend itself to arbitrary map layouts, leaving the player wandering in cycles through corners for the next area to search through. Tomb Raider, for the most part, succeeded in doing this well, whereas Descent (unfortunately) did it very poorly. In a more action-oriented game the wandering is made even worse by going frequently through areas well after the interesting part of that genre (the enemies!) have been eliminated.


Reverse Breadcrumb


The name of this technique comes from the old Brothers Grimm fairy tale, Hansel and Gretel, in which a young boy and girl leave a trail of breadcrumbs behind them to find their way back home. It's "reverse" because, in this method of level design, breadcrumbs are scattered everywhere by the game's designers, and the player finds their way by picking them all up.


id Software used Reverse Breadcrumb in Doom, but it has been around at least since Pac-Man, and appears to this day in modern FPS games. Reverse Breadcrumb laces corners, hallways, side rooms, and action areas with cheap, low-value items of cumulative worth. +1% health, +1% armor, and small ammo packs are ideal for this, but in some games it's easily defeated badguys that. Besides giving you as the level designer an instrument of instruction to show the player where to go, it provides an immediate visual test for the player to mark off areas he's/she's already visited. If there are no more items (or weak badguys) in a room with several branching hallway exits, the player only has to explore whichever hallways still have items to find new areas of the map.


This approach constantly rewards the player, and leads to most or all of a map's areas being explored in turn. Care needs to be taken in a map designed with Reverse Breadcrumb to minimize the depth of dead ends, to avoid the player winding up stranded without cheap items as hints.


Arena Traps


Although Painkiller is among the few recent commercial games to exploit this design strategy, games like Robotron, Mega Man, and Zelda established its place in history. The concept behind "Arena Traps" is to have the player fight battle after battle in isolated architectures. This avoids player's using kill zones to take advantage of deterministic AI. It implies that the world has an overriding, malicious intelligence manipulating the player's environment, but that works so long as the story takes the player to an evil dungeon, a trapped temple, or alien den.


Puzzle Based


Jumps, keys, physics engine exploits, and remote switches or time trip wires dominate puzzle based games. It's rare to see an entirely puzzle based game anymore, but some degree of puzzle is more likely than ever to find its way into every game on the shelf. Prince of Persia had a few undisguised puzzles in the story, as did Quake II and Tomb Raider. Portal has more recently repopularized puzzles in the form of intricate navigation.


Disguised Linear


When the player is stringed from one location to the next, but they feel like it's their idea each time, then the level design is Disguised Linear. Done right, this describes a map that plays linear but doesn't feel linear. Max Payne and Half-Life are the best-selling games with this structure. It can significantly detract from replayability, and can also raise some issues of the designer having more fun than the player; if the player doesn't get to decide where he/she will go next, and instead the level designer does, who's really playing? On the plus side, it typically means the player won't get lost, and the emphasis of the gameplay is on action or platform/key puzzles rather than exploration.


A non-linear level structure (like one with a centralized hub and many hallways) can quickly be turned linear by use of keys, remote door switches, and other order-of-play constraining mechanisms. The workaround to avoid this problem is to take a Mega Man boss weapon approach, so that although the order of action is up to the player, there's an ideal order that the expert player will take to optimize level performance. For these types of unenforced Creatively Linear level designs to work, the player must be given clear clues or signs of what is to be found in different directions – perhaps by imposing architecture, detailed red warning patterns on the floor, or puddles of damaging green goo.


Hybrid


Most commercial games don't follow any one formula. The most interesting level design philosophies are those that manage to take the elements that work from a variety of design angles. Don't be afraid to experiment, but when you do so, you'll probably want to test it in a smaller map before you build it in as a crucial point of a larger map.


Invent some terms, like those used here, and categorize your thoughts into discrete concepts - it makes it easier to re-use the ones that turn out well, easier to avoid re-using the ones that turn out poorly, and easier to mix new combinations of what worked well to generate more intricate levels for later parts of the same game.


Rapid Prototyping Methods for Spatial Levels


Node Network


The scientist's approach. Begin by drawing a few circles on a blank page to represent major rooms, areas, hubs or hallway intersections. Draw a few lines between these nodes, until everything is connected in at least 1 way. Next, put your mind to thinking about how you'll run the player through these loops – item lure? Strictly ordered key puzzles?


Advantage: Fast way to sketch out how your level can have complex interconnectedness, without holding yourself back to conventional orthogonal hallways or linear path cutting as you might be tempted to do in most level creation environments.


Disadvantage: Leaves a LOT of unanswered questions about the level's theme, and the layout of rooms. This prototyping definitely should be used only in conjunction with another method, such as Pipelining or Area Sketching.


Division of Space


The builder's approach. Begin on a piece of paper with a rectangle, pentagon, or a more interesting shape, like a giant hand (Doom, map E3M2 did this), and then recursively divide that space into rooms.


Advantage: Can create a more realistic building space (no wasted area between rooms or halls). Doing it freehand on paper then transforming it into your game's level format reduces the tendency to work strictly orthogonal or on-grid.


Disadvantage: Leads to a map that is potentially too visually cluttered. If the overriding shape is not broken carefully, it can also yield a map that feels too contrived.


Pipelining


The mechanic's approach. This can be done equally well in most level building tools as it can on graph paper, if you're sufficiently comfortable with its environment and tools. Basically, form the level out of hallways, placing important items and keys in intersections or corners. Go back and bloat certain areas of the pipe into room-sized combat areas, add a little decoration based on a given theme, and call it done.


Advantage: As fast, if not faster, than any other method, without creating trivially simple maps.


Disadvantage: Often results in an unrealistic environment, and it takes some practice and patience to identify which areas of the pipeline should be bloated.


Mimicking


The beginner's approach. Basically, steal from anything and everything you can. Copy areas and layouts out of buildings you've been in, attach them to movie sets you've admired, and connect them altogether with an order of events that worked in your favorite game. As long as you're mixing multiple sources, you can result in some fairly decent levels while learning from the pros along the way.


Advantage: Creates much better content than you could have on your own.


Disadvantage: Makes you feel dirty and guilty inside. Do it if you're looking for a way to learn as you go, but try to wean yourself of it a.s.a.p.


Blueprint


The architect's approach. This actually involves sketching out the area as if it really existed – where do pipes go? Electrical wires? How and why are different areas (locker rooms, restrooms, offices, closets) placed where they are in relation to everything else?


Advantage: This method leads to the most believable environments.


Disadvantage: Slow, slow, slow. Maybe try it out for some early maps, but in the end, most of the money, energy, and time should be spent tending to the content that the player directly sees and experiences. Strive to see if you can figure out some patterns or rules to follow to simulate the same effect without putting so much invisible work into it.


Area Sketching


The artist's approach. This technique is very popular in the industry, and often shows up in collector edition released concept art. Make 3-D sketches of areas you'd like to fight in – from the player's perspective, or from a "security camera" ¾ angled perspective from a room's corner against the ceiling. How do obstacles fit together? From where will the enemies come at the player?


Advantage: Creates memorable areas, vastly more so than any other means of design.


Disadvantage: Requires a little art talent, and some random inspiration. Do this when you can, but don't expect it to work for every room of every level.


Mixture


This is the game designer's approach. Unfortunately, it's also a lot less formulaic in how to perform it properly. Knowing some of the other prototyping methods are there to work from, and how to articulate the different aspects to team members, is essential to succeeding in hybrid level prototyping. As design schemes can be mixed, so too design prototyping methods can be mixed.


IV.) Advanced - Knowing When to Hack


"If everything seems under control, you're not going fast enough."

-Mario Andretti


Hacking as Rushed Programming


The word "hacking" doesn't mean to programmers and software developers what it does to laymen. It used to mean committing computer crimes, but today that is more often referred to as cracking, or with an extra preposition added in the phrasing "hacking into" a computer. When people first started editing commercial videogames, like Command & Conquer or Doom, using homemade tools that the commercial game developers didn't officially endorse, that was what hacking referred to for awhile... but these days that's called "modding." So when we use hacking here, we're using it's most common usage among modern programmers: writing sloppy, on-the-fly, rushed code that's the bare minimum to accomplish the task at hand.


Serious Pros Hate It


Hacked code is known for being difficult for anyone to understand other than the person that wrote it, for being inconvenient to update/maintain, and for generally not reflecting good habits and principles of scalable programming.


Any reputable Computer Science or Engineering education will develop a scornful disdain for hacking in every student that passes through its doors. Researchers and professors and systems professionals will frown upon the idea strongly. If the habits of hacking seem deeply ingrained in a potential employee, a recruiter or interviewer may find a person unemployable.


Videogame Development Pros Know When to Do It


Videogame development is not exactly like research. Nor is it like programming an operating system, compiler, telecommunications satellite, or missile defense system. Those projects have extremely strict requirements in terms of functionality, stability, maintainability, and code readability. The time and money that go into those serious projects is often tightly bound by business calculations, without much passion or love or creativity from team members pulling extra hours from their personal lives to cram more love and cool stuff in. If something goes wrong with that serious software, then someone's degree is at stake, or businesses will lose millions of dollars in missed business opportunities, or soldiers will be killed. If something goes terribly, terribly wrong in a videogame, the player may have to replay 20 minutes of something they hopefully enjoy doing anyway, and it'll lose a few points in reviews.


What this means is that there absolutely, positively, without a doubt, is a time and place for hacking in videogame development.


But when?


Once, It Was the Only Way


The original videogames in nearly every genre were only possible because of absurd amounts of awkward hacking. That includes the first videogame ever. That also includes Adventure, the first action-adventure videogame, from 1978 by Warren Robinett (PDF presentation slides, mirrored as PDF version of a PPT from Warren's site). It's true too for each of the major innovations in first-person shooters John Carmack created with id Software (Catacombs 3D, Wolfenstein, Doom, Quake), which were notoriously made possible through Carmack's willingness to write hard-to-read code when it was the only way at the time to render 3D-looking worlds on such early hardware. That was the only way due to factors relating not only to machine optimization, but also programmer communication overhead, budget limitations, and time potentially taken away from polishing other features of the games.


Tradeoffs and Circumstances


Beyond basic requirements, what can be done in a videogame is determined by tradeoffs, or opportunity cost. Opportunity cost is estimated based on time and staff required to make something possible. If it can be done by 1 person in 2 hours the "wrong" way (getting in the way of doing future things the "right" way), but would take 5 people 3 days to do it the "right" way (easier to update, more predictable effect on the rest of the system), then there are a few important considerations as to which path is preferred:

  1. Is the project near completion, with no sequel in sight? If the hacked method involves writing code that will be cryptic, or hard to build a wide variety of features on top of, this is more of an option near the end of the project when the readability issue will be in code that may never be seen again, and your team is out of time to add any unplanned features atop the hack anyway.

  2. Are you certain that the game is definitely better with the feature than without? If there's a chance that it won't look, play, feel, and act in a way that benefits the game - and sometimes there's no way to know until the feature is in - then consider doing the 2 hour hack implementation to try the feature out. Information gathered from having it working in-game can then be used to inform whether it's worth investing 5 people for 3 days to get it done right, or just backing out the changes with the added certainty that the path isn't worth exploring.

  3. Are you certain that the "proper" method will really offer any advantages in the context of the project's needs, or that it accomplishes the same goal as is possible by the hacked implementation? There are many cases where properly organized, highly readable, professional patterned code may be best for human eyes, but less-than-optimal for machine computation in terms of memory or processing time. What you don't want to do is dedicate the time and development staff to implementing a feature the "right" way only to discover for some reason that it'll need hacks anyway to perform fast enough for inclusion in the game. (Disclaimer/warning: not all hacks are faster, and some classic hacks if used with modern compilers are redundant or detrimental.)

  4. Smart engineers feel guilty about writing "special case' code. Special case code is a bad idea a lot of the time, because it's time and energy that cannot be effectively re-used elsewhere. But in the case of videogames, we must ask, "Is this a special case?" Should only 1 boss in the game do this? Does this effect only happen in 1 level? Do all other powerups disable when this bonus level is entered? Special cases in the game warrant special cases in the code, and those special cases are what can make boss fights in Mega Man so distinct, as opposed to the not-so-special-cased (but rather cost-effectively generalized) 4 types of bosses used 50 times in Superman Returns.

  5. What else will you be able to do with the time saved by the hack method? Only if you're out of polish or features that you would like to add to the project - and it's worth noting that this is virtually never the case - then there's no opportunity cost of other cool features or polish that could be accomplished with the time. (Unless, of course, that time is going to get burnt up fixing bugs introduced by the hack method.)

Are there times when hacking something in the fast way can come back to cause you trouble? Absolutely. Is it dangerous if overdone? Of course. Though wouldn't it be foolish to pretend like it isn't one of many options at your disposal, to be utilized when the risks are understood and can be reasonably mitigated? Yep.


Sometimes the race goes to the driver willing to do push their car a bit further, a bit faster, through spaces that are a bit tighter, than the other people on the track.


(But that option is only viable provided that the rest of the car is built well enough to survive being pushed that far.)


V.) Up-and-Coming Developer Nominations


Off to the Right Start? Want Free Publicity?


Beginning with next month's newsletter, I will begin recognizing and giving visibility to up-and-coming videogame developers.


Whether it's a 13-year-old that demonstrates maturity beyond his/her years in level design using specialized videogame building software, or an older moonlighting indie with a track record of cool work but little visibility, I want to help.


What is there to win?

  1. Recognition to add to your resume or ongoing list of acclaims

  2. Free developer and project visibility by being featured in my next GameDevLessons.com videogame development newsletter

Have someone in mind? Even if it's yourself? Simply take a few minutes to send me a short e-mail with the creator's name, website, a link to one or more of the creator's best games, a brief (3-10 sentence) description of the creator's accomplishments and (if known) a few words about the creator's goals to chris@gamedevlessons.com.


Chris DeLeon

chris@gamedevlessons.com


PS I am writing this newsletter series to help people, and I want the contents to reach as many people as possible. Please pass along this link if you know someone that might find this useful: http://gamedevlessons.com/lessons/letter5.html Sending the link works better than copy/paste, since that way they'll see the latest updated version with Q&A or corrections.


PPS If you'd like to be kept up-to-date with these monthly mailings, simply subscribe to the GameDevLesson.com Monthly Newsletter: gamedevlessons.com/?page=free