Fabians Game Programming Tips: Comments Are Not As Great As People Say

Download as pdf or txt
Download as pdf or txt
You are on page 1of 7

Fabians game programming tips

During the years I've learned to optimize for readability and having straight forward
code that is easy to debug.

Comments are not as great as people say


During development, your code will evolve and any comments will quickly become
outdated. When possible, it is better to write code that explains itself. Don't be afraid
to use long names on variables and methods. Good names replace comments, once
the method/variable evolves to something new - hit that rename button!
void checkCollisionsAndOuterBounds()

Don't use unnamed values:


Bad:
myHealth += 5; //What the hell is '5'?!

Good:
const int HealthPickup = 5;
myHealth += HealthPickup;
Don't be afraid to use constants for one use only.

No plan survives the first debugging


Planning is overrated, focus on one feature at a time, make that work and don't worry
about any future features. Start in one class and split things up as they get too
bloated.

Curly brackets is a great way to organize code


This is how people are taught organize their code, but having too many methods,
that are only used once, can make the code hard to follow.
void Update()
{
PlayerUpdate()
HudUpdate()
}
void PlayerUpdate()
{
if (Input.Keydown())
{ Log("Hello!"); }
}
void HudUpdate()
{
title = "Player health " + health.ToString();
}

An alternative way is using curly brackets


void Update()
{
{//Player Update
if (Input.Keydown())
{ Log("Hello!"); }
}

{//Hud Update
title = "Player health " + health.ToString();
}
}

If you got lots of brackets in brackets, comment their endings

for (int y = 0; y < 10; ++y)


{
for (int x = 0; x < 10; ++x)
{
if (x == 5 && y == 5)
{
Log("Center");
}//End If center
}//End for x
}//End for y

Learn to love crashes


A loud crash is always better than a weird glitch. Use those exceptions and write a
proper error message. If you want your end product to be more forgiving, you can
check if the game is in Debug:
if (health < 0)
{
if (DebugMode)
{
throw new Exception("Can't have negative health: " + health.ToString());
}
else
{
health = 0; //Autocorrect in release
}
}

Capture unexpected values


Avoid using equal comparison like in this example, is otherwise very likely to bite you
in the back later.
void takeDamage()
{
health -= 1;
if (health == 0) //Bad! Use health <= 0 instead
{
deathEvent();
}
}

Use exceptions to capture any unwanted values.


switch (value)
{
case 1: DoOption1(); Break;
case 2: DoOption2(); Break;
default: throw new ArgumentException();
}

Organize in logical order


X, Y, Z, Left to Right, Top to Bottom. Organizing your code like this, will make it more
readable. Naming something "BottomRight" sounds right, but "RightBottom" is more
logical.
x += move.x;
y += move.y;

In loops, I suggest you reverse the order of xyz, this will go through the array in the
same order you read a book.
for (int y = 0; y < Height; ++y)
{
for (int x = 0; x < Width; ++x)
{
doSomething(x, y);
}
}

When comparing values, order smallest to largest.


If (smallerValue < midValue && midValue < largerValue)
Use fallback states
If you use an enum to keep track of the game state, you can easily end up with
unexpected state conflicts - like getting stuck in a menu because of a pop-up
message.

Bad:
bool onHorse;
void update()
{
switch(state)
{
case GameState.InMenu:
updateMenu();
break;

case GameState.Play:
if (onHorse)
{
updateHorseRide();
}
else
{
updateGamer();
}
break;

case GameState.Death:
updateDeathCinematic();
break;
}
}

Good:
void update()
{
if (menu != null)
{
updateMenu();
}
else if (player.health > 0)
{
if (horse != null && horse.health > 0)
{ //Checking if the horse exist instead of trusting a boolean
updateHorseRide();
}
else
{
updateGamer();
}
}
else
{
updateDeathCinematic();
}
}

Connected values
Don't write code where the same change has to be done in two or more places.
Connect all values that rely on eachother, example:
int totalHeight = 10;
int topRow = 4;
int bottomRow = totalHeight - topRow;

Do not use not


Negations confuses the brain. Use variables where the natural state is TRUE.
bool invisible = false; //Very bad, the name itself is an negation
bool hidden = false; //Less bad
bool visible = true; //Best

If statements should be easy to follow.


Bad:
if (!alive)
{ DoOption1(); }
else
{ DoOption2(); }

Good:
if (alive)
{ DoOption2(); }
else
{ DoOption1(); }

Look at the example below, it is very straight forward but it is easy to miss the "not":
if (!player.alive)
{ DeathAnimation(); }

Three tips on how to make it easier to read:


if (player.alive == false)
{ DeathAnimation(); }

bool dead = !player.alive;


if (dead )
{ DeathAnimation(); }

if (player.alive)
{ } //Left empty for now
else
{ DeathAnimation(); }

Treat any untested line of code as a bug


Don't trust yourself to write bug free code.

Complexity kills
Big projects often hits a brick wall when they get too complicated. For example, a
game i worked on for a long time, this is what I do to add a new monster:

In the first edition (2009):


-Make a model with standing idle and walking animation.
-Create a class that inherits AbstractMonster.
-Set width and height on collision bound.

In my current edition (2016):


-Make a model, idle, walking, pre-attack, attacking, stunned, jump, riding, swim, sleeping
animations.
-Unique sounds for the monster.
-Create a class that inherits AbstractMonster, and apply about 30 settings like: How to react
at stun, how to react on water, how will it ride other animals or how animals can ride it.
-I will most often create one or two weapons for the monster, which itself needs a lot of
setup.
-Set take-damage bound, give-damage bound and terrain collision bound.
-How to share and update over network.
-Must add the monster to the stats book in menu and statues you can collect them as.

You can not completely avoid this issue, but here is a few tips on how to make it a bit
easier to manage:
-Remove old code whenever possible, people keep things and think "it will be useful
later".
-Add one feature at a time, make everything bug free before you add more.
-Make debug tools that makes it easy to go anywhere in the game and get any
equipment. Make them available for people who are testing your game.
-Straight forward and 'dumb' solutions often lasts longer. Optimizations, multi
threading, complicated math formulas and recursive methods - will often give you
issues later down the line.
-When planning ahead, keep in mind that each new feature is going to take longer
and longer to add. Do not be fooled by how fast the initial progress was.

You might also like