When writing scripts in Game Maker Language projects, I have come to realize a couple things that I want to share for anyone else who might be working on GML projects:
GML parsing is a bit loose. This makes the language fault tolerant, which is nice for newbie programmers who don’t need to get beaten up for not following strict syntax. But by enabling you to get away with imprecise syntax, it lets you get in to trouble that isn’t easy to detect.
Strict syntax is your friend, if you have it as an option in the language you’re using, I recommend following it as soon as you’re comfortable. Strive to get comfortable as quickly as possible. Unfortunately, GML does not have a strict mode…so I have the following tips to offer:
- Scripts (sometimes referred to as “programs” in the official Game Maker documentation) are supposed to begin and end with curly braces. The interpreter is forgiving if you don’t do this. But you should always do it.
- GML terminates statements with a semi-colon. The semi-colon is semi-optional, but I recommend using them wherever you intend a line of code to end, so that the interpreter doesn’t have to do extra work guessing that for you. Doing so will make it look like you know Pascal, C, or Java more than you know VB, which is enough reason to do it;) (Usually a statement is more or less the same thing as a line of code in your script file, but some structures may incorporate blocks of code, such as loops or branches.)
- Strings in GML can include line break characters (there’s no escaping with \n or using a character code like CRLF, like there is in most languages), so if you want to have a string with a line break in it, you simply hit the enter key and put a literal line break in your string. The interpreter handles this OK since the string is bounded by double or single quotes, but it’s still a weird thing about the language that they don’t really explain adequately in the documentation. If you’re not using semi-colons where you intend to end a line, it can get confusing to look at a multi-line string declaration that incorporates the line break as part of the string.
- It’s easy to not scope your variables appropriately without realizing it. GML allows global vars, and has two kinds of locality: locality with respect to an instance of an object, and locality with respect to a script. You shouldn’t use globals unless you really need to; according to the language doc they are slower to access than local variables. I haven’t noticed any difference that I can measure, but I’m sure that it is something that adds up, and at any rate proper scoping is a good habit to get into.When I refactored my project to pull drag-n-drop code out and replace it with scripts that were more re-usable, this caused some of my instance variables to turn into script variables. I had to go back and turn them into instance variables once I discovered that this had happened, and caused some issues with the way the code was executed by the interpreter.If you’re using variables in a script that were not declared in the object somewhere (normally the best place for this is in the object’s
create() event), and you are declaring the variable in the script, but you want to make it an instance-local variable, you can do so. The code to do this is:
That dot between
MyLocalInstanceVar is actually an operator. Knowing this is nifty, but I am not prepared to expound on why just yet.
Keep reading the language specification doc! Every time I go back to it and read, I pick up something I didn’t know, or refine something I thought I knew. One of the really nice things about GML is that it’s a small enough language that you can pick it up and do things with the basic features right away, without needing or being overwhelmed by all the other stuff that you’ll discover as you continue to progress as a developer. And there are enough built-in features in GML that you don’t have to spend a lot of time figuring out how to build sophisticated stuff out of primitives all by yourself.
The more I work in GML, the more respect and appreciation I gain for it. It is not the purest language, nor is it the most powerful, nor is the development environment as rich and sophisticated as a “serious” IDE like Visual Studio or Eclipse, but it is extremely accessible for a non-programmer to pick up and start working with and being effective quickly.
If you dread or fear refactoring, it’s because your code is a big ugly mess.
If your code is a big ugly mess, it’s because you didn’t refactor soon enough or often enough.
To make your code not be a big ugly mess, you need to refactor it.
So, refactor every time you see the opportunity. Keep the code lean and pretty. Then refactoring stays simple and easy and doesn’t take long or hurt.
I say do this even if you feel mounting deadline pressure. In the long run, the gains in maintainability will far outweigh perceived slowdown of productivity. Working on maintainable code is far more productive than working on unmaintainable code.
Don’t ship messy code. Messy code hides many flaws. Flaws that you’ll need to fix sooner or later anyway. When you fix a mess, it’s a lot more work than fixing something that’s clean.
The most memorable moment for me was in the afternoon, when I spoiled a rant that Mark was about to launch into about a perceived problem he had with TDD “forcing” the programmer to code improperly by requiring them to expose inner members of classes that should properly be kept private.
Instantly, I blurted out, “So write the test method inside your class!” It was kindof a “from the mouth of babes” moment. I barely even thought before the words came out of my mouth. I wasn’t even sure if that was the right answer or not, but I guess it must have been, because the look on Mark’s face was priceless.
There were so many messages in that look: 1) that I was right with my guess; 2) that Mark had been stuck on this mental error for some time; 3) that it might’ve humbled him a little bit that he hadn’t seen it before.
I don’t mean to embarrass him by recounting this — if I thought this would, I’d never be using his real name. It wasn’t that I’d really shown him up — he’s got way more experience than I do, plenty of success under his belt, and he’s someone I like personally as well as look up to. But that was the first moment I felt like I was capable of making a tangible (if relatively tiny) contribution, that it wasn’t just a one-way knowledge transfer from the more experienced programmers at the event to me.
What made it a moment I’ll never forget was that I saw that I wasn’t the only person who gets mentally stuck in my own problems when it comes to programming. If a guy like Mark can still make a mistake like that once in a while, it makes me feel a lot better about doing it too, now and then.
But the bigger lesson is, it totally reinforced the value that we all get from being in the same room, talking to each other, making mistakes in front of each other, and learning from each other what lessons we might. With enough eyes, all bugs become shallow.
I went to a local CodeRetreat event hosted at Lean Dog, an agile development studio in downtown Cleveland. I had a great time, and learned a few things. There were a great many more things there to learn than I was able to learn, but that just means I’ll have an equally great time at the next one.
We broke the day up into 5 sessions, working in pairs on a test-driven development exercise. At the end of each exercise we deleted what we coded and paired with someone else and repeated the exercise. It was interesting to see both how different pairs would approach the problem, and how I approached the problem differently with each successive pairing. One of the interesting things I got out of this was how my own thought process and approach to solving the problem improved each time. Even though just 45 minutes had passed, each successive attempt was markedly better than the last. I’m intrigued by this and will be less reluctant to throw out code and start over in the future. I also gained greater appreciation for how important it is to pick good names for your variables, objects, properties, and methods. Good names really make it easier to think clearly about both the problem and your code.
I’ve heard of, and seen examples of, test driven development before, but never done it myself. I got an introduction to NUnit, which I’ll definitely be making greater use of in the future, courtesy of Mark W. Schumann of criticalresults.com. I got to pair with Jeff “cheezy” Morgan, who demonstrated some very keen insights on the essence of TDD, and gave me a little exposure to the Ruby language.
I’m really happy I went, and can’t wait to find more events like this to take part in. Lots of thanks to Corey Haines and everyone at Lean Dog for putting the event together.
I’ve released an update to DomeWrinklesCurl. This isn’t really much of a game still, it’s just a simple rock-paper-scissors programming exercise for Win32 CLI console.
The new feature in this release is improved stat keeping.
With this release, I’ve also cleaned up the code a little bit. The initial release ran OK, but internally was a bit messy. Not a big deal, you won’t notice unless you look at the source and compare it to the 1.0 release.
I’ve been thinking of ideas about what I where I want to take this project…
- Sound effects
- Colored text
- Select # of players (0-2)
- Named players
- External configuration file for settings, game stats to persist
- 2-player network play
Once I get this much done, I’ll have enough of a framework developed to begin building a real game with, and I’ll start moving from the Console to GUI.
Download it here:
dwc.exe (zip archive)
I wrote a windows console game in C# as a programming exercise.
It’s nothing spectacular, but it’s my first game, and I’m happy with the way it works.
The game is a silly pug-themed implementation of Rock Paper Scissors that I made up, called Dome Wrinkles Curl.
- Dome straightens the curly tail.
- Wrinkles cover dome.
- Curl wags away the wrinkles.
Download it here:
dwc.exe (zip archive)