Here at the end of the second day of Devember, progress has been made towards the actual generation of levels. I’m hoping that I should have at least an initial implementation ready for tomorrow. Today I spent some time reworking a couple of graphical assets as well as implementing the rest of the entities that are needed for level generation, which includes some animated ones as well.
I started things off today with a little bit more refactoring, which was entirely intentional. I gave the maze grid only the ability of set and get the value of grid cells as bricks (which is mostly handy for generation of the level) but which is not fully compliant with getting at non-brick items in the grid. This was just a simple matter of creating a more generic interface and then refactoring the existing API functions to use the new ones. This basically just saves having to do a typecast on every brick request.
I then went ahead and implemented a couple more level entities, which also included extending the Brick entity a bit and changing the graphic assets that I had previously created to make rendering a little easier.
Basically the rendering code iterates over the entire grid of bricks and renders the appropriate entity for that location, which defaults to the empty tile that fills the grid if nothing is there. This means that for any entity that does not completely obscure the square, we first have to render the empty brick tile, followed by the entity itself. The determination on whether or not this needs to happen is based solely on the contents of the square being an instance of the Brick entity, since those should always obscure the entire tile.
While this works just fine, I neglected to take into account that the Brick entity variant for gray bricks (which are solid and then vanish near the end of the game) are animated to show them shrinking out of existence. This would complicate the rendering code to require it to render the backing tile for non bricks OR for bricks that are gray and shrinking, which is a pain. Instead I modified the tile sheet so that the background of the gray tile frames contains the empty tile instead of being transparent, which seems a lot cleaner.
Similar operations were taken for the tiles that represent bonus points if the ball passes them during the game. I made that another subtype of the Brick entity and made similar graphic modifications to it, so both of those entity types can appear and disappear as needed.
Other entities that were added were the “Black Hole” (a spinning spiral) that will ultimately teleport the ball to somewhere else in the play field, and the two kinds of arrow blocks, which direct the ball through the maze. Both arrows have the ability to point either left or right and to rotate between facings and are identical except for the background color. The idea is that some arrows will switch position every time they push the ball, while others will spontaneously change directions.
For the purposes of testing, an entity of each new type is added to the level at startup. The gray brick and the bonus tile vanish and reappear at set intervals, the arrow swaps directions once a second, and the black hole is in a state of constant rotation:
So far I’m fairly pleased with how my animation system is working for me. It’s set up so that you can add any number of named animations with a list of frames to be played. Animations can loop and ping-pong, plus each has it’s own private frame rate. Everything is hidden behind the scenes in the Actor class (the base class of Entity) to drive the animation based on invocations of the update() method, which just modifies what the current sprite to be used for rendering is set to, allowing the default render() implementation to do everything we need.
The only “problem” that I have come across is in the Brick entity; here the Gray and Bonus variants need to be sometimes animated and sometimes static (i.e. when they are not actively vanishing or appearing) while the variants for the background tiles and the screen edges never animate. My implementation doesn’t like to play nice in this situation; invoking update when there are animations seems to want to fiddle the current sprite value even if the animation is not currently playing (specifically by setting it to 0, the default sprite).
I never checked so I’m not sure if that’s an oversight on my part or if I intended it to work that way as a reminder that you probably don’t want to mix automatic and manual animations together. I’m easily getting around it here by having a single frame idle animation for the bricks not vanishing, which works just fine. We just make sure to only invoke the update() method for entities that we know are animating.
With all of this in place tomorrow I plan on getting started on actually randomly generating the levels. I don’t have any hard and fast rules for how this should actually work, so probably a bunch of playing and tweaking will be needed in order to come up with something pleasing. I didn’t get to this aspect today because I was pondering the design of an entity pool class of some sort that would easily allow the Maze entity to keep lists of the entities that it needs to animate separate from the ones that it doesn’t so that we don’t waste time invoking the method for things that don’t need it.