Something that interests me greatly with making things is the process by which the maker transforms from a novice to a master. This is a process of learning primarily by doing and through experience. Things like reading about a subject, interacting with peers, or watching others demonstrate, or abstractly thinking about a topic all contribute to learning, but none so much as actually doing things.
To the greatest extent possible, one should endeavor to spend their time doing and making. Get outside of your head and make. Do not exhaust yourself while making and doing; give yourself opportunity to observe what, how, and why you are doing what you are doing, and take time to examine and reflect on these things. Then apply what insights you gain from this into your next doing and making.
As I have progressed in learning GameMaker, I have observed a few distinct phases in my development. I don’t know that I’m at the highest level yet, or if there is a highest level. But as a gamer I like being able to categorize things and assign levels to them :-)
I really wish that I had had something like this to guide me as I made my progress, so it makes me really happy to have written this. I think it can help a less-experienced developer have some idea of a criteria of competencies so they can figure out how to get better, things to look for that can help them get there without having to figure it all out for themselves. It can also help a mentor recognize where their protegé is at in their development and help them identify areas where they should focus in order to improve.
Here’s a summary of my progression as a GM Dev to date:
Complete ignorance. It’s a struggle to do anything.
All you can really do is follow instructions in a tutorial, most likely doing things with drag and drop actions. And sometimes even that is frustrating.
Despite the instructions being clear and straightforward, you still have a hard time following them because you have questions that are so basic that the people who wrote the tutorials don’t even realize that you would have them.
If you’re trying to follow written instructions, you wish that instead of still images, you had an animation showing where to click and what to type. The instructions use terms for user interface widgets in the IDE that you aren’t familiar with yet, leaving you to guess until you figure out what they mean.
Six months or so later, you think to search for tutorial videos on YouTube, and find a bunch, although they’re not really much better because of amateurish production quality, and by this point you’re well beyond needing them anyway. Still, there’s a few good ones on topics you’re not yet clear on.
Drag and Drop competence. You’ve followed a few tutorials and by now have gotten somewhat of an understanding of the major resource types in a Game Maker project, the most commonly useful Events and Actions.
You understand enough of the most basic, commonly used Drag and Drop Actions that you can use them to put together a game without too much frustration. Subtleties like the distinction between the Keyboard and Key_Press are a bit frustrating, but you’re beginning to get when to use each of them.
You are curious about what else is available to you, and try to learn a new thing each time you get into your projects. You spend a lot of time exploring and experimenting with things you haven’t used yet, which is pretty much everything.
You figured out that you can stick a variable or even a calculation or function in the property fields of Drag and Drop actions, and this makes them a lot more powerful than you thought they could be when you were just putting in literal values into them.
You’ve started to feel comfortable with the Sprite and Image editors, and collision masks. But you’re probably overusing “precise” collision masks, and likely to for a while yet.
You have an understanding of the Object editor, but haven’t yet fully grasped all of the subtleties, such as inheritance, depth, persistence, and solid — although you’ve played with them a bit and are beginning to gain an appreciation for when to use or not use them.
You’re totally comfortable with the distinction between an Image and a Sprite, and between a Sprite and an Object.
You still refer to an individual instance by the name of its Object, and may not yet have learned about instance id’s as a way of referencing a particular instance, but you are beginning to wonder how to do this.
You’re beginning to want to learn about things that aren’t covered in the tutorials. You’re starting to hit the limits of Drag and Drop actions, wanting to do things which require GML code.
You start converting all your projects from DnD to GML. This helps give you an understanding of many GML functions and the language syntax. You spend a LOT of time reading the Help file, and re-reading it. Slowly, you begin to get a feel for the features and capabilities of the framework. Each new thing you learn about fills you with dozens of ideas to try.
You stop working on your game ideas and start building small demos to make sure you understand how some function works, or that combines a few things in novel ways to see if they work how you expect. Oftentimes they don’t, but you are figuring things out and learning a great deal.
You’re starting to use the debugger to help you understand what’s going on when your project doesn’t work the way you think it should.
Dissatisfied with the limitations and clumsiness of the debugger, you learn how to use file I/O functions to implement a logging system, and, for even more immediate debugging info, you figure out how draw data to the screen using draw_text(). This helps immensely when you need to figure out why some object is behaving bizarrely, and it’s because some calculation or function that you’re using to set the object’s properties is returning a weird value because you’re doing something wrong. Suddenly it’s like you can see The Matrix :-)
You spend a lot of time trying this or that, rebuilding and playing your project, for hours until you figure out how to make it do something you want.
You spend a lot of time reading the help documentation, the wiki, and the community forums.
You don’t post on the forums a lot, yet — or if you do, you tend to annoy forum veterans with poorly worded questions, that have already been asked and answered. But you catch on quickly.
You begin learning to research first before you post to the forums, and how to write up your problem or what you’re observing in a manner that is clear and helpful to your audience.
You are appreciative when other forum users reply to your posts or comments.
You’ve come up with your preferred naming conventions for variables and functions, and have become self-disciplined enough to employ them consistently, which makes remembering their names a lot easier when you need them.
You are beginning to form strong opinions on matters of whitespace, capitalization, and abbreviation, and what style of brackets/indenting you prefer. Everyone else is WRONG.
You’re beginning to appreciate what a mess you can make of your code if you don’t follow a consistent format and style, and are looking for solutions, if you’re smart enough to recognize the problem.
If it hasn’t dawned on you yet, you’re having problems with projects that require major refactoring in order to implement small updates, and managing complexity is becoming such a headache that you’re ready to give up on projects and walk away from them.
You start to pull all your repetitive code from individual Object’s Events and put them into Script resources, and are very happy that now when you go to update a script to fix a bug or add a feature that you don’t have to do it in multiple locations.
You realize that even calling the same script in two different objects is still duplication, even if it’s just one line of code. You start figuring out how to minimize the amount of code you need to write by effective organization of parent-child relationships between Objects.
You start figuring out how to re-write similar code so that you can cover it with a single script rather than two or more similar scripts.
You figure out that you can call a script within another script, which means you can re-use smaller bits of code more frequently and build up larger functions with them. Then it dawns on you that you can call a script from within itself. Eventually you’ll figure out that, while recursion is clever, it is not necessarily something you want to use very much due to performance concerns.
You have a mind blowing realization (or maybe you just read it somewhere) that having a single, very complex object that does a multitude of different behaviors, deciding how to act through complex series of conditional checks that are performed every step is not necessary. Instead, you can break up what you would normally think of as a single real-life “object” (eg, Mario) into a series of related objects (obj_Mario, obj_Mario_running, obj_Mario_jumping, obj_Mario_swimming, etc.), each of which represents a distinct state, or mode, which handles one specific behavior, and rules to handle what state it changes into next when certain conditions are met.
Then it dawns on you that you’ve been doing this all along, with simple two-state objects that handle “alive” vs. “dead” states, and that this is just an expansion of that idea. Not sure whether to feel like a genius or a fool, you scrap most of your old projects and re-implement them using this new insight, and are happy to discover how much easier it is this time. Suddenly, your scripts are much simpler, easier to read and maintain, and faster to execute.
You recognize a need to refer to a “collection” of these state objects by a single parent’s name, and come up with the concept of an “identity parent” — which holds no code of its own, but allows you to refer to any of its children through invoking the Identity Parent’s name. Before this, the idea of an object with nothing implemented inside of it would have seemed mysterious, perhaps pointless.
By this point, you’ve realized how crucial source control is to keeping your sanity. Being able to roll back changes you’ve made to code has saved you HOURS, which you’ve re-invested into becoming even more productive.
You struggle with source control a lot at first, and gradually figure out how to document your commits, when to commit.
You’re glad not to be using the old, bad “rename xx previous saves” method of restoring borked projects anymore.
You’re trying to get a better feel for when to fork, and when to merge a fork back into the trunk.
You wish you had some fellow GameMaker devs at your level who you could collaborate with… but then you’d need to beat them into submission with your vastly superior formatting and code style.
You have written enough scripts at this point, and refactored them effectively enough, so that you now have successfully written a few generalized functions that are generically useful.
You have figured out that it is better to pass parameters into a function, instead of referring to outside objects and global variables from within a script. Although all variables in GameMaker are essentially public, you’re starting to really appreciate the concept of encapsulation now, and through self-discipline, try to implement it in your projects whenever possible, limiting the occasions when you might directly access inner variables of another object to only those situations where it makes sense, such as in Collision events, or when you have a Controller object managing a collection of “drone” objects.
You can take that same function that you wrote in Project A and use it in Project B without changing the code at all; there are no dependencies upon particulars in either project.
You are ready to collect all of these functions that you’ve come up with and write GameMaker Extensions.
Now that you know how to write readable, maintainable GML code, you’re becoming increasingly concerned about performance.
You’ve read a lot of claims about various methods of performance optimization, do’s and don’ts, but sadly there aren’t many demo projects out there that can back up the claims with facts. And the ones that do exist, you have to look at the code to confirm that they were built in such a way as to constitute a legitimate test, testing fairly what they think they’re testing. What was true several years ago in some old version of GM may not be true now.
You begin looking at ways to isolate code so that you can test it properly and see for yourself which is the faster performing code. After you do so a few times and win a few arguments and gain a few reputation points on the forums, you realize how valuable it is.
You not only see it as “no big deal” to whip up a quick demo, but you actually enjoy doing it. You make the code as pretty and readable as possible, because you’re proud to have other developers referencing it when they claim that method X is faster/better than method Y.
You save those projects so you can re-run your tests when GameMaker gets upgraded to see if your findings are still valid.
You share them with the internet so they can run them on their machines and verify the results you’re seeing, audit the code you’ve written, and help you find any flaws in your tests or still-faster optimizations.
You learn to write families of functions around a problem space, some which are slower but can solve a broader case, others which are more specialized or less precise, but very fast. And you appreciate each for its strengths.
You’re maybe getting a little more tolerant of other ways of bracketing and whitespacing, and can deal with them when you have to without flipping out and re-formatting. Maybe.
And you’re relaxing a bit when it comes to Drag and Drop. It’s not a big deal when you have a one-instruction Event, to just use the Drag and Drop action for it. You don’t feel like you’re being a newb anymore when you use it; it’s just being expedient.
By now, you’re starting to realize that not every piece of GML that you write actually NEEDS to be a script, and sometimes it’s actually BETTER to write it in an Execute GML Code action instead of an Execute Script action. You use each when it’s appropriate, and have stopped writing scripts named “do_ThisObject_Event” … a while ago.
Your projects have nice, neat Objects with well thought out inheritance relationships, and only the code in them which they actually need, and it is written to be readable, maintainable, and fast — in that order, unless performance is absolutely critical.
You’ve even managed to figure out how to separate concerns in your objects’ Events, so no more single, giant Execute GML Code Action, but a series of Execute GML Code actions, each doing its own particular thing, with a nice Comment action above it, serving as a label, so you can tell what your objects do at a glance, simply opening it in the Object Editor and clicking on its Event and looking at the Comment Actions, and maybe hovering over the Execute GML Code action for a second or two.
You’ve attempted (and perhaps even succeeded) to write a specialized Engine in GameMaker, to make it easier for you to make games within a certain technical genre, such as platformers. Or you’ve looked at a few projects that have been built by others, and made use of them, perhaps even improved upon them. You probably chat with them on forums and twitter.
At this point, people may begin to address you as Lord. You may establish a freehold by building some type of castle and clearing the land in an area of a radius of twenty to fifty miles. You will then attract a body of men-at-arms led by an above average fighter which will serve you as long as you pay reasonably and maintain his freehold, and you will collect seven silver coins for every sentient inhabitant of the area through trade, tariffs, and taxes. This is the really hard part.
Where to beyond here? I don’t know. As I keep going, I’ll find out. How have you come to GameMaker? Did you follow this same path? Or did you take another course? Did you learn something that you hadn’t thought of before as a result of reading this? Or do you have something to teach me?
Update: This article has been picked up for discussion over at TIGSource forums.