Concept
My midterm project is an escape room game where the players must follow a series of clues to find different objects around the room. The game begins with a hint that directs the player to the first object. An once it is found, the object reveals a number that the player must remember, as it is part of the final password. The object also provides the next clue, leading the player to the next item in the sequence. This process continues until all objects have been discovered, all of them giving a number needed for the final passcode. To ensure the correct sequence, my game has an ordered clicking type of logic, this means the players can only interact with objects in a specific order. If they attempt to click on an object out of sequence, it will not respond, preventing them from skipping ahead or guessing the passcode incorrectly. This makes sure the players follow the clues and remember the numbers in the right order, so that they can successfully input the password at the end to escape.
link to sketch: https://editor.p5js.org/tfr9406/full/1UNobzqQo
Code Highlights
I think a very important part of my game’s code is the ordered clicking system, which makes sure players find clues in the right order, and prevents them from skipping ahead . To do this I made it so that the code tracks the order of the interactions using clickOrder and marks visited clues in the visitedClues object. This means, each clue can only be accessed if the previous one has been clicked. For example, the clock must be clicked first (clickOrder === 0) before moving to clue1, then the computer unlocks clue2, and so on until the final clue, the painting, leads to the password page.
I also made it so that the players can revisit clue while keeping the correct order. This is important because it allows players to go back and see the clue again without breaking the structured order. The visitedClues object keeps track of which clues have already been discovered, making sure that once a clue is unlocked, it remains accessible even if the player navigates away and returns. For example, once the player clicks on the clock, visitedClues.clue1 is set to true, meaning they can go back to it at any time. However, they can’t jump ahead to later clues unless they follow the intended order. This is the code:
if (currentPage === "game") {
// checks for valid order before allowing to open next clue page
if (clickOrder === 0 && clock.isClicked(mouseX, mouseY)) {
clickOrder = 1; // clock clicked first
visitedClues.clue1 = true; // mark clue1 as visited
} else if (clickOrder === 1 && computer.isClicked(mouseX, mouseY)) {
clickOrder = 2; // computer clicked second
visitedClues.clue2 = true; // mark clue2 as visited
} else if (clickOrder === 2 && cupboard.isClicked(mouseX, mouseY)) {
clickOrder = 3; // cupboard clicked third
visitedClues.clue3 = true; // mark clue3 as visited
} else if (clickOrder === 3 && books.isClicked(mouseX, mouseY)) {
clickOrder = 4; // books clicked fourth
visitedClues.clue4 = true; // mark clue4 as visited
} else if (clickOrder === 4 && painting.isClicked(mouseX, mouseY)) {
currentPage = "password"; // move to password page after painting
if (currentPage === "game") {
// checks for valid order before allowing to open next clue page
if (clickOrder === 0 && clock.isClicked(mouseX, mouseY)) {
currentPage = "clue1";
clickOrder = 1; // clock clicked first
visitedClues.clue1 = true; // mark clue1 as visited
} else if (clickOrder === 1 && computer.isClicked(mouseX, mouseY)) {
currentPage = "clue2";
clickOrder = 2; // computer clicked second
visitedClues.clue2 = true; // mark clue2 as visited
} else if (clickOrder === 2 && cupboard.isClicked(mouseX, mouseY)) {
currentPage = "clue3";
clickOrder = 3; // cupboard clicked third
visitedClues.clue3 = true; // mark clue3 as visited
} else if (clickOrder === 3 && books.isClicked(mouseX, mouseY)) {
currentPage = "clue4";
clickOrder = 4; // books clicked fourth
visitedClues.clue4 = true; // mark clue4 as visited
} else if (clickOrder === 4 && painting.isClicked(mouseX, mouseY)) {
currentPage = "password"; // move to password page after painting
}
if (currentPage === "game") {
// checks for valid order before allowing to open next clue page
if (clickOrder === 0 && clock.isClicked(mouseX, mouseY)) {
currentPage = "clue1";
clickOrder = 1; // clock clicked first
visitedClues.clue1 = true; // mark clue1 as visited
} else if (clickOrder === 1 && computer.isClicked(mouseX, mouseY)) {
currentPage = "clue2";
clickOrder = 2; // computer clicked second
visitedClues.clue2 = true; // mark clue2 as visited
} else if (clickOrder === 2 && cupboard.isClicked(mouseX, mouseY)) {
currentPage = "clue3";
clickOrder = 3; // cupboard clicked third
visitedClues.clue3 = true; // mark clue3 as visited
} else if (clickOrder === 3 && books.isClicked(mouseX, mouseY)) {
currentPage = "clue4";
clickOrder = 4; // books clicked fourth
visitedClues.clue4 = true; // mark clue4 as visited
} else if (clickOrder === 4 && painting.isClicked(mouseX, mouseY)) {
currentPage = "password"; // move to password page after painting
}
To get to this final code, I first tested it out with a simpler object and basic logic to make sure the ordered clicking system worked correctly. Initially, I used a minimal setup with just 3 clickable elements and basic variables to track whether an item had been clicked. This helped me confirm that the logic for the sequential interactions was working before expanding it to include the full set of clues and the ability to revisit them. Below was the initial code:
function mousePressed() {
if (!rectClicked && mouseX > 50 && mouseX < 130 && mouseY > 100 && mouseY < 150) { //first rectangle is clicked
} else if (rectClicked && !triClicked && mouseX > 170 && mouseX < 230 && mouseY > 100 && mouseY < 150) { //triangle clicked true if rectangle clicked first
} else if (rectClicked && triClicked && !circClicked && dist(mouseX, mouseY, 320, 125) < 25) {//circle clicked true if rectangle and triangle clicked before
escape = true; //clicking circle = players escapes
function mousePressed() {
if (!rectClicked && mouseX > 50 && mouseX < 130 && mouseY > 100 && mouseY < 150) { //first rectangle is clicked
rectClicked = true;
} else if (rectClicked && !triClicked && mouseX > 170 && mouseX < 230 && mouseY > 100 && mouseY < 150) { //triangle clicked true if rectangle clicked first
triClicked = true;
} else if (rectClicked && triClicked && !circClicked && dist(mouseX, mouseY, 320, 125) < 25) {//circle clicked true if rectangle and triangle clicked before
circClicked = true;
escape = true; //clicking circle = players escapes
}
}
function mousePressed() {
if (!rectClicked && mouseX > 50 && mouseX < 130 && mouseY > 100 && mouseY < 150) { //first rectangle is clicked
rectClicked = true;
} else if (rectClicked && !triClicked && mouseX > 170 && mouseX < 230 && mouseY > 100 && mouseY < 150) { //triangle clicked true if rectangle clicked first
triClicked = true;
} else if (rectClicked && triClicked && !circClicked && dist(mouseX, mouseY, 320, 125) < 25) {//circle clicked true if rectangle and triangle clicked before
circClicked = true;
escape = true; //clicking circle = players escapes
}
}
Challenges
For my game I knew I wanted to implement hover animation to improve overall user experience by providing feedback. However, this was tricky at first because my game page was based on images rather than shapes. Unlike with shapes, where I could easily change the fill color on hover, I had to find a way to replace the whole image itself to give that same visual feedback. To solve this, I created an if-else condition that checks the mouse’s position relative to the designated area for hover. I then updated the image only if the mouse is hovering within the defined boundaries of the clickable area, and also made sure that when the hover condition is not met, the image reverts to its original state, which prevented it from being stuck in the wrong image.
function handlePageHoverEffects() {
if (currentPage === "landing") {
// hover for Landing image (switches to landing2 on hover)
if (mouseX >= 346 && mouseX <= 468 && mouseY >= 337 && mouseY <= 403) {
currentImage = landing2; // switch to landing2 on hover
currentImage = landing1; // switch back to landing1 otherwise
// hover effect
function handlePageHoverEffects() {
if (currentPage === "landing") {
// hover for Landing image (switches to landing2 on hover)
if (mouseX >= 346 && mouseX <= 468 && mouseY >= 337 && mouseY <= 403) {
currentImage = landing2; // switch to landing2 on hover
} else {
currentImage = landing1; // switch back to landing1 otherwise
}
// hover effect
function handlePageHoverEffects() {
if (currentPage === "landing") {
// hover for Landing image (switches to landing2 on hover)
if (mouseX >= 346 && mouseX <= 468 && mouseY >= 337 && mouseY <= 403) {
currentImage = landing2; // switch to landing2 on hover
} else {
currentImage = landing1; // switch back to landing1 otherwise
}
Improvement
Some of the improvements I could make to the game could maybe include adding different rooms or clues, which would provide more variety and depth to the game. Additionally, introducing difficulty levels would also make the game more accessible to a wider audience. For example, a beginner level with simple clues , and then progressively harder levels with more difficult riddles, hidden objects, and tougher challenges.