Hello OpenFL community!
This post is one part showcase, one part request for critique. I am still very much in the discovery phase of learning about OpenFL, and before diving deep into some passion project I want to make sure that I understand the groundwork and best practices for the tools that I’m using.
So, over the past month or so I’ve worked on re-implementing an old open-source Ludum Dare game created by Markus “Notch” Persson called Breaking the Tower. The original game was written in Java and published as an applet (in other words, old technology), but the entire game is open source for others to explore.
Seeing that this nifty little diversion was created in 48 hours for a video game competition, I figured that it would be an interesting exercise to re-implement it in Haxe using OpenFL. I could focus on learning some of the fundamentals of this relatively new technology, rather than getting bogged down in creative “designer’s block” and/or scope creep.
You may play a rough, alpha version of the game here!
The source code is available on GitHub!
After you’ve attempted to play the game and have become sufficiently disillusioned with my half-baked implementation, I would greatly appreciate your advice and insights into how to better architect my code for this sort of application.
General advice is welcome, but here are a few specific questions that have plagued me during development:
In the original Java code, a single-frame buffer of sorts was passed to every game object, and the object was responsible for drawing its own bitmap in the proper location on the screen. My understanding is that this strategy is called “active rendering.”
OpenFL, on the other hand, advocates a “passive rendering” strategy, in which the developer simply adds sprites to the display list and updates their position and other properties as needed. Frame-by-frame redrawing is handled internally.
I tried my best to organize my code with passive rendering in mind. Where possible, sprites are added to the display list in an
init()function called once, and sprite properties are updated in event handlers (rather than in the
render()function called every frame).
However, I wasn’t always successful at keeping my render functions clean. Generally, I faced the issue that my spritesheet (a tileset) was passed in via an
init()function called after an object’s construction. Although this helped me separate the logic of a game object from its visual representation, it also meant that I could not reference the sprite sheet in any event handlers. Instead, I had to store extra information about game objects in private properties (that’s okay, I guess) and then still update the sprites on every frame referencing those properties (not good at all).
Are there more appropriate/canonical strategies for handling this separation of concerns—logic and rendering?
Speaking of event-based visual updates, I started to go down a rabbit hole with defining custom event types on which I could store data. After making two of these custom event types with almost the same source code, I felt that I was missing some obvious utility to do exactly this task (dispatch events with simple pieces of data associated with them). Since I had already written non-event-based code that worked fine, I punted on the issue until I could ask the OpenFL forum.
Is there a better way to handle the large number of data-tagged event types that inevitably show up in game development?
With the large number of trees and rocks, using the Tilemap classes seemed like an obvious decision, until I needed to do a custom drawing of a simple graphic object (the health bar) interspersed in the Tilemap’s tile ordering. You can see the original forum post where I asked about this. In that topic, the consensus was to create multiple tiny Tiles in a TileContainer that could be transformed (scaled, rotated, etc) as though they were just blobs of pixels on the screen.
That strategy seemed to work just fine, but I wonder if others haven’t figured out better solutions to adding ad-hoc “mini-canvases” for custom drawing within a Tilemap. Has anyone else attempted this sort of Tilemap customization? What are your strategies?
I eventually want to write a series of blog posts outlining the design process of a game like this in OpenFL, talking through it “tutorial-style” so that readers can write the code as they go along. The process has been invaluable to me already, and I feel that others would appreciate such a comprehensive resource outlining the best practices for OpenFL/Haxe development in 2021.
I also want to customize the game to make it unique to me, and not infringe on Notch’s intellectual property. This part of development is some of the most exciting stuff (creative, self-expression work, rather than trudging through display logic and platform-specific nuances).
But I don’t want to pursue either of those tasks until I get out of my own echo chamber and hear some feedback from more experienced developers. There is little worse than an uneducated developer like me touting kludges as “best practices” on the Internet and consequently driving many other aspiring game designers into confusion and disillusionment.
So, regardless of whether you read this entire rambling post, please let me know what your thoughts and critiques are, good or bad! This project is the most fun I’ve ever had doing video game development. At the end of the day, I want the products I produce to be both fun to play, and useful for other developers to learn from when reading the code.