Finalizing first draft level generation

Today’s development work ran the full gamut; I did some refactoring, managed to cause some conflicts, discovered a bug in my engine code (or a design flaw?) AND managed to finalize the first draft of level generation. Basically, it was an action packed Sunday.

My OCD brain was unable to leave alone the notion that the EntityPool class should a) be named ActorPool and b) should be made generic to make life easier when working with it. While I was busy doing my morning walk I had to pull out my phone and do a little research to see if I was remembering correctly that TypeScript has support for this that worked in the way that I thought. On the plus side I managed to verify that my new e-tip gloves work as advertised, so there’s that.

So I quickly modified the class to rename it and make it generic; now when you instantiate the class you have to tell it what sort of Actor you’re going to be putting into it (just plain Actor is also acceptable). This is set up to ensure that only classes that derive somehow from Actor are allowed, so that we can still do things like call the update() method internally (without this, TypeScript assumes any as the type, which forces you to type cast).

The new ActorList also got a new method that allows you to mark all currently alive entities as dead in one fell swoop, which will be important later when it comes time to actually re-use the entities in the pool in another level without reloading the page.

I also finished the first draft of the maze generation code. We now generate gray bricks and bonus bricks. These work similar to how arrows work, where we only generate a certain random number of them per row. However, in this case there is a percentage chance that a row will get no bricks of that type at all. This keeps these two brick types a bit more sparse.

While I was at it I also made some slight modifications to the arrow generation to make sure that an arrow will not generate directly under a black hole. This reduces the chances that the ball will be able to enter a black hole while moving laterally as the result of a push of an arrow. It may still be possible in other scenarios, but I wasn’t trying to stop it from happening entirely; rather it just looks more pleasing visually this way.

Just for kicks, I also modified the Arrow entity so that if it is an automatic arrow, it will randomly flip directions. Currently this happens as a function of time, so just sitting there causes this to happen. I’d have to check back with the source first but it seemed to me that in the original the arrows only chose to move or not while the ball was in motion (sort of turn based). Until we get more work done and can actually start playing, I won’t know if this matters or not.

Sample maze generations

Sample maze generations

To make testing easier I added in the ability to regenerate a maze without reloading the page by pressing the G key. This exposed either a bug or a design flaw in my engine code that I’ve never noticed. When an entity is created, it creates a SpriteSheet, which creates an Image, which it marks for preload. The preloader will throw an exception if you try to preload an image after the game has started running.

As a result of this, attempting to create such an entity after the game has started causes a bit of a problem. Clearly in this situation it should just re-use the image that it has. I would have to dig into the engine code to determine if I meant to do it this way or I’m just using my classes wrong. One solution would be for the entity class to preload the image and have instances access it directly. That seems sort of involved, so for the time being I’m using my new ActorPool class to ensure that I’m creating all of my entities at startup. Who knew that would come in so handy so quickly?

I want to re-work the generation code a bit more before I proceed. The random number distribution is all out of whack, which makes things visually ugly. For example, there can be either 1 or 2 bonus tiles per row. This is randomly generating a number that is either 1 or 2, which means that it’s usually almost always either 1 or 2 for any given level. I think it would be better to spread that around.

I have a couple of ideas for this, such as creating an array like [1, 1, 1, 1, 2, 2, 2, 2, 2, 3] and then randomly generating an index into the array to see what the number is. That would allow me to skew the values selected a bit better, I think. Tomorrow’s primary task will be to play around with that and see if we can come up with something better.