Saturday, August 15, 2020

Making Pent Up Anger Part 5 of 5

 I have finally gotten around to posting the code for this at https://github.com/BillySpelchan/BlazingPorts. This month we are finishing up Pent Up Anger, and next month will hopefully be my attempt at the js13kGame competition which I hope to be able to enter as it is going on for a month. I am hoping to somehow find an hour a day to put into it, so it won't be a great game but I will try to do something good. 

Putting Everything together

Tri-state Buttons

At this point in time we have a complete and playable game but need to alter the code to change which players are humans, which are inactive, and which are computer players. We need a way of selecting which players are which. This means that we are going to need some type of menu system that lets the player choose who controls a particular color.

As every color is going to have one of three choices, and only one of the three choices is valid at a time, it makes sense to create a component that lets the player choose one of three states. As there is no such component built into Animate, this Tri-state button then needs to be created as show in the figure below.


First, we create a movie object the size of the desired object. Then we assign a dynamic text object to the left side of the tri-state button. This is named label\_txt and is going to be used for setting the label. Next we draw the three boxes. We create a fill object to represent the check state of the object. This is converted into a movie named select\_box. Three instances of this movie are used, one for each box. The idea here is that, as we are going to have to control the state anyway, one of the three box movies will be visible at a time.

The symbol for the movie is placed on the screen where it is desired, and a tint is applied to this movie so that each instance is a different color. We then create a managing class which handles the state of the component.

We need a way of actually making this component do it's work. We create an invisible button the size of a box. The over frame will be a visible solid color as will the highlight. Instances of these buttons go over each of the three boxes. Now we are ready to write the code for this component. We start of with the initialization code. When creating the button, the creator provides the movie instance of the button, as well as the label to be assigned to the button, and the type of player to initially assign to the button. Listeners for the three box movies are set up so that we will know when the type of player is being changed. Finally, we call a method designed to update the state of the component called refreshComponent.

spelchan.TriState = function(movie, label, playerType) {
this.movie = movie;
this.movie.label_txt.text = label;
this.current_select = playerType;
this.box1Listener = this.setSelected.bind(this,1);
this.box2Listener = this.setSelected.bind(this,2);
this.box3Listener = this.setSelected.bind(this,3);
this.movie.box1_btn.addEventListener("click", this.box1Listener);
this.movie.box2_btn.addEventListener("click", this.box2Listener);
this.movie.box3_btn.addEventListener("click", this.box3Listener);
this.refreshComponent();
}

The refreshComponent method simply sets the box movies visibility to reflect the currently selected player type. It also has a updateCache() method which is used to force the cache holding the pre-drawn version of the component to be redrawn. This is necessary due to the use of tinting. Because tinting is such a costly operation, the tinted object is cached so that only needs to be drawn once. When an object changes, however, the cache needs to be forced to redraw the image so that it is up to date.

spelchan.TriState.prototype.refreshComponent = function() {
console.log("Should be adjusting box state");
this.movie.box1_movie.visible = (this.current_select == 1);
console.log("box1 = " + this.movie.box1_movie.visible);
this.movie.box2_movie.visible = (this.current_select == 2);
this.movie.box3_movie.visible = (this.current_select == 3);
this.movie.updateCache();
}

Next, we need to be able to select a button (otherwise, how are we going to change the state). Note that this function automatically calls the refreshComponent function to make sure that the changed state is drawn. This is paired with a getSelected function which simply returns the currently selected state (1 for the first button, 2 for the second, and 3 for the third). This is the method that was set up in the initialization and thanks to the flexibility of JavaScript's bind method, we can let the function know exactly which button was clicked. 

spelchan.TriState.prototype.setSelected = function(n) {
console.log("TriState button selection changed to " + n);
this.current_select = n;
this.refreshComponent();
}

Having the ability to select the player type is once thing, but the main program needs a way of finding out which state the tri-state button was in once the game is about to start. We could simply grab the current\_selected parameter, but a more proper way is to have a getter method, which simply returns teh current\_selected parameter.

spelchan.TriState.prototype.getSelected = function() {
return this.current_select;
}

One last bit of housekeeping is to be able to remove the listeners once we are done with the component.

spelchan.TriState.prototype.clearListeners = function() {
this.movie.box1_btn.removeEventListener("click", this.box1Listener);
this.movie.box2_btn.removeEventListener("click", this.box2Listener);
this.movie.box3_btn.removeEventListener("click", this.box3Listener);
}

And we have a completed tri-state button so it is easy to set up which type of player each of the five players are. We still need to put five of these buttons somewhere so the next task is to build a title screen.


Title Menu


Now we can assemble the title screen. First, a simple logo. This is simply a nice cursive font for the “Pent up” text and a harsh, bold font for the “Anger” portion. Certainly, if you have the time you could design a fancy title. I am not an artist, so I will keep things simple.

Next we put together the menu of options and the “Start Game” button. The menu is made up of five of the tri-state buttons that we created in the last section. Each of the tri-state buttons is tinted the appropriate color. They are each named using the following template: label\#\_movie. The number of the player replaces the crosshatch symbol. The start button is given the label “start\_btn.” To make the three states of the tri-state button understandable, the labels “No player,” “Human,” and “Computer” are used. The image below shows the resulting title screen.



While the title screen looks nice, it doesn’t do anything at the moment.  To get the title screen to actually do something, we are going to need to add some code. In the first frame we have the initialization code that sets the default player to human, and the startGame function which is called by the start button when it is selected. The startGame function simply sets the global player\_type variables to the values in the tri-state fuctions. To prevent an infinite loop from occurring, it also makes sure that there is at least one human or computer player.

spelchan.Pent.prototype.initTitle = function(movie) {
this.titleMovie = movie;
this.triStates = [];
this.triStates[0] = new spelchan.TriState(this.titleMovie.label1_movie, "Purple", this.playerTypes[0]);
this.triStates[1] = new spelchan.TriState(this.titleMovie.label2_movie, "Red", this.playerTypes[1]);
this.triStates[2] = new spelchan.TriState(this.titleMovie.label3_movie, "Yellow", this.playerTypes[2]);
this.triStates[3] = new spelchan.TriState(this.titleMovie.label4_movie, "Green", this.playerTypes[3]);
this.triStates[4] = new spelchan.TriState(this.titleMovie.label5_movie, "Blue", this.playerTypes[4]);
this.startListener = this.startGame.bind(this);
this.titleMovie.start_btn.addEventListener("click", this.startListener);
this.titleMovie.stop();
}

spelchan.Pent.prototype.startGame = function(e) {
var numPlayers = 0;
for (var cntr = 0; cntr < 5; ++cntr) {
this.playerTypes[cntr] = this.triStates[cntr].getSelected();
if (this.playerTypes[cntr] > 1)
++numPlayers;
this.triStates[cntr].clearListeners();
}
if (numPlayers > 1) {
this.titleMovie.start_btn.removeEventListener("click", this.startListener);
this.stage.gotoAndStop("Game");
}
}

Final Touches


The Pent class updateGameUI now needs to be updated to handle the different types of players. In particular, we need to know if there really is a player which can be done by taking a look at the player type that was assigned to the player as a result of the tristate buttons. One of the options in the tri-state menu’s is “No player”. This is to allow a small number of players play against each other without having any computer opponents. This code should be added to the UI\_ROLL case:

if (this.playerTypes[player] > 2)
this.startRoll();
else if (this.playerTypes[player] < 2)
this.skip();


While I covered the skip button, originally I did not have this feature. It was after playing through the game I noticed that it would be nice to be able to skip a turn.  This is only a tiny bit of the fine tuning for the game. 

There is one more thing that should have been added to the game, but for some reason I never did implement before releasing. That is sound effects. This would be similar to the way it was done for the Video Poker game.

That is it for this game, next month I hope to have a post mortem of mj js13kGame entry (if I manage to finish one) and if I do finish, will spend a few months going over the various parts of the game. If I am lucky enough to be able to use some of my research in the game, I will go over the related research papers and how they aided me in this game.