Another week, another bloggity update on game development goings-on. A lot of this week was spent in setting up some “behind the scenes” stuff. In particular, I set up a new subdomain, http://gamedev.nurdz.com for posting my game development explorations. Currently there are only two things posted there, Rx (the same code as is posted at itch.io, see previous post) and a nascent page for the upcoming pong port, which seems to be called Tennis Mania.
I also tweaked up the blog a little bit so that there are links to all of the relevant code repositories. Somehow in all of this business I actually ended up doing some game development stuff!
In the interests of clarity of code the original uses non-OOP layouts with global variables for state, which doesn’t really fly in a class based layout. Also the code that handles the ball and the code that handles the paddles are both integrated; the ball needs to know about the paddles to know when it is being reflected and the paddle (if computer controlled) needs to know the trajectory of the ball in order to determine where it wants to move to.
For now the global state is still global, but it is held inside the nurdz.game module, which means that despite being global it is available to all code without actually polluting the real global namespace. This is good enough for now, but I’m thinking that maybe some sort of explicit game state or Game class/object is a better way to go. As for the chicken-egg of the ball and paddle both requiring each other, that’s still up in the air, as that part has not been fully ported yet.
Instead I stepped away from that to make a modification to ts-game-engine regarding preloading of assets. One of the things I was pondering regarding a SpriteSheet/Sprite class is determining the dimensions of an image between when you ask for it to be preloaded and when the game actually starts. I’m guilty of a little over thinking on this one.
Originally I was thinking that since a load event won’t fire if an image is already loaded when you add the listener (I think), you would need to use a different property on the image to see if it’s already loaded, and then either do things or attach the event handler as appropriate. I was a little worried about potential race conditions here; what happens if the image is not complete, but finishes loading just before attaching the load event handler happens?
This turns out to not actually be a consideration at all, because no matter how many images are preloaded, the load does not actually start until you call Stage.run() to kick the game off. Since all preload requests happen at object construction time, this is not a worry at all; all preloads are queued up and then once everything is ready to go, THEN the preloads happen.
As such I have now included a mechanism in the engine by which when you preload an image or a sound, you can also optionally supply a callback to be invoked when that particular image/audio is loaded (or in the case of audio, when it has loaded “enough”). The callbacks get the actual HTMLImageElement object for images or the ts-engine Sound() instance that wraps the HTMLAudioElement object for sounds, so that doing things with the resulting object is as simple as possible.
The Ball entity in ts-tennis sets up its width/height to be 0 at construction time, but when its image is loaded that is used to set the actual bounds of the object. This is something that the original code was not smart enough to do, and although it’s not strictly necessary it DOES seem like something that makes things more robust for asset changes.
Work on this port will continue into next week. I’m hoping that a week is enough to fully grok all of this code again and replicate it in the new engine so that the task of polishing it up and finishing all of the other exercises associated with it can commence. At this point I can’t actually remember where I left off with the exercises in the textbook, but I figured that the best thing to do would be to port it first so that I would know for sure what it’s currently doing.
Until next week!