Rock Popper Deluxe!

Rock Popper Deluxe!

An Asteroids-style space-shooter game for Windows, built with GameMaker Studio, and an ongoing paean to self-indulgent feature creep.

(If you’d just like to download and play the game (Windows only, at the moment), head right over here for instructions.)

Context

As a kid, I built terrible ASCII and ANSII games with ZZT and MegaZeux (all of which are now crushingly lost to the ravages of magnetic depolarization and disk-wevils), made highly derivative pixel art, and dreamed up RPG battle mechanics with my friends that no one ever wound up using. While the drive to design games in my adulthood has mostly shifted to card-based systems, I did pick up GameMaker Studio a couple of years ago on a lark and began patiently tending my hobby-horse, Rock Popper Deluxe.

RPD was initially based on a tutorial series by the prolific Shaun Spalding to remake the classic Asteroids game using the engine, but after I’d learned the interface and a bit of the framework, I grew drunk with power and possibility and began a campaign of unrepentant, convulsive feature creep, seeing if I could implement and polish any feature I could dream up. Intentional organization and forays into project management followed, though at the time of writing new updates generally come about once every couple of months when I get inspired, hoard some time, and see if I’m equal to my vision.

(Updates are posted on the RPD Devlog portion of this website.)

Reviewing the Code

The repository I use for version control is available here, though the structure that GameMaker Studio imposes is a bit arcane. If you’re interested in looking at the code, it would be helpful for you to know a bit about the language and framework. (Otherwise, I suggest you continue on to Notable Features). You’ll probably find the most interesting stuff in /scrips and /objects. Anything with a .gml (GameMaker Language) extension has my code in it; anything with a .yy seems to be an auto-generated JSON manifest for the resource and is probably only interesting to look at for the "parent" key, which describes class inheritance.

GameMaker Language (GML)

  • The language is essentially loosey-goosey swiss-cheese Javascript if you output your game to run in GameMaker’s container environment (as I have). That’s what’s running when you open my .exe file; there are some performance penalties to this approach, rather than building in precompiled native-mode, but if you try to build in native-mode, seemingly random (and appallingly undocumented) aspects of the language get super persnickety, and the call-stack goes insane, making debugging an existing project insufficiently fun for me to try it. (The reason for this is that a subset of GML syntax much closer to C is required, as far as I’ve been able to discern.)
  • The main assets are called “objects” and are effectively classes; you can do linear heredity with them and I’ve arranged mine as obj_base_entity at the top for nearly everything, spinning out to things like obj_base_enemy -> obj_base_enemy_with_thrusters (for trajectory-righting behaviour) -> obj_droid_straight_shoot (for those little tiny swarmy shooty buggers).
  • If you see an naked variable declaration (eg: points_value = 100) in the code, this is a property declaration and can be automatically accessed by object_name.points_value, in this case. Conversely, if you see a declaration prefixed with var, you’re looking at a temporary variable that GameMaker promises to clean up for you automatically when you’re done with it. Function parameters always generate temporary variables but (you could very happily set new class properties within them, like a crazy person).
  • The elements you encountered while playing (entities, shots, powerups, etc.) are all “instances” of the pre-established “objects”. GameMaker’s interface includes a “room editor” that lets you paint down tiles and instances to make pre-made scenes/levels/etc., but in my game basically everything is generated on the fly through the code. I have a few game-management instances invisibly (and uncollidably) hanging around detecting and directing things behind the scenes, but everything you see is instantiated and deleted as needed in an otherwise empty void. Probably because I’ve spent most of the last four years doing backend.
  • GameMaker allows you to create “scripts”, stored in the /scripts folder in the repo. These are a vestige of when you couldn’t write functions as properties of “objects” and worked as a place to store universal (top-level) functions callable from anywhere and scoped to the instance calling them. Because core features of the language advanced and became available as I was working with it, you’ll see some of my early physics functions in /scripts/script_movement or /scripts/script_interactions… I really ought to move these into the appropriate “objects” as methods to keep everything tidy and easier to find.
  • Code is run asynchronously, but according to universal, serialized lifecycle events. Instances have a “Create Event” step where initialization occurs, so it’s usually only run once. Then, they have a “Begin Step Event”, “Step Event”, “End Step Event”, “Pre-Draw Event”, “Draw Begin Event”, “Draw Event”, “Draw End Event”, “Post-Draw Event”, etc. (This reminded me of the React lifecycle when I learned about it.) It’s possible for “objects” to have code for any and all of these steps, and the code in those steps will run once for each instance for each frame while the game is running. If you’re looking at my code in the /objects directories, you’ll see each of these lifecycle events as their own .gml file. Create_0.gml and Step_0.gml will usually be the most interesting files to look at to get a sense of how the “objects” are initialized and then what they do for every tick of the game. The language, while improving, is limited (arrays, “structs” (similar to JavaScript objects), and methodized functions scoped to classes are all very recent additions to the language), often criticized, and probably doesn’t inherently nurture good craft. In my experience, I found my time programming the game split between trying to implement best practices as they were taught to me at PostageApp or as I’ve read about them, and the other half trying to hack and kludge my way around the limitations of the language.

Notable Features

  • Visual grades of damage on enemy entities with hooks with customizable and programmatic debris systems
  • Momentum physics! Different entity types live by different rules, but your shots’ trajectories are affected by your momentum and damage targets according to their associated vectors (accelerating towards an enemy that’s accelerating towards you while firing will do substantially more damage than shooting something moving safely away from you, especially if you’re also moving away from it). Many entities (including you) enjoy a robust recoil system to encourage deliberation and tactics over button-mashing.
  • Regenerative shields (with specialized physics for collisions between shielded and non-shielded entities)
  • Both cumulative and switchable power-up modules that affect your ship’s physics, weapons, and shields
  • A customizable background animation system to add visual interest and distinctiveness across various waves.
  • Tasteful screen-shake and motion-blur effects
  • Multiple enemy variations across multiple distinct enemy types (asteroids, asterdroids, droids, and cryptic crystal spheres… for now!)
  • A climactic, multi-stage finale

Planned Features

  • Control customization and gamepad compatibility
  • Local co-op and competitive multiplayer modes (the code for which is mostly in place, pending testing once control customization is implemented)
  • Accessibility features to customize game difficulty and rules

Feature Kanban Really, quite a lot more.

Download and Play

The most recent version of the game (Alpha 0.0.23.0503) is available to download here).

Keyboard controls:

  • Up/Down to thrust/reverse
  • Left/Right to rotate
  • Space to fire

  • Q to quit
  • R to restart
  • Alt+Enter to toggle fullscreen