Saturday, May 18, 2019

Enter the Nasty

To add a bit more pressure on the player, I have a villain that pops up after the player has stayed in the room too long. Being a programmer, the first villain that came to mind is the dreaded Blue Screen of Death that occurs on Windows machines. Linux and Macintosh OS X don't have this problem (and are extremely stable operating systems) but most people have windows, and a lot of my programming happens to be for Windows machines. To be fair to Microsoft, the blue-screen problem has largely gone away.



In addition to the BSoD image, we also need a movie that controls the BSoD. This movie consists of nothing for the first few frames (labeled hide) with a stop on the second frame. There is also be a block labeled show which is a two second sequence of the BSoD appearing. For control purposes we have the button code in the previous section call the hide method which shows nothing. There is a flag that is set indicating that there is no BSoD yet. A timer is set up to 0 and when this timer reaches 3 the BSoD will appear. What are we timing? We already have a loop for growing and shrinking the room so we will use the end of that loop as the timer. So instead of having a gotoAndPlay on the last frame to loop the animation, we instead have nightmare.updateBSOD("blueLoop"); with the string being the name of the label to go to for looping the room animation. The BSOD update code is as follows:

spelchan.Nightmare.prototype.updateBSOD = function(loop) {
// BSOD calculations
if (this.bsodAppearing) {
this.stage.gotoAndPlay("loseGame");
return;
}
++this.bsodTimer;
if (this.bsodTimer >= 3) {
this.bsodAppearing = true;
this.stage.bsod_movie.gotoAndPlay("show");
}
this.stage.gotoAndPlay(loop);
}

The function simply keeps track of how many times it has been called. As the function is called every 2 seconds, we simply figure out how long we give the players before the BSoD appears and then start the appearing animation. If another tick happens after the appearing animation has occurred then we know that the player has bit the bullet. This simply goes to the loseGame frame which we use for losing the game. Which leaves us with the task of handing the winning and losing of the game.

Saturday, May 4, 2019

Linking the Rooms

Now comes the task of assembling and linking the rooms. I create a block of frames for each of the six rooms with each room being broken into three animated sequences. First is the Enter sequence (labeled enterColor, with Color being the color of the room). This sequence shows the room zooming into view. Next is the main room loop (labeled colorLoop, with color being the color of the room). I want to have an additional disorienting effect added to the room. Therefore, I set this block of frames to loop. The room will slowly grow and then shrink back to it's starting size. Finally there is an exit sequence (labeled colorExit, with color being the color of the room). This shows the room shrinking into nothing.

As animate likes to tie code to the frame it is written in, we are creating a globally accessible class that we will be using for tracking the state of the game. This class will be added to throughout this chapter but to start with we have the following initialization code.

if (typeof(spelchan) == "undefined") spelchan = {};

spelchan.Nightmare = function() {
this.registerStage = function(stage) { this.stage = stage;}
this.dirButtons = [null,null,null,null];
this.dirClickHandler = this.directionClicked.bind(this);
this.exitTarget = "exitRed";
}

This sets up a spelchan.Nightmare class that holds the list of buttons that are used to control the navigation between rooms. We need buttons for the four directions that the player can go. Quite simply, I will label the directions North, South, East and West. The four buttons will be invisible buttons. These are buttons that have a hit box but no image. Actually, when the player is over the buttons, we will have a "Go Direction" message appear. This is done simply by having the over and down frames of the button have the desired text in them. In the editor the invisible buttons have a cyan color and are placed over the doors in the image. Due to the animation of the room this placement isn't exact.



Every room will have it's own set of four buttons. I use the convention of naming the button instances colorDirection_btn. As the logic for the buttons is similar for all the rooms we can create a general method for setting up the buttons for a room as follows:

spelchan.Nightmare.prototype.setDirectionTargets = function(
btnNorth, targetNorth, btnEast, targetEast,
btnSouth, targetSouth, btnWest, targetWest, exitTarget) {
this.dirButtons[0] = btnNorth;
btnNorth.directionTarget = targetNorth;
this.dirButtons[1] = btnEast;
btnEast.directionTarget = targetEast;
this.dirButtons[2] = btnSouth;
btnSouth.directionTarget = targetSouth;
this.dirButtons[3] = btnWest;
btnWest.directionTarget = targetWest;
this.exitTarget = exitTarget;

for (var cntr = 0; cntr < 4; ++cntr) {
this.dirButtons[cntr].addEventListener(
"click", this.dirClickHandler);
}

this.bsodTimer = 0;
this.bsodAppearing = false;
this.stage.bsod_movie.gotoAndPlay("hide");
}

This code simply sets up the buttons and gives each button a target frame to go to when it is clicked. It also provides the frame to goto to start the exit room animation. The buttons are then assigned an event listener to handle being clicked. We will be covering this handler later in this section. Finally the code sets up the timer for the villain. We will cover the appearance of the villain in the next section. Each of the six rooms needs to call the above method when it is appearing with the code being on the frame where the room starts appearing. This code is something like the following:

nightmare.setDirectionTargets(
this.redNorth_btn, "enterCyan",
this.redEast_btn, "enterGreen",
this.redSouth_btn, "enterCyan",
this.redWest_btn, "enterYellow", "exitRed");

As you can see this is simply a function call to the method we created above. The parameters would be the appropriate buttons for that room and the labels of the frame the program should go to when the button is clicked. The button variables are self-evident while the target frames require looking at the map to determine the appropriate room to go to.

Handling the click is the next thing we need to do. This is done by the event handler we hinted at above.

spelchan.Nightmare.prototype.directionClicked = function(e) {
// make sure button has valid target
if (typeof(e.target.directionTarget) == "undefined") {
console.log("ERROR - Missing target in button");
this.directionTarget = "enterRed";
} else {
console.log("Button target is " + e.target.directionTarget); 
this.directionTarget = e.target.directionTarget;
}

// clean up buttons
for (var cntr = 0; cntr < 4; ++cntr) {
this.dirButtons[cntr].removeEventListener("click", this.dirClickHandler);
}
this.stage.gotoAndPlay(this.exitTarget);
}

This function first sets up a class variable called directionTarget to be the name of the frame to go to once the room has been exited. We can't go to this frame right away because we have to play an exit animation first. To be good citizens, we need to clean up our event handlers so we remove the event listeners. Finally we start the animation for exiting the room.

To finish our navigation system we need to go to the appropriate room when the player is exiting the room. Each of the exit animations will have a call to nightmare.nextRoom() on the last frame. This is a simple method that simply goes to the frame indicated by the button that was clicked on above.

spelchan.Nightmare.prototype.nextRoom = function() {
this.stage.gotoAndPlay(this.directionTarget);
}

This code simply goes to the appropriate frame for the next room. And that is all that is required for a navigation system. Now we need to implement the villain of this game which we will do next fortnight..