Dev Blog: What I Learned from Derek Yu

On last week's episode...

It's been a while since I posted about a game I've been working on. Then again, when my last game featured a goat, lackluster hit detection and Keith Moon's head in a jar, you'll understand if I wanted to take some time to rethink the tools I've been working with.

Everyone has to start somewhere, of course, and it's a poor craftsman who blames his tools. Still: a goat jumping on laser beams in space? Yeesh. If that's not a good reason to do some soul-searching, I'm not sure what is.

Look, I wasn't kidding - this is a game with a goat and lasers and Keith Moon, yet /somehow/ it's not the coolest thing ever made
Look, I wasn't kidding - this is a game with a goat and lasers and Keith Moon, yet /somehow/ it's not the coolest thing ever made

I spent a week sketching out some new ideas and revisiting older concepts I considered developing over the years. After a healthy amount of time away from GameMaker, I came to a realization: GameMaker ain't half bad. It's actually a robust tool, as the developers of Hotline Miami and Spelunky will undoubtedly tell you, but it suffers from two significant shortcomings that help explain why I felt stymied in making my game-jam game.

  • First: GameMaker's emphasis on its drag-and-drop, what-you-see-is-what-you-get programming interface is shortsighted. The visual language isn't particularly intuitive, and its design makes debugging a nightmare.
  • Second: The included tutorials are, by and large, not very well-constructed. It's pretty clear that GameMaker was designed and marketed as a widely accessible tool, suitable for classrooms and seasoned game devs, but the tutorials are hamstrung by a lack of context behind the methods it teaches you and, again, a reliance on combining the drag-and-drop interface with snippets of actual code.

I don't have an engineer's mind, but I'm happiest when I understand how things work. That's why I've been drawn to programming throughout my life: I don't care about the science behind computer programming so much as I need to see how the pieces fit together -- how the mechanism moves.

Thankfully, I found a GameMaker tutorial that's almost entirely code-based, and it's gratuitously documented with plenty of logic and reasoning behind the approach it teaches. Unsurprisingly, it's by Derek Yu, the creator of Spelunky -- perhaps still the most-ambitious and endlessly enjoyable game ever made in GameMaker. Without a doubt, it's the best introduction to making games I've ever seen.

Now that I've finished all four parts of Yu's tutorial and learned enough from it to add some additional features of my own to the finished product, I wanted to share some things I learned from the process.

Things I learned

Make sure you take this to heart, even if you forget everything else you read here: The best way to learn how to do anything is to do it yourself. So that's what I did. Yu's tutorial provides plenty of art and code to pull out and utilize, but he encourages you to make everything yourself as you go. So everything in my game -- every sprite, every tile in the environment, every bit of text, every line of code -- is my own.

I even drew my own retro-arcade font for the game, pixel by pixel. Worth it.
I even drew my own retro-arcade font for the game, pixel by pixel. Worth it.

Yu actually presents almost every bit of code you'll need, so I suppose it's not entirely true that what I have written is solely my own doing. However, I wanted to challenge myself to put the pieces together on my own to best simulate what it's like developing something without a safety net, so I always wrote a first draft of the code on my own and tested it to make sure it worked. I'd then compare it to Yu's example and, if I missed something clever or more efficient, I'd modify my code to match his. In one case I even found a more scalable way to implement a script where I had more central control over variables affecting the flow of play -- the speed that the player and their surroundings move, for example -- which made it easier to test out the "feel" of the game as I was building it. So yeah, go me.

If you, like me, haven't drawn any sprites in a long time, you'll be thrilled to discover a tool called Aseprite. It's a free sprite-making tool with a GUI and hotkeys that'll be instantly familiar to Photoshop veterans, and it's available for OS X, Windows and major Linux distros. If you're serious about making (or even just prototyping) games, go grab a copy.

The next major lesson I learned is code is king in GameMaker. And thank god, because I'll be damned if I get stuck working with a clunky, drag-and-drop development tool.

In other words, GameMaker works great even when your game is almost entirely code-based. Executing code and writing/calling your own scripts is also far more efficient, far more powerful and-- bonus! -- much more transferable to other game dev tools you may move on to.

For example, I was able to draw a pretty simple but useful HUD (heads-up display) with just a few lines of code:

if (state == PLAY) // In other words, "If the game is being played and isn't at the title screen/game over/etc..."
{
    // Draw HUD
    draw_sprite(sPlayerShipIcon, 0, view_xview[0]+3, 226); // Shows a mini-player ship to indicate lives left
    draw_text(view_xview[0]+18, 228, /*"X" + */string(global.pLives)); // Shows number of lives left
    drawTextCentered("SCORE " + string(global.pScore), view_xview[0], 0, 8, 320); // And this shows the score. Boom.
}

Doing the same thing by dragging and dropping parameters for an object would've been far more cumbersome and less open to customization. If you, like me, find yourself scratching your head at the lack of flexibility in the drag-and-drop method, prioritize doing everything in code first. The YoYoGames Wiki is a fantastic resource, and failing that, GameMaker: Studio's built-in help database is actually pretty well-written and searchable.

The third and perhaps most important lesson: Don't be afraid to wander. Your curiosity is the source of your creativity, and you can always sidestep from the lesson at hand to test something out. In the case of following a tutorial, there's still plenty of room to add or modify things while sticking to the guidelines as long as you do it within reason. For example:

  • Don't: Deviate from the basic logic and design you're learning from, remove core components of the game
  • Do: Modify your NPCs, customize level designs, experiment with implementing randomness and tweaking it through playtesting

This spirit of being willing to try new things taught me a lot along the way. I tested writing bits of code in a different way, creating basic movement patterns for the enemies (those gangly-looking squid-bubble things you see up above) and even implementing acceleration/deceleration in player movement. Those are all concepts that may or may not be the best fit for this game -- especially within the scope of the tutorial -- but they're valuable snippets of knowledge I can tuck away (and blocks of code I can store elsewhere) for future projects.

Things to avoid

With any luck, you'll find something useful in the advice above. Still, I want to call out a couple of common mistakes to watch out for:

  1. Taking the easy way out:  Do everything yourself at least once, even if it's tedious -- especially if it's tedious. For example, debugging movement and collisions is almost always a pain in the ass, but you'll learn so much from slogging through it. I learned GameMaker has a ton of options for defining hitboxes, which made it much easier to fine-tune my game to make sure any collision between the player and other objects felt fair. (Just for reference: A hitbox is a shape that defines what areas of an object are considered to be "solid." In other words, when Mario runs into a Goomba and loses a life, his hitbox collided with the Goomba's and the game knew to execute code to subtract a life from the player and restart the level.
  2. Importing other people's assets: If you've never made your own full set of assets (art, code, music, sound, etc.) for a game, you're cheating yourself out of a lot of fundamental knowledge. Plus, doing everything yourself teaches you to make sure every piece of the game fits together in a natural way; otherwise, the player winds up needlessly distracted by how slapped-together your game looks instead of focusing on how it plays. Hell, I even drew my own font across a set of 59 sprites. That took time, but I learned some valuable bits of GameMaker code in the process and I got the retro look I was going for without ripping something out of an old Namco ROM. Sure, once you've got the hang of the basics of making games you should feel free to pull in existing assets to accelerate your prototyping process, but there's no substitute for experience.

Next steps

I can't overstate how much better prepared I feel for future GameMaker projects now that I've finished Derek Yu's tutorial. Still, even as I start to make new things, my mind keeps wandering back to the basic shoot-'em-up I built. What if I'd just added ___ to the game? Wouldn't it be way cooler if ___ happened when you did ___? That kind  of stuff.

While I can't promise I'll ever polish this thing up into something more presentable, here are the things I’d prioritize:

  • Sound and music: Games feel empty without audio. If I do end up going back to work on this shoot-’em-up game, I plan on making every bit of sound by myself. GarageBand's surprisingly robust and easy to work with for making music, and Bfxr is a sweet web-based app for generating your own sound effects on the fly.
  • Score counter: I just added this to the build I uploaded before writing this post, but I'd love to give it a little more focus. Scrolling numbers could be a lot more fun. And fortunately, it'll be super-easy to modify it thanks to the drawTextCentered() script I wrote while making the game.
  • Enemy diversity and movement: Unless you're sorely lacking in reaction time, it's really hard to be killed by an enemy in this game. I'd like to change that in the future by adding several enemy types, distinct movement patterns and bullets they can fire towards the player.
  • Boss enemy: Before uploading the final build for this post, I added a bit of logic to make the camera stop moving once you arrive at the end of the stage. My intention behind that was to have a boss appear before you can finish the stage, but I haven't figured out what I'd like it to do. Still, I have plenty of ideas, and designing a great boss encounter is one of those things I've always wanted to do.
  • Random level elements: Games are most fun when systems are in play, and a big part of making a game feel open-ended is randomness. Nothing is randomized at this point, but enemy spawn points, movement patterns and even chunks of the level that appear could all be randomized. This would be a big area to focus on if I actually wanted to make this game, you know, fun.

Thanks for reading! I hope this was helpful, especially for those of you who've struggled to get into working with GameMaker previously. I'm not sure what's next for me, but I've got a few ideas for modding games like Dark Souls and Skyrim that I'd like to try out. Then again, now that I'm feeling more confident with the GameMaker IDE, maybe it's time to go back to the drawing board with something more ambitious.

Want to learn more? Download my game and several of the assets I made.