Sunday, November 15, 2020

Porting a Game in Zero Hours

 


Way back in 2014, I participated in a game jam called the Zero Hour Game Jam, with the idea being that you had to write the game between 2AM and 2AM when the times switched for daylight savings time. This “missing” hour would we the time you wrote your game in. The rules were “there are no rules.” Wanting to keep the spirit of the Jam, I decided to do my coding during the jam, but allow myself to prepare artwork beforehand. While I did not have to do the same thing with the port, as the time switch was happening on November 1st and because there is talk of getting rid of daylight savings time (had something called Covid-19 happened, it is possible that there wouldn’t be daylight savings time in BC as voters overwhelmingly want to get rid of it as it serves no practical purpose but does pose medical problems to some people) so this may be the last chance I have to do a game in 0 hours. While there are Zero Hour jams running this year, I opted to do my own Zero Hour Port where I take my original Zero Hour game and re-write it in JavaScript so it will be playable since Flash is no more.

My rules for this port were simple. Pre-Jam preparations were allowed which simply consisted of using my old copy of Flash to create a sprite sheet of the assets in the original game and to convert the resulting JSON file from this sprite sheet that was generated into my own condensed format. A sample of my JSON format is shown below. I am also allowing myself to use my Vampire Attack game from last month as skeleton code to quickly hack out a working game.

ZHAtlas = {

    //"ContinueBtn": {"x":0,"y":0,"w":350,"h":82, "over_x":358,"over_y":0,"down_x":0,"down_y":90},
    "KeyABtn" : {"x":0,"y":0,"w":94,"h":84, "over_x":102,"over_y":0,"down_x":102,"down_y":0},
    "KeyDBtn" : {"x":204,"y":0,"w":94,"h":84, "over_x":306,"over_y":0,"down_x":306,"down_y":0},
    "KeyQBtn": {"x":510,"y":0,"w":94,"h":84, "over_x":612,"over_y":0,"down_x":612,"down_y":0},
    "KeySBtn": {"x":714,"y":0,"w":94,"h":84,"over_x":816,"over_y":0,"down_x":0,"down_y":0},
    "KeyWBtn": {"x":918,"y":0,"w":99,"h":84,"over_x":0,"over_y":92,"down_x":0,"down_y":92},
    "KeyEBtn": {"x":214,"y":92,"w":94,"h":84,"over_x":316,"over_y":92,"down_x":316,"down_y":92},
    "continueBtn": {"x":418,"y":92,"w":216,"h":50,"over_x":642,"over_y":92,"down_x":0,"down_y":184},
    "Zombie": {"x":448,"y":184,"w":546,"h":656},
    "backdrop": {"x":0,"y":848,"w":512,"h":256}
}

As you can see by looking at the above JSON code, objects in the games are named and given information about coordinates and size. Buttons also have additional coordinate information for their over and up states. The sprite sheet is too big to put here but is available in the git repository for those of you who wish to view it.

Once the missing hour started, I copy and paste code into a new project. The HTML boilerplate is pretty much unchanged just with some redundant code removed and the name of the game and script changed. The js file linked to from the html file really doesn’t need too much to be copied from Vampire Attack. First I paste in my JSON file and turn it into an object, that is the one thing I do love about JSON. Then I copy the button class and turn my ScreenHandler class into the game class. I am figuring that I can simply have the title screen and win/lose screens built into this one screen, which in hindsight was a bit more work than I expected.

Drawing the backdrop is trivial so for my rendering routine I simply draw the backdrop image. Then, which is not shown in my final code, I want to make sure the buttons are rendering properly so I render all of them using a for loop. The button class uses a callback mechanism so implementing the handler is trivial. For quick testing the handler just displays a console message but game logic will be going here shortly.

With the user interface implemented, it is time for the gameplay. This involves the zombie moving toward the player. Here is where I wish that more time was spent examining the original code for doing this. While writing scaling code is trivial, having the zombie at the center of the screen didn’t look very good as the zombie was floating in the air. The obvious quick fix for this problem is to shift down the y coordinate. This solves the footing problem, but as we are scaling at a constant rate the zombie appears to slow down as it starts reaching the player. Playing a few times it is a bit surreal but sort of like what you would experience as your adrenaline started kicking into overdrive so figured I would leave this alone unless there was time at the end to fix it.

Now clicking on a button adjusts the zombie distance, and when the zombie is far enough away we log a win. If the zombie gets too close we log a loss. The problem is that all the keys will let the player run, making the game too easy. This is easily fixed by picking one of the keys at random and only rendering/accepting that key. This meant that keyboard support had to be added which isn’t hard. The keyboard handler for key down looks at the key being pressed and checks to see the character is the same as the expected character and if so calls the player step method for moving the player. The button handler does likewise so we have both keyboard and mouse/touch suppprt.

    playerStep() {
        this.zscale -= .06;
        this.cur_key = Math.floor(Math.random()* 6);
        if (this.zscale < .1)
            this.nextScreen(); // note this was a console log earlier
    }

At this point I am thinking that I am almost done and will be able to add sound, music, and maybe even fix the zombie motion. First, however, we need title, win, and lose screens. Choices here are to cut an paste the screen handling code from Vampire Attack and have different screens. Or as there are just messages to display I could just do everything within the existing screen. Feeling the later would be faster, I opted to go for that approach. I don’t think it ended up being faster and added some ugly code to my project so was ultimately a poor decision.

To add a title screen, a showTitle flag was added. When set the title text gets shown. A playing flag determines if the game is in progress. If the game is not being played, a separate message (for winning, losing, and extra title text) will be shown. To handle the transition between the different states, a next screen method was written as shown below. This code gets called whenever a screen transition should occur which includes winning, losing, clicking to return to title, and starting the game from the title.

    nextScreen() {
        if (this.playing === true) { // game ended
            this.cur_key = 6;
            this.playing = false;
            if (this.zscale >= 1) {
                this.message = "You have died!";
            } else
                this.message = "You Escaped!!!";
        } else if (this.showTitle === true) {// game starting
            this.cur_key = Math.floor(Math.random()* 6);
            this.zscale = .5;
            this.showTitle = false;
            this.playing = true;
        } else { // return to title
            this.cur_key = 6;
            this.message = "Billy Spelchan's Zero Hour Game port";
            this.showTitle = true;
        }
    }

Once I finally finished the screen transition logic there was few minutes left but I was too tired to continue so the sound effects, which probably could have been added in only a couple of minutes, was dropped and I figured I would go to bed and put up the game when I woke up.  The code for this game is available in the git repository for those who are interested. Not sure what will be next month, but I do have an interesting multi-part series where I create a game then demonstrate different approaches to solving that game. If I have time to do a Christmas game (slim but non-zero) then I will do a postmortem on that game otherwise I will start the new series.