THE FINAL PRODUCT
The link the code on the web editor can be found here here. I have also embedded the sketch below, although the game must be viewed in full screen on Chrome, with the Bookmarks tab hidden. I made this choice to have the canvas size this large so that the user could be fully immersed in the game. Since this isn’t one of those games that’s meant to be played to pass the time, I didn’t want a small canvas size and other tabs to distract from the experience. Of course, headphones with decent sound quality also enhance the experience.
CHANGES & SIMILARITIES FROM THE STORYBOARD
Overall, the final product is very similar to the storyboard created in last weeks post, although some of the games have been modified. A theme that I wanted to establish from the start was an 80’s arcade aesthetic. The aesthetic is very nostalgic of the gameboy and nintendo games I used to play as a child, and because the game is sort of reflective of my life as an adoptee up until now, I think it is fitting. I wanted there to be lots of pixelated images, saturated colors, and sounds that are reminiscent of old computers. In terms of the story I was telling, I wanted the text to be informative and genuine so as to represent my experiences as authentically as possible, but still very personal and quirky. I think I accomplished this quite well.
In terms of the actual games, I did make some changes in the final product. For the first chapter, I felt that the “lost treasure” analogy (explained on the mind map) was difficult to capture and more complex than I anticipated. Instead I decided to make a maze. In the second chapter, I still wanted to express the idea of mixing culture, but due to time constraints, I simplified the game that was intended to be a chasing game, where the blue monster is controlled by the user and the red controlled by the computer. Unfortunately, I was unable to make the red monster move on its own, so for now, it remains stationary while the user is able to move the blue monster freely. Finally, for the third chapter, I felt that the original game was too similar to the previous chapter. I began to think about the most important thing to represent, which was the idea of presenting differently to please others. Hence, I decided to make a dress up game where the user can dress up a chameleon with different accessories. The last chapter remained the same.
Although I had to simplify my original storyboard to fit with the time constraints of the project, I’m glad that I had to. It made me think about the power of simple but effective analogy, and challenged me to think of new ways I could show an aspect of my experience, rather than tell the user directly. I think with game design, it’s sometimes easy to forget that the user indeed can put pieces together themselves without the game having to explicitly show every part of the plot and meaning.
Finally, when it came to writing the text, I decided to divide the game by “chapters” rather than levels. Though subtle, I think this choice of diction makes a significant difference. Similarly, I avoid using language such as “you lost” or “you won,” as I think it breaks up the story and doesn’t allow for a smooth transition between one chapter and the next.
ESSENTIAL CODE
Although the game has far too many lines to go into detail in this post, I will share some pieces of the code that I found essential to this entire process. For one, two classes that were reused many times were the Button and Sign class. The Button class allowed me to create buttons that played the next slide of text, switched to the next chapter (changing the game state in the process), replaying games, and more. The Sign class is what I used to place all of my text on screen. Because there were a lot of specifics involving margins, font color, and positioning, having a class to hold this information was helpful. The code for the two classes is shown below:
class Button{
constructor(x, y, font_color,font_size, string, btn_w, btn_h){
this.x = x;
this.y = y;
this.string = string;
this.age = frameCount;
this.opacity = 255;
this.hover = false;
this.width = btn_w;
this.height = btn_h;
this.font_color = font_color;
this.font_size = font_size;
}
display() {
if (mouseX < this.x+this.width/2 &&
mouseX > this.x - this.width/2 &&
mouseY > this.y-this.height/2 &&
mouseY < this.y+this.height/2){
this.hover = true;
}
else {
this.hover = false;
}
if (this.hover) {
this.opacity = 100;
}
else {
this.opacity = 255;
}
//FILL OF BUTTON
//next buttons with gray center
if (game_state!=0 && game_state != 5 && game_state!=6 && game_state!=16 && game_state!=11 && game_state !=1 && game_state!=20){
fill(180);
}
else {
noFill();
}
//STROKE OF BUTTON
if (game_state == 1 || game_state == 5 ||game_state == 0 || game_state == 20) {
this.font_color = color(255, 255, 255);
}
else {
this.font_color = color(0,0,0);
}
push();
strokeWeight(2);
stroke(red(this.font_color),green(this.font_color), blue(this.font_color), this.opacity);
rect(this.x, this.y, this.width, this.height);
pop();
//TEXT OF BUTTON
noStroke();
if (game_state == 1|| game_state == 5 || game_state == 0 || game_state == 20){
this.font_color = color(255, 255, 255);
fill(255, 255, 255, this.opacity);
}
else {
this.font_color = color(0,0,0);
}
textAlign(CENTER);
textSize(this.font_size);
fill(red(this.font_color),green(this.font_color), blue(this.font_color), this.opacity);
text(this.string, this.x, this.y, this.width, this.height);
}
mouse_over() {
if ((mouseX >=(this.x - this.width/2) && mouseX <=this.x+this.width/2) && (mouseY >= (this.y-this.height/2) && mouseY<=(this.y+this.height/2))) {
return true;
}
}
}
In the Button class, it has a variable named this.font_color, which changes depending on the current game state, so that it draws in black or white depending on the background. It also has a method called mouse_over(), which returns true if the mouse is inside the button. If true, a variable called this.opacity_changes, allowing the button to fade on hover.
class Sign{
constructor(x, y, font_color, font_size, string, sign_w, sign_h) {
this.x = x;
this.y = y;
this.string = string;
this.age = frameCount;
this.speed = 20;
this.font_size = 0;
this.width = sign_w;
this.height = sign_h;
this.font_color = font_color;
this.font_size = font_size;
}
display(){
push();
rectMode(CENTER);
textFont('VT323');
textAlign(CENTER);
textSize(this.font_size);
noStroke();
fill(this.font_color);
text(this.string, this.x, this.y, this.width, this.height);
pop();
}
}
The Sign class is very similar to the Button class, containing all the same attributes, although the way the text animates is defined outside the class in the type() function.
The type() function was the most reused function of the entire program, and it really brought the entire game to life. Given that most of it is text based, adding a typewriting effect made it more visually interesting and immersive, forcing the user to slow down their reading speed to match the speed at which the text was appearing on screen. The code is shown below:
function type(current, string) {
if (current==0) {
start_typing();
}
if (current_char>= string.length-1){
stop_typing();
}
let current_str = string.substring(0, current);
textSize(30);
text(current_str, windowWidth/2, windowHeight/2, windowHeight-200-margin, windowHeight/3-margin);
current_char +=random(0.1, 0.6);
Essentially, the function takes a string as its input and prints a substring of the string that increases with each successive frame, giving the illusion of typing. The substring starts with length 0 and ends at length string.length, incremented by the current_char variable. The curent_char variable is incremented in random values to give the appearance of natural typing.
CHALLENGES
The most challenging part for me was understanding the concept of game states as a way to organize my code. In the beginning, I was writing the code for each game in separate files, and thought that keeping separate functions would be enough to organize the code. However, I experienced a lot of difficulty trying combine multiple sketches. After creating the global variable game_state, which was a numerical value that kept track of the current game_state, it was much easier to organize the code and have the program transition from one scene to another. For example, the draw() function simply consists of several if statements that say “when the game state is __ number, go to __ function”, where each function corresponded to a certain “scene” in the game, such as the winning screen to chapter 1, or the instruction screen for chapter 3. Also, the game_state could be changed almost only with the mouseClicked() function. Inside the mouseClicked() function, it deals with every button that is used in the program, and depending on what type of button is clicked, it increments or decrements the game state.
BORROWED CODE
The only outside sources that were used in making this game was the algorithm used to make the maze, and the typing function. Of course, I adapted each of them slightly to fit my game. For example, the maze was built using a depth first recursive program made by The Coding Train, though it only generated the pattern and did not allow the user to actually move through the maze. The code that was used to allow the user to actually play the maze was completed on my own. Secondly, the original typing function that I found only worked with single strings, and I adapted this to fit with a list of strings, as well as display a new message with the click of a button.
The link to the maze algorithm can be found below: https://editor.p5js.org/codingtrain/sketches/EBkm4txSA
The link to the typing effect can be found below:
https://editor.p5js.org/cfoss/sketches/SJggPXhcQ
IMPROVEMENTS FOR THE FUTURE
Of course, I would love to finish the second chapter so that the game is complete. I would also like to refine the code more. I recognize that as the process went on, I became lazy and hardcoded much of it. Editing it by adding some intermediary variables, making variable names more clear, and even reducing the amount of Button and Sign instances would make the code not only shorter, but more organized. Additionally, as brought up by my professor, using Javascript objects would be incredibly useful for this project. For example, I use two arrays: invader_keys and alien_keys, which are both arrays of 4 elements that store boolean values, each corresponding to an arrow key. Each arrow key is represented by the indexes of 0, 1, 2 and 3, which is very unclear and confusing to someone who doesn’t know the code.