No more than one blank line between SLOCs.
Good
// Good
var hello = "world";
_log(hello);
// Bad
var hello = "world";
_log(hello);
No newlines between brackets and their associated conditional
// Good
if (condition) {
// ...
}
// Bad
if (condition)
{
// ...
}
Variables should be camelCased
// Good
var myVariable = 1;
var myOtherVariable = 2;
// Bad
var MyVariable = 1;
var my_other_variable = 2;
Scripts should not be prefixed as with other resources
Why? Scripts should be treated as an extension of the base GML API. Craft the scripts to mesh intuitively with the rest of the code. Namespacing everything with
scr_
makes this difficult.
// Good
do_the_thing()
player_death()
// Bad
scr_do_the_thing()
scr_player_death()
Scripts should be lower_snake_cased
// Good
player_health_add()
player_health_max()
// Bad
playerHealthAdd()
Player_Health_Max()
Scripts should be named using a system -> topic -> action
methodology. When appropriate, name scripts with the system first, then the topic within the system, then the action the script takes.
Why? This system more closely replicates how the core GML API functions are named. Additionally, this helps to organize scripts by the scope of their effects.
// Good
player_health_add()
world_light_initialize()
enemy_defeat()
// Bad
add_player_health()
initialize_light_world()
defeat_enemy()
Prefix resources (except scripts) with an identifier of the type.
Resource Type | Prefix | Example |
---|---|---|
Sprite | spr |
spr_player |
Tile Set | tle |
tle_world |
Sound (SFX) | snd |
snd_bullet |
Sound (Music) | mus |
mus_town |
Path | pth |
pth_enemy |
Shader | shd |
shd_heat |
Font | fnt |
fnt_title |
Timeline | tml |
tml_cutscene |
Object | obj |
obj_player |
Room | rm |
rm_world |
Name all arguments unless the script is a one-liner.
// Good
var enemy = argument0;
var damage = argument1;
if (damage - enemy.resist > 0) {
enemy.hp -= damage;
} else {
instance_create_depth(enemy.x, enemy.y, 0, obj_resit_message);
}
// Bad
if (argument1 - argument0.resist > 0) {
enemy.hp -= argument1;
} else {
instance_create_depth(argument0.x, argument0.y, 0, obj_resit_message);
}
Default arguments whenever it makes sense using ternaries.
// Good
var enemy = argument[0];
var damage = argument[1];
var resist = argument_count > 2 ? argument[2] : 0;
enemy.hp -= (damage - resist);
// Bad
var enemy = argument[0];
var damage = argument[1];
if (argument_count > 2) {
enemy.hp -= damage - argument[2];
} else {
enemy.hp -= damage;
}
Define @func
, @desc
, @param
and @returns
annotations on scripts
// Good
@func enemy_damage(enemy, amount, resistance)
@desc Damages an enemey, minus the given resistence
@param {Instance} enemy The enemy to target
@param {Real} amount The amount to deal
@param {Real} resitance [Optional] How much damage to resist
@returns {Real} the enemy's new health
Use gml_pragma("forceinline")
for one-liners
// Good
gml_pragma("forceinline");
return argument0 * 2;
When creating an array in a loop, start at the end.
Why? This prevents memory from having to be re-allocated as the array expands
// Good
var arr = [];
for (var i = 99; i >= 0; i--) {
arr[i] = i;
}
// Bad
for (var i = 0; i < 100; i++) {
arr[i] = i;
}