Since a lot of my readers probably come from Game Maker communities, I thought I'd write up some tips for that game engine. This is especially geared toward people with some familiarity with Game Maker and GML, and not intended for people new to the engine.
1. GML Console A lot of people say never to use execute_string(), because it's so slow -- and they're right, but one good use of it is to create a "console" window for debugging purposes: a window which you can bring up to type in some code and have it be executed, without having to exit the game, change the code, and then restart the game. Sure, you could accomplish the same thing by running the game in debug mode, but the game runs slower in that mode and sometimes you weren't really intended to debug anything but want to change a variable on the fly to do some balance tweaking or something. This is fairly simple to set up, here's how to map it to the F11 key (this is what I used in this post's screenshot):
if keyboard_check(vk_f11) execute_string(get_string("Command?",""));
2. Difference Between Directions Finding the difference between two directions (Game Maker uses a wrapping 360 degree direction system) is common enough that I've used it in every game I've made for it, yet Game Maker gives you no easy way to find that out. So here's what I use; the two arguments are simply the two directions to find the difference between:
var ret_result; ret_result = abs((argument0 mod 360) - (argument1 mod 360)); if (ret_result > 180) ret_result = 360 - ret_result; return ret_result;
3. Nearest Objects Game Maker comes with functions to find the nearest object or the furthest object of a certain type to a certain position, but often you want the second-nearest or the third-nearest instead, especially when you're searching for the nearest object of the same type as the object calling the function, because the absolute nearest would be the object itself, and Game Maker would just give you that as the nearest object of that type. This comes up often enough that I wrote a script to deal with this problem, here it is. Make sure you create the global.priority_id data structure in the game's initialization somewhere.
// geo_nearest(x,y,object,number) ds_priority_clear(global.priority_id); with(argument2) ds_priority_add(global.priority_id,id,point_distance(x,y,argument0,argument1)); repeat (argument3 - 1) ds_priority_delete_min(global.priority_id); if (ds_priority_empty(global.priority_id)) then return (noone); else return (ds_priority_find_min(queue));
4. Homemade Collisions If you code your own collision routines instead of relying on Game Maker's, make sure to check for collisions on the *next* step after the current one, rather than just the current one. I.e. use speed, direction, and current location to calculate where every object will be next step, and prophylactically deal with collisions before they happen. I find this prevents objects getting stuck in each other. Another important thing to keep in mind is that when you're doing bullet collisions and bullets are of a sufficient speed, and objects sufficiently small, the bullets may jump right over their target, and not register as collisions. To avoid this, either have the bullet check for a line collision (with a line parallel to the bullet's movement), or just check a few spots between a bullet's current and previous position.
5. Arrays of Script Identifiers You can use names of scripts without parenthesis as identifiers for that script, and then use script_execute() to call that function. This may seem useless, but imagine you have an AI set up, where an NPC or an enemy can be in a variety of "states" depending on the current conditions, and have different behavior depending on that state. If each state has a distinct number, you could create an array of script identifiers, so instead of having a complex switch statement for its step event, you could simply use something like "\ script_execute(AI_step_script[AI_state]) to run the appropriate behavior script for its current AI state.
6. Families of Objects Game Maker is very object-oriented. The GML language itself isn't an object-oriented language, but Game Maker objects inherit behavior from parent objects, so it's a good idea to use object inheritance. At first you might think that child events overrule parent events -- for instance, if both a child object and a parent object have a step event, only the child's would be run. But then I learned about the "call event" drag and drop icon and the event_inherited() function, and it's amazing how I got along without them. For complex games I recommend setting up a large "tree" of inheritance for your games: one object that refers to all objects, then large families of objects under that, and so on down to distinct subtypes; think of it as a taxonomy. 7. "With" The with() construction is probably the most underestimated aspect of GML. Using it, you can cycle through every object of a certain type and perform some code as if you were within that object. You can also use "other." inside of a with() construction to refer to the object which set up the with() construction. You can even nestle a with() within a with(), and can even do with(other) to backtrack outside of the with() construct -- as you you're making a hole in a hole. If you keep a nice taxonomy of objects (see #6), remember that using with() on a parent object will also refer to all of its child objects, which can be useful. There are a multitude of nice ways to use with() constructions, I could make an entire post on these varied uses of with(), and perhaps I will eventually.