DWITM PROTOTYPE POSTMORTEM

Date: 05/03/13

Now that my prototype is complete, I wanted to take some time and review the decisions I made. Since it's only a prototype, I'm not taking the lack of content into consideration. A future build would include more tilesets, enemies, and abilities. The prototype also lacks a menu, saving system, ending, and proper introduction.

I made the decision to move forward using only my current knowledge of JavaScript at the beginning of this project. This was important to me since I hadn't done anything on a larger scale (other than this site itself) since graduation. I believe that there is no better way to learn than to simply do. You can spend all the time you want researching, but you only absorb so much. Putting this information into practice strengthens what you learned. You may find that assumptions you made are incorrect, or something you thought was complicated may be a lot easier in practice.

This is how I learned to scale objects visually in the game. I wanted a dynamic screen that would adjust according to the size of the browser window so I started to tinker around. I realized it was easier to scale visually at the end, when drawing the objects on the screen, rather than scaling each calculation individually. I also found that the object designs I had in mind didn't allow for items or dynamic tiles that can break. To remedy this, I changed the container (array) originally intended for enemies into a container for any dynamic entity that can collide. I then added a method to every collidable entity that runs when the player collides with it. That way a power-up can respond differently than an enemy even though the same method name is called.

Gameplay with a smaller scale

I wanted to look for a better looping option to replace setInterval/setTimeout. The solution was to use requestAnimationFrame. There are a few things to consider when using requestAnimationFrame though. Unlike setTimeout/setInterval, you don't have control over the amount of time between each call. This is because requestAnimationFrame is set to run as close to 60 FPS as it can. If this is too fast, you can artificially slow it down within your own code. Another negative to requestAnimationFrame (that will disappear eventually) is the lack of browser support. It's still under development, so you need a prefix in front of it which depends on your browser. Not only that, some browsers have virtually no support for it. Chrome and Firefox adopted requestAnimationFrame fairly early, but Safari didn't until Safari 6.0. Internet Explorer was the same way and didn't have support until IE10. Opera still has no support to date.

Here is the code I used in order to avoid prefix discrepancies

Including audio was another hurdle when using audio tags. In this case, each browser supports different audio formats. I wanted to use Ogg Vorbis since it's open source, but IE and Safari don't support it. The solution was to add a second set of audio files that use the AAC format. AAC doesn't require a license or payment so I can avoid the chance of legal threats that using the MP3 format would allow.

In order to make the game more efficient, I made a couple changes to the code. An object is only drawn or updated if it's within a certain distance of the player.

Here is an example with the drawing/update distance reduced

The second change I made was to the map builder. Each map is contained within a 2-D array. Each position in this array contains a single letter that corresponds to a tile type. An "X" is a solid tile, an "A" is a background tile, a "Z" is a crumbling tile, and an "O" is the lack of a tile. The builder runs through each row and places a tile in the world according to the letter. Solid and background tiles automatically check their neighboring ones to decide which tile to display from the tileset. That way tiles with nothing above them have grass and cliffs have corners/edges. The change I mentioned was to move tiles in the center of groups to the background tile container. I did this because background tiles are simply displayed on the screen and have very little properties to them. No collision checks are made against these tiles, and since you can't collide with a tile in the center of a group, it avoids unnecessary calculations.

Here is an example with the background tiles hidden

This still leaves more than enough room for improvements. There are some very big problems with my game. I didn't know how to properly encapsulate objects in JavaScript which means that any code can be accessed from anywhere. I was also having scope issues within functions and my quick solution was to access a few things using the window object. These barbaric solutions weren't bad to deal with at the time, but going back to this code at a later date or working with another person using these bad habits would not go over well. A simple example would be to think about applying force from gravity to the player. The way the game is coded, you can do that anywhere. If someone were to look at my code they would need to guess where to look for the calculation. Am I subtracting velocity within the physics object or the player object? The same thing can be said when checking collisions or taking damage.

Collision detection could use an overhaul as well. If an object was moving at a fast rate, it was possible for it to jump right over another object. What I mean by that is if a ground tile is ten pixels wide and the player was moving at twenty pixels per frame, the player could pass the ground tile without ever having overlapped. My solution was to add a cap to velocity, but that is fairly limiting to a game. A better solution would be to calculate movement of objects in smaller increments when they are within a certain distance. This can be implemented along with a collision grid that reduces the amount of objects you need to check against.

Inheritance is another factor I considered, but didn't apply as much as I should have. JavaScript has prototypal inheritance which means that an object can be a clone of an existing object rather than an instance of a class that extends another. I only ended up using prototypal inheritance once in all of my code, because I made the mistake of saying "I'll come back to it."

There are also a few things to consider with the platform. I'm not sure about other JavaScript engines, but Google's (V8) is much less efficient when using floating point variables. I used floating point a lot, especially when scaling. I've also read it's more efficient to pre-render images off-screen in a separate canvas element rather than pulling data from an image file and rendering straight to the game canvas.

The idea from this point is to make these changes in the next iteration of the game. I knew about some of these issues when I started, but creating the prototype put a lot into perspective. I realize how important some of these changes actually are, and I can design around them. I also picked up a lot of smaller knowledge that I hadn't considered before, and this will factor into the redesigning. I wouldn't have learned any of this if I didn't get my hands dirty and create something.