Rog: A Rogue-like Engine
A turn-based tiled game engine for rogue-like games developed over seven evenings.
Tile-based renderer, virtual camera, spritesheets, animator, game-state trees for AI, queue-based update loop.
Rog started up when one of my good friends proposed an idea for a rogue-like. He’d been playing a lot of Sil, a rogue-like based on Tolkien mythology.
He played the game to pieces, but had some improvements in mind. While the game was interesting, navigating the UI was inconvenient.
Also, the game was difficult to the point where completing a run was something of a feat.
We both worked at the same company, and we both itched to do something creative during our off-hours. So, while he worked out the mechanics, I worked on a prototype engine.
I chose Flash because I had experience with it in middle school. It also seemed the most accessible platform for distribution at the time.
Building the Engine
However, the devil’s in the details. Learning to implement everything I wanted to do was an exercise in patience. Reading through documentation taught me the language features relevant to me.
Rog’s game state was stored in a class called (wait for it) GameState. The map, position of characters, their statuses, everything.
This way, I could load new GameStates as different levels.
I could also pass these GameStates to enemy AI. The AI could then base decisions on the player’s stats, equipment, its proximity to other enemies, etc. It could also simulate future moves by running the GameState itself.
The current enemy simply calculates the shortest path to the player, attacking anything in its way.
I tried something a bit experimental with the engine’s update loop. Anything the game did was defined as a type of GameAction. Each update, the engine would run through a Queue of GamesActions, performing each one.
The main benefit was that complex sequences of actions could resolve in a single update. However, my implementation created scheduling problems. This had consequences later when I tackled animation.
The next step was to implement the renderer.
I wanted the player to be able to pan the camera around the world, so I implemented a virtual camera. Players could drag their mouse around to see the full map. To position entities in the world, I created an interface called Positionable. Entities implementing Positionable could keep track of their map position independent of where they rendered. Another interface called Drawable would handle where to draw it on the screen.
To achieve the flexibility I wanted, I developed my own sprite renderer. I wrote Spritesheets as an extension of Actionscipt 3.0’s BitmapData. Spritesheet handled which sprite to cut and how much to scale it by.
Now, I had a renderer drawing the world through a virtual camera.
I had most trouble with my animation system: GameAnimator.
- Animation data was tedious to write.
- GameActions could schedule animations.
First problem – Every animation needed to be programmed by hand. This included offsets from the map position, whether the sprite needed to flip, the number of frames, etc.
I needed an editor, but I didn’t think to write my own. After working on Project Battlefield, I’ve seen the benefit of writing my own editors.
Second problem – Scheduling animations was complex.
GameAnimator allowed GameActions to schedule concurrent or sequential animations. It grouped animations together to keep track of sequence. While it seemed straightforward, GameActions had no context. This complicated things for the GameAnimator .
I’m still unsure whether this system works or not. It certainly fits Rog’s turn-based feel. Perhaps extra tweaks would iron out the last wrinkles and produce something I’m satisfied with.
After some time, work picked up and we ceased to develop the game.
Still, I learned a lot from the experience. Something I found useful was the polymorphic game action. Since subclasses take the same type of input, the input both encapsulates scope and makes actions easy to combine. This is a design I’ve carried over into Project Battlefield and Marquis.
I learned a lot about the pros and cons of using queues. It’s great for scheduling things, but it’s hard to interrupt the sequence efficiently. I plan to use what I learned in the networked card game Marquis.
I believe Rog needs more work and I’d love to extend it in the future. However, Rog as it is today is a complete rogue-like engine. I think I can take some pride in that.
Sil screenshot taken from Sil’s homepage.
All other graphics were created personally.