clean up code + documentation

This commit is contained in:
adeliptr 2025-05-10 15:10:42 +09:00
parent 05d1136461
commit 2ca032f930
16 changed files with 465 additions and 240 deletions

BIN
.DS_Store vendored

Binary file not shown.

60
Controller.js Normal file
View File

@ -0,0 +1,60 @@
import { showWinningScreen } from './level/WinLose.js';
import { level1Mice } from './level/Level1.js';
const cheeseCount = document.getElementById('cheeseCount');
const gameProgress = document.getElementById('gameProgress');
const catCosts = {
chefCat: 50,
singleYarnCat: 100,
doubleYarnCat: 200,
sleepyCat: 150,
iceCat: 150
};
let miceKilled = 0;
/**
* Updates the player's cheese count by n
*
* @param { number } n - The amount of cheese to add (can be negative)
*/
export function updateCheeseCount(n) {
let currCheese = parseInt(cheeseCount.textContent);
currCheese += n;
cheeseCount.textContent = currCheese;
}
/**
* Enables or disables cat selection buttons based on the current cheese count
* Buttons will be disabled if the player cannot afford the corresponding cat
*/
export function updateCatButtons() {
document.querySelectorAll('.catButton').forEach(button => {
const catType = button.id;
const cost = catCosts[catType];
if (parseInt(cheeseCount.textContent) < cost) {
button.disabled = true;
button.style.cursor = 'not-allowed';
button.style.opacity = '0.5';
}
else {
button.disabled = false;
button.style.opacity = '1';
button.style.cursor = 'pointer';
}
})
}
/**
* Updates the game progress bar based on the number of mice killed
* If all mice are killed, the win screen is triggered
*/
export function updateGameProgress() {
miceKilled++;
const percentage = Math.floor((miceKilled / level1Mice.length) * 100);
gameProgress.value = percentage;
if (percentage >= 100) {
showWinningScreen();
}
}

View File

@ -1,89 +1,36 @@
import { prototypeFrame, gameFrame } from './constants/Prototype.js'; import { prototypeFrame, gameFrame } from './constants/Prototype.js';
import { Colors } from './constants/Colors.js'; import { Colors } from './constants/Colors.js';
import { imageAssets, selectedCatType, resetCatType } from './sketch.js'; import { imageAssets, selectedCatType, resetCatType } from './sketch.js';
import { createCat, SleepyCat, sleepyCats, throwables } from './classes/Cat.js'; import { createCat, SleepyCat, throwables } from './classes/Cat.js';
import { createMouse } from './classes/Mouse.js'; import { spawnMouse } from './classes/Mouse.js';
import { RobotVacuum } from './classes/RobotVacuum.js'; import { drawRobotVacuums } from './classes/RobotVacuum.js';
import { level1Mice } from './level/Level1.js'; import { level1Mice } from './level/Level1.js';
import { showWinningScreen, showLosingScreen } from './level/WinLose.js'; import { showLosingScreen } from './level/WinLose.js';
import { updateCatButtons, updateCheeseCount } from './Controller.js';
import { calculateCell, isCellValid } from './Helper.js';
const gameParent = document.getElementById('gameFrame'); const gameParent = document.getElementById('gameFrame');
const upperContainer = document.getElementById('upperContainer'); const upperContainer = document.getElementById('upperContainer');
const controlPanel = document.getElementById('controlPanel'); const controlPanel = document.getElementById('controlPanel');
const cheeseCount = document.getElementById('cheeseCount'); const cheeseCount = document.getElementById('cheeseCount');
const gameProgress = document.getElementById('gameProgress'); const menuButton = document.getElementById('menuButton');
export const activeCats = [];
export const activeMice = Array.from({ length: 5 }, () => []); export let activeCats, activeMice, robotVacuums, cheeses, grid, levelMice;
const robotVacuums = [];
let leftBar, rightBar, cheeseFeast;
export let gameSprites = []; export let gameSprites = [];
export let cheeses = []; export let catGroup, mouseGroup, throwableGroup;
export let grid = Array(5).fill().map(() => Array(9).fill(null)); let leftBar, rightBar, cheeseFeast;
let startTime; let startTime;
let levelMice = [...level1Mice];
export let miceKilled = 0;
export let catGroup, mouseGroup, throwableGroup, cheeseGroup;
export function calculateCell(mouseX, mouseY) {
let col = floor((mouseX - gameFrame.padding_left) / gameFrame.tileWidth)
let row = floor((mouseY - gameFrame.padding_up) / gameFrame.tileHeight)
return {row, col};
}
function isCellValid(row, col) {
if (row < 0) return false;
if (row >= gameFrame.rows) return false;
if (col < 0) return false;
if (col >= gameFrame.cols) return false;
return true;
}
export function GameScene() { export function GameScene() {
this.enter = function() { this.enter = function() {
select('#upperContainer').show();
select('#endingOverlay').hide(); select('#endingOverlay').hide();
select('#menuButton').show();
select('#startButton').hide(); select('#startButton').hide();
upperContainer.style.display = 'flex';
menuButton.style.display = 'flex';
upperContainer.style.width = width + 'px'; resetGame();
const gridHeight = gameFrame.rows * gameFrame.tileHeight; drawSideBars();
upperContainer.style.height = (gameFrame.height - gridHeight - gameFrame.border) + 'px'; drawRobotVacuums();
controlPanel.style.margin = gameFrame.border + 'px';
controlPanel.style.height = (gameFrame.height - gridHeight - 3 * gameFrame.border) + 'px';
gameSprites = []; // kayanya ga butuh, sama kayak allSprites
leftBar = createSprite(gameFrame.border / 2, gameFrame.padding_up + gameFrame.tileHeight * 2.5, gameFrame.border, gameFrame.tileHeight * 5);
leftBar.color = Colors.dark_brown;
leftBar.layer = 10;
leftBar.overlaps(allSprites);
gameSprites.push(leftBar);
rightBar = createSprite(width - gameFrame.border / 2, gameFrame.padding_up + gameFrame.tileHeight * 2.5, gameFrame.border, gameFrame.tileHeight * 5);
rightBar.color = Colors.dark_brown;
rightBar.layer = 10;
rightBar.overlaps(allSprites);
gameSprites.push(rightBar);
cheeseFeast = createSprite(gameFrame.tileWidth / 4, gameFrame.padding_up + gameFrame.tileHeight * 2.5, gameFrame.tileWidth / 2, gameFrame.tileHeight * 5);
cheeseFeast.opacity = 0;
cheeseFeast.overlaps(mouseGroup);
gameSprites.push(cheeseFeast)
for (let row = 0; row < gameFrame.rows; row ++) {
let x = gameFrame.paddingRobot + gameFrame.robotSize / 2;
let y = gameFrame.padding_up + row * gameFrame.tileHeight + gameFrame.tileHeight / 2;
let vacuum = new RobotVacuum(x, y, row);
gameSprites.push(vacuum.sprite);
robotVacuums.push(vacuum);
}
startTime = millis() / 1000;
cheeseCount.textContent = 50;
} }
this.setup = function() { this.setup = function() {
@ -100,20 +47,16 @@ export function GameScene() {
gameFrame.catRatio = 1.2 * gameFrame.tileWidth/200; gameFrame.catRatio = 1.2 * gameFrame.tileWidth/200;
catGroup = new Group(); resizeFrame();
mouseGroup = new Group();
throwableGroup = new Group();
cheeseGroup = new Group();
} }
this.draw = function() { this.draw = function() {
clear(); clear();
image(imageAssets.gameBackground, 0, gameFrame.padding_up - gameFrame.border, gameFrame.width, gameFrame.height - gameFrame.padding_up + gameFrame.border); image(imageAssets.gameBackground, 0, gameFrame.padding_up - gameFrame.border, gameFrame.width, gameFrame.height - gameFrame.padding_up + gameFrame.border);
noFill(); noFill();
stroke(Colors.dark_brown); stroke(Colors.med_brown);
strokeWeight(gameFrame.border); strokeWeight(gameFrame.border);
// fix the border radius --> create a ratio for it rect(gameFrame.border / 2, gameFrame.border / 2, width - gameFrame.border, height - gameFrame.border, 0.025 * width);
rect(gameFrame.border / 2, gameFrame.border / 2, width - gameFrame.border, height - gameFrame.border, 35);
updateCatButtons(); updateCatButtons();
drawGrid(); drawGrid();
@ -136,17 +79,13 @@ export function GameScene() {
showLosingScreen(); showLosingScreen();
} }
sleepyCats.forEach((cat) => { activeCats.forEach((cat) => {
if (cat.sprite.overlaps(currMouse.sprite)) { if (cat instanceof SleepyCat && cat.sprite.overlaps(currMouse.sprite)) {
cat.awake = true; cat.awake = true;
cat.action(currMouse); cat.action(currMouse);
} }
}) else if (cat.sprite.overlaps(currMouse.sprite)) {
activeCats.forEach((cat) => {
if (!(cat instanceof SleepyCat) && cat.sprite.overlaps(currMouse.sprite)) {
currMouse.targetCat = cat; currMouse.targetCat = cat;
console.log(`seting targetCat to ${currMouse.targetCat}`);
} }
}) })
@ -167,10 +106,8 @@ export function GameScene() {
} }
this.exit = function() { this.exit = function() {
console.log(`i exit gameScene`);
console.log(allSprites);
gameSprites.forEach((sprite) => sprite.remove()); gameSprites.forEach((sprite) => sprite.remove());
activeCats.forEach((cat) => cat.remove()); // idk if it is needed or not activeCats.forEach((cat) => cat.remove());
} }
this.mousePressed = function() { this.mousePressed = function() {
@ -185,6 +122,7 @@ export function GameScene() {
activeCats.splice(index, 1); activeCats.splice(index, 1);
} }
grid[row][col] = null; grid[row][col] = null;
resetCatType();
} }
} }
@ -203,15 +141,13 @@ export function GameScene() {
} }
for (let i = 0; i < cheeses.length; i++) { for (let i = 0; i < cheeses.length; i++) {
console.log(`there are ${cheeses.length} cheeses`) // Calculate boundaries of the cheese
// Calculate boundaries
let left = cheeses[i].x - cheeses[i].width / 2; let left = cheeses[i].x - cheeses[i].width / 2;
let right = cheeses[i].x + cheeses[i].width / 2; let right = cheeses[i].x + cheeses[i].width / 2;
let top = cheeses[i].y - cheeses[i].height / 2; let top = cheeses[i].y - cheeses[i].height / 2;
let bottom = cheeses[i].y + cheeses[i].height / 2; let bottom = cheeses[i].y + cheeses[i].height / 2;
if (mouseX >= left && mouseX <= right && mouseY >= top && mouseY <= bottom) { if (mouseX >= left && mouseX <= right && mouseY >= top && mouseY <= bottom) {
console.log(`cheese ${i} is pressed`)
updateCheeseCount(25); updateCheeseCount(25);
cheeses[i].remove(); cheeses[i].remove();
cheeses.splice(i, 1); cheeses.splice(i, 1);
@ -220,84 +156,93 @@ export function GameScene() {
} }
} }
}
function drawGrid() { /**
for (let row = 0; row < gameFrame.rows; row++) { * Resizes and styles UI containers and game canvas based on screen width
for (let col = 0; col < gameFrame.cols; col++) { */
let x = gameFrame.padding_left + col * gameFrame.tileWidth; function resizeFrame() {
let y = gameFrame.padding_up + row * gameFrame.tileHeight; gameParent.style.borderRadius = (0.03125 * width) + 'px';
canvas.style.borderRadius = (0.03125 * width) + 'px';
let isHovering = ( const gridHeight = gameFrame.rows * gameFrame.tileHeight;
mouseX > x && mouseX < x + gameFrame.tileWidth && upperContainer.style.width = width + 'px';
mouseY > y && mouseY < y + gameFrame.tileHeight upperContainer.style.height = (gameFrame.height - gridHeight - gameFrame.border) + 'px';
); upperContainer.style.borderRadius = (0.03125 * width) + 'px' + (0.03125 * width) + 'px 0 0';
if (isHovering && selectedCatType && selectedCatType === 'petCage' && grid[row][col] != null) fill('red');
else if (isHovering && selectedCatType && selectedCatType != 'petCage' && grid[row][col] == null) fill('red');
else fill((row + col) % 2 === 0 ? Colors.dark_yellow : Colors.light_yellow);
noStroke(); controlPanel.style.margin = gameFrame.border + 'px';
rect(x, y, gameFrame.tileWidth, gameFrame.tileHeight); controlPanel.style.marginRight = 0;
controlPanel.style.height = (gameFrame.height - gridHeight - 3 * gameFrame.border) + 'px';
}
/**
* Resets all game state variables and reinitializes the game board
*/
function resetGame() {
gameSprites.forEach((sprite) => sprite.remove());
activeCats = [];
activeMice = Array.from({ length: 5 }, () => []);
gameSprites = [];
robotVacuums = [];
cheeses = [];
grid = Array(5).fill().map(() => Array(9).fill(null));
levelMice = [...level1Mice];
startTime = millis() / 1000;
cheeseCount.textContent = 50;
catGroup = new Group();
mouseGroup = new Group();
throwableGroup = new Group();
}
/**
* Draws the tile grid on the game canvas
* Applies hover feedback based on selected cat type and grid cell state
*/
function drawGrid() {
for (let row = 0; row < gameFrame.rows; row++) {
for (let col = 0; col < gameFrame.cols; col++) {
let x = gameFrame.padding_left + col * gameFrame.tileWidth;
let y = gameFrame.padding_up + row * gameFrame.tileHeight;
let isHovering = (
mouseX > x && mouseX < x + gameFrame.tileWidth &&
mouseY > y && mouseY < y + gameFrame.tileHeight
);
if (isHovering && selectedCatType && selectedCatType === 'petCage' && grid[row][col] != null) {
fill(Colors.med_brown);
} }
else if (isHovering && selectedCatType && selectedCatType != 'petCage' && grid[row][col] == null) {
fill(Colors.med_brown);
}
else fill((row + col) % 2 === 0 ? Colors.dark_yellow : Colors.light_yellow);
noStroke();
rect(x, y, gameFrame.tileWidth, gameFrame.tileHeight);
} }
} }
} }
function updateCheeseCount(n) { /**
let currCheese = int(cheeseCount.textContent); * Draws the left and right borders and the cheeseFeast loss-detection area
currCheese += n; */
cheeseCount.textContent = currCheese; function drawSideBars() {
} leftBar = createSprite(gameFrame.border / 2, gameFrame.padding_up + gameFrame.tileHeight * 2.5, gameFrame.border, gameFrame.tileHeight * 5);
leftBar.color = Colors.med_brown;
leftBar.layer = 10;
leftBar.overlaps(allSprites);
gameSprites.push(leftBar);
function spawnMouse(type, row) { rightBar = createSprite(width - gameFrame.border / 2, gameFrame.padding_up + gameFrame.tileHeight * 2.5, gameFrame.border, gameFrame.tileHeight * 5);
let x = width; rightBar.color = Colors.med_brown;
let y = gameFrame.padding_up + row * gameFrame.tileHeight + gameFrame.tileHeight / 2; rightBar.layer = 10;
rightBar.overlaps(allSprites);
let newMouse = new createMouse(type, x, y, row); gameSprites.push(rightBar);
if (newMouse) {
activeMice[row].push(newMouse);
if (type == 'bossMouse') {
if (row - 1 >= 0) activeMice[row - 1].push(newMouse);
if (row + 1 < gameFrame.rows) activeMice[row + 1].push(newMouse);
}
mouseGroup.add(newMouse.sprite);
gameSprites.push(newMouse.sprite);
}
}
export function updateProgressBar() { cheeseFeast = createSprite(gameFrame.tileWidth / 4, gameFrame.padding_up + gameFrame.tileHeight * 2.5, gameFrame.tileWidth / 2, gameFrame.tileHeight * 5);
miceKilled++; cheeseFeast.opacity = 0;
const percentage = Math.floor((miceKilled / level1Mice.length) * 100); cheeseFeast.overlaps(mouseGroup);
gameProgress.value = percentage; gameSprites.push(cheeseFeast)
if (percentage >= 100) {
showWinningScreen();
}
console.log(`killed ${miceKilled} out of ${level1Mice.length}, % = ${percentage}`);
}
const catCosts = {
chefCat: 50,
singleYarnCat: 100,
doubleYarnCat: 200,
sleepyCat: 150,
iceCat: 150
};
function updateCatButtons() {
document.querySelectorAll('.catButton').forEach(button => {
const catType = button.id;
const cost = catCosts[catType];
if (parseInt(cheeseCount.textContent) < cost) {
button.disabled = true;
button.style.cursor = 'not-allowed';
button.style.opacity = '0.5';
}
else {
button.disabled = false;
button.style.opacity = '1';
button.style.cursor = 'pointer';
}
})
} }

30
Helper.js Normal file
View File

@ -0,0 +1,30 @@
import { gameFrame } from "./constants/Prototype.js";
/**
* Calculates the grid cell (row and column) corresponding to the given mouse coordinates
*
* @param { number } mouseX - The X-coordinate of the mouse relative to the canvas
* @param { number } mouseY - The Y-coordinate of the mouse relative to the canvas
* @returns {{row: number, col: number}} An object containing the calculated row and column indices
*/
export function calculateCell(mouseX, mouseY) {
let col = floor((mouseX - gameFrame.padding_left) / gameFrame.tileWidth)
let row = floor((mouseY - gameFrame.padding_up) / gameFrame.tileHeight)
return {row, col};
}
/**
* Checks whether the specified cell coordinates are within the valid bounds the game grid
*
* @param {number} row - The row index of the cell to validate
* @param {number} col - The column index of the cell to validate
* @returns {boolean} True if the cell is within the bounds of the game grid, otherwise, false
*/
export function isCellValid(row, col) {
if (row < 0) return false;
if (row >= gameFrame.rows) return false;
if (col < 0) return false;
if (col >= gameFrame.cols) return false;
return true;
}

BIN
assets/.DS_Store vendored

Binary file not shown.

View File

@ -1,10 +1,10 @@
import { gameFrame } from '../constants/Prototype.js'; import { gameFrame } from '../constants/Prototype.js';
import { catAnimation, imageAssets } from '../sketch.js'; import { catAnimation, imageAssets } from '../sketch.js';
import { grid, cheeses, activeCats, activeMice, calculateCell, mouseGroup, throwableGroup, gameSprites } from '../GameScene.js'; import { grid, cheeses, activeCats, activeMice, mouseGroup, throwableGroup, gameSprites } from '../GameScene.js';
import { Yarn, Snowball } from './Throwable.js'; import { Yarn, Snowball } from './Throwable.js';
import { calculateCell } from '../Helper.js';
export const throwables = []; export const throwables = [];
export const sleepyCats = [];
const catAniDesc = { const catAniDesc = {
chefCat: { chefCat: {
idle: { row: 0, frames: 4, frameSize: [200, 200], frameDelay: 10 }, idle: { row: 0, frames: 4, frameSize: [200, 200], frameDelay: 10 },
@ -31,7 +31,19 @@ const catAniDesc = {
} }
} }
/**
* Cat class representing a cat character in the game
*/
class Cat { class Cat {
/**
* Creates an iinstance of a Cat
*
* @param {number} x - The x-coordinate of the cat's position
* @param {number} y - The y-coordinate of the cat's position
* @param {number} cost - The cost of placing the cat
* @param {p5.SpriteSheet} spriteSheet - The sprite sheet for the cat's animations
* @param {Object} ani - Animation details for the cat
*/
constructor(x, y, cost, spriteSheet, ani) { constructor(x, y, cost, spriteSheet, ani) {
// (x, y) is the center of the grid // (x, y) is the center of the grid
this.width = 1.2 * gameFrame.tileWidth; this.width = 1.2 * gameFrame.tileWidth;
@ -57,16 +69,26 @@ class Cat {
this.col = col; this.col = col;
} }
/**
* Switches the cat's animation to 'idle' state
*/
switchToIdle() { switchToIdle() {
this.sprite.changeAni('idle'); this.sprite.changeAni('idle');
this.active = false; this.active = false;
} }
/**
* Switches the cat's animation to 'action' state
*/
switchToAction() { switchToAction() {
this.sprite.changeAni('action'); this.sprite.changeAni('action');
this.active = true; this.active = true;
} }
/**
* Called when the cat is attacked by a mouse
* @param {Object} mouse - The mouse attacking the cat
*/
attacked(mouse) { attacked(mouse) {
this.addExplosion(imageAssets.grayExplosion); this.addExplosion(imageAssets.grayExplosion);
this.explosion = undefined; this.explosion = undefined;
@ -82,20 +104,30 @@ class Cat {
}, 1500); }, 1500);
} }
changeAni(name) { /**
this.sprite.changeAni(name); * Removes the cat from the game
} */
remove() { remove() {
this.sprite.remove(); this.sprite.remove();
grid[this.row][this.col] = null; grid[this.row][this.col] = null;
const index = activeCats.indexOf(this); let index = activeCats.indexOf(this);
if (index !== -1) { if (index !== -1) {
activeCats.splice(index, 1); activeCats.splice(index, 1);
} }
index = gameSprites.indexOf(this);
if (index !== -1) {
gameSprites.splice(index, 1);
}
} }
/**
* Adds an explosion animation to the cat
* SleepyCat - Red explosion when it overlaps with a mouse
* Other Cats - Gray explosion when it is attacked by a mouse
* @param {p5.SpriteSheet} spriteSheet - The sprite sheet for the explosion
*/
addExplosion(spriteSheet) { addExplosion(spriteSheet) {
this.explosion = createSprite(this.x, this.y, this.width, this.width); this.explosion = createSprite(this.x, this.y, this.width, this.width);
gameSprites.push(this.explosion); gameSprites.push(this.explosion);
@ -105,11 +137,12 @@ class Cat {
this.explosion.collider = 'none'; this.explosion.collider = 'none';
this.explosion.addAnis(catAniDesc.explosion); this.explosion.addAnis(catAniDesc.explosion);
this.explosion.changeAni('action'); this.explosion.changeAni('action');
// this.explosion.overlaps(mouseGroup);
// this.explosion.overlaps(catGroup);
} }
} }
/**
* Cat that generates cheese periodically for resources
*/
class ChefCat extends Cat { class ChefCat extends Cat {
constructor(x, y) { constructor(x, y) {
super(x, y, 50, catAnimation.chefCat, catAniDesc.chefCat); super(x, y, 50, catAnimation.chefCat, catAniDesc.chefCat);
@ -118,13 +151,14 @@ class ChefCat extends Cat {
} }
action() { action() {
// Produces 25 cheese every 10 seconds, cheese.png pop in front of the chefCat // Produces 25 cheese every 10 seconds
if (millis() - this.lastProduced > 10000) { if (millis() - this.lastProduced > 10000) {
const cheese = createSprite(this.x + this.width / 4 + this.offset * this.width / 20, this.y + this.width / 3 + this.offset * this.width / 20); const cheese = createSprite(this.x + this.width / 4 + this.offset * this.width / 20, this.y + this.width / 3 + this.offset * this.width / 20);
cheese.scale = this.width / 216; cheese.scale = this.width / 216;
cheese.image = imageAssets.cheese; cheese.image = imageAssets.cheese;
cheese.collider = 'static'; cheese.collider = 'static';
cheese.overlaps(mouseGroup); cheese.overlaps(mouseGroup);
cheeses.push(cheese); cheeses.push(cheese);
gameSprites.push(cheese); gameSprites.push(cheese);
this.lastProduced = millis(); this.lastProduced = millis();
@ -133,6 +167,9 @@ class ChefCat extends Cat {
} }
} }
/**
* Cat that throws a single yarn at mice every 3 seconds
*/
class SingleYarnCat extends Cat { class SingleYarnCat extends Cat {
constructor(x, y) { constructor(x, y) {
super(x, y, 100, catAnimation.singleYarnCat, catAniDesc.singleYarnCat); super(x, y, 100, catAnimation.singleYarnCat, catAniDesc.singleYarnCat);
@ -140,7 +177,6 @@ class SingleYarnCat extends Cat {
} }
action() { action() {
// Throw yarn every 3 seconds -> yarn has velocity x of 1 (to the right)
if (activeMice[this.row].length > 0) this.switchToAction(); if (activeMice[this.row].length > 0) this.switchToAction();
else this.switchToIdle(); else this.switchToIdle();
@ -159,6 +195,9 @@ class SingleYarnCat extends Cat {
} }
} }
/**
* Cat that throws 2 yarns at mice every 3 seconds
*/
class DoubleYarnCat extends Cat { class DoubleYarnCat extends Cat {
constructor(x, y) { constructor(x, y) {
super(x, y, 200, catAnimation.doubleYarnCat, catAniDesc.doubleYarnCat); super(x, y, 200, catAnimation.doubleYarnCat, catAniDesc.doubleYarnCat);
@ -166,14 +205,12 @@ class DoubleYarnCat extends Cat {
} }
action() { action() {
// Throw 2 yarns every 3 seconds -> yarn has velocity x of 1 (to the right)
if (activeMice[this.row].length > 0) this.switchToAction(); if (activeMice[this.row].length > 0) this.switchToAction();
else this.switchToIdle(); else this.switchToIdle();
if (this.active && (millis() - this.lastShot > 3000)) { if (this.active && (millis() - this.lastShot > 3000)) {
// TODO: check on the offset again // TODO: check on the offset again
for (let offset of [0, 20]) { for (let offset of [0, 0.3 * gameFrame.tileWidth]) {
let yarnX = this.x + gameFrame.tileWidth / 2 + offset; let yarnX = this.x + gameFrame.tileWidth / 2 + offset;
let yarnY = this.y; let yarnY = this.y;
@ -189,6 +226,9 @@ class DoubleYarnCat extends Cat {
} }
} }
/**
* Cat that activates when overlapping with a mouse and explodes, damaging the enemy by 150 points
*/
export class SleepyCat extends Cat { export class SleepyCat extends Cat {
constructor(x, y) { constructor(x, y) {
super(x, y, 150, catAnimation.sleepyCat, catAniDesc.sleepyCat); super(x, y, 150, catAnimation.sleepyCat, catAniDesc.sleepyCat);
@ -200,7 +240,7 @@ export class SleepyCat extends Cat {
action(targetMouse) { action(targetMouse) {
if (this.awake) { if (this.awake) {
this.changeAni('action'); this.switchToAction();
this.addExplosion(imageAssets.redExplosion); this.addExplosion(imageAssets.redExplosion);
this.wakeStart = millis(); this.wakeStart = millis();
this.targetMouse = targetMouse; this.targetMouse = targetMouse;
@ -224,6 +264,9 @@ export class SleepyCat extends Cat {
} }
} }
/**
* Cat that throws snowballs at mice every 3 seconds
*/
class IceCat extends Cat { class IceCat extends Cat {
constructor(x, y) { constructor(x, y) {
super(x, y, 150, catAnimation.iceCat, catAniDesc.iceCat); super(x, y, 150, catAnimation.iceCat, catAniDesc.iceCat);
@ -231,8 +274,6 @@ class IceCat extends Cat {
} }
action() { action() {
// Throw snowball every 3 seconds -> snowball has velocity x of 1 (to the right)
if (activeMice[this.row].length > 0) this.switchToAction(); if (activeMice[this.row].length > 0) this.switchToAction();
else this.switchToIdle(); else this.switchToIdle();
@ -251,6 +292,13 @@ class IceCat extends Cat {
} }
} }
/**
* Factory function to create different types of cats
* @param {string} type - The type of cat to create. One of 'chefCat', 'singleYarnCat', 'doubleYarnCat', 'sleepyCat', 'iceCat'
* @param {number} x - The x-coordinate
* @param {number} y - The y-coordinate
* @returns {Cat|undefined} The created cat instance or undefined if type is invalid
*/
export function createCat(type, x, y) { export function createCat(type, x, y) {
switch (type) { switch (type) {
case 'chefCat': case 'chefCat':
@ -262,9 +310,7 @@ export function createCat(type, x, y) {
case 'doubleYarnCat': case 'doubleYarnCat':
return new DoubleYarnCat(x, y); return new DoubleYarnCat(x, y);
case 'sleepyCat': case 'sleepyCat':
const sleepyCat = new SleepyCat(x, y); return new SleepyCat(x, y);
if (sleepyCat) sleepyCats.push(sleepyCat);
return sleepyCat;
case 'iceCat': case 'iceCat':
return new IceCat(x, y); return new IceCat(x, y);
default: default:

View File

@ -1,26 +1,42 @@
import { gameFrame } from '../constants/Prototype.js'; import { gameFrame } from '../constants/Prototype.js';
import { mouseAnimation } from '../sketch.js'; import { mouseAnimation } from '../sketch.js';
import { activeMice, mouseGroup, updateProgressBar } from '../GameScene.js'; import { activeMice, mouseGroup, gameSprites } from '../GameScene.js';
import { updateGameProgress } from '../Controller.js';
const mouseAniDesc = { const mouseAniDesc = {
idle: { row: 0, frameSize: [200, 200] }, idle: { row: 0, frameSize: [200, 200] },
walk: {row: 1, frames: 6, frameSize: [200, 200], frameDelay: 10 } walk: {row: 1, frames: 6, frameSize: [200, 200], frameDelay: 10 }
} }
/**
* Mouse class representing a mouse character in the game
*/
class Mouse { class Mouse {
constructor(x, y, row, speed, HP, AP, spriteSheet, width) { /**
this.sprite = createSprite(x, y, width, width); * Creates an instance of a Mouse
*
* @param {number} row - The row the mouse belongs to
* @param {number} speed - The speed of the mouse's movement
* @param {number} HP - The health points of the mouse
* @param {number} AP - The attack power of the mouse
* @param {object} spriteSheet - The sprite sheet for the mouse animation
* @param {number} size - The size of the mouse sprite
*/
constructor(row, speed, HP, AP, spriteSheet, size) {
const y = gameFrame.padding_up + row * gameFrame.tileHeight + gameFrame.tileHeight / 2;
this.sprite = createSprite(width, y, size, size);
this.sprite.spriteSheet = spriteSheet; this.sprite.spriteSheet = spriteSheet;
this.sprite.scale = gameFrame.catRatio * width / gameFrame.tileWidth; this.sprite.scale = gameFrame.catRatio * size / gameFrame.tileWidth;
this.sprite.overlaps(mouseGroup) this.sprite.overlaps(mouseGroup)
this.sprite.addAnis(mouseAniDesc); this.sprite.addAnis(mouseAniDesc);
this.sprite.changeAni('walk'); this.sprite.changeAni('walk');
this.sprite.layer = 3; this.sprite.layer = 3;
this.sprite.vel.x = speed; this.sprite.vel.x = speed;
this.row = row; this.row = row;
this.HP = HP; this.HP = HP;
this.AP = AP; this.AP = AP;
this.width = width;
this.targetCat = undefined; this.targetCat = undefined;
this.lastAttack = 0; this.lastAttack = 0;
this.defaultSpeed = speed; this.defaultSpeed = speed;
@ -28,12 +44,16 @@ class Mouse {
this.isAlive = true; this.isAlive = true;
} }
/**
* Removes the mouse from the game and updates the progress
*/
remove() { remove() {
this.sprite.remove(); this.sprite.remove();
let index = activeMice[this.row].indexOf(this); let index = activeMice[this.row].indexOf(this);
if (index != -1) { if (index != -1) {
activeMice[this.row].splice(index, 1); activeMice[this.row].splice(index, 1);
} }
if (this.defaultHP = 1000) { if (this.defaultHP = 1000) {
if (this.row - 1 >= 0) { if (this.row - 1 >= 0) {
index = activeMice[this.row - 1].indexOf(this); index = activeMice[this.row - 1].indexOf(this);
@ -44,17 +64,25 @@ class Mouse {
if (index != -1) activeMice[this.row + 1].splice(index, 1); if (index != -1) activeMice[this.row + 1].splice(index, 1);
} }
} }
index = gameSprites.indexOf(this);
if (index !== -1) {
gameSprites.splice(index, 1);
}
if (this.isAlive) { if (this.isAlive) {
this.isAlive = false; this.isAlive = false;
updateProgressBar(); updateGameProgress();
} }
} }
/**
* Makes the mouse attack the target cat if one exists
*/
attack() { attack() {
if (this.targetCat != undefined) { if (this.targetCat != undefined) {
this.sprite.vel.x = 0; this.sprite.vel.x = 0;
this.sprite.changeAni('idle'); this.sprite.changeAni('idle');
console.log(`I have a target Cat, and its HP is ${this.targetCat.HP}`)
if (this.lastAttack == 0 || millis() - this.lastAttack > 3000) { if (this.lastAttack == 0 || millis() - this.lastAttack > 3000) {
this.targetCat.attacked(this); this.targetCat.attacked(this);
this.lastAttack = millis(); this.lastAttack = millis();
@ -66,9 +94,12 @@ class Mouse {
} }
} }
/**
* Handles when the mouse is attacked and reduces its health
* @param {number} point - The damage taken by the mouse
*/
attacked(point) { attacked(point) {
this.HP -= point; this.HP -= point;
console.log(`I'm being attacked by ${point} points and my HP is now ${this.HP}`)
if (this.HP <= 0) this.remove(); if (this.HP <= 0) this.remove();
else { else {
this.sprite.opacity = (this.HP / this.defaultHP) * 0.5 + 0.5; this.sprite.opacity = (this.HP / this.defaultHP) * 0.5 + 0.5;
@ -76,41 +107,82 @@ class Mouse {
} }
} }
/**
* Basic type of mouse
*/
class BasicMouse extends Mouse { class BasicMouse extends Mouse {
constructor(x, y, row) { constructor(x, y, row) {
super(x, y, row, -0.15, 100, 20, mouseAnimation.basicMouse, gameFrame.tileWidth); super(x, y, row, -0.15, 100, 20, mouseAnimation.basicMouse, gameFrame.tileWidth);
} }
} }
/**
* Helmet-wearing mouse
* Has a higher HP compared to BasicMouse
*/
class HelmetMouse extends Mouse { class HelmetMouse extends Mouse {
constructor(x, y, row) { constructor(x, y, row) {
super(x, y, row, -0.15, 150, 20, mouseAnimation.helmetMouse, gameFrame.tileWidth); super(x, y, row, -0.15, 150, 20, mouseAnimation.helmetMouse, gameFrame.tileWidth);
} }
} }
/**
* Sporty type of mouse
* Has a higher speed compared to Basic Mouse
*/
class SportyMouse extends Mouse { class SportyMouse extends Mouse {
constructor(x, y, row) { constructor(x, y, row) {
super(x, y, row, -0.3, 85, 20, mouseAnimation.sportyMouse, gameFrame.tileWidth); super(x, y, row, -0.3, 85, 20, mouseAnimation.sportyMouse, gameFrame.tileWidth);
} }
} }
/**
* Boss mouse is 3 times bigger than other mice
* Has a higher HP and AP compared to the other types
* Has a slower speed compared to the other types
*/
class BossMouse extends Mouse { class BossMouse extends Mouse {
constructor(x, y, row) { constructor(x, y, row) {
super(x, y, row, -0.05, 1000, 50, mouseAnimation.bossMouse, 3 * gameFrame.tileWidth); super(x, y, row, -0.05, 1000, 50, mouseAnimation.bossMouse, 3 * gameFrame.tileWidth);
} }
} }
export function createMouse(type, x, y, row) { /**
* Factory function to create different types of cats
*
* @param {string} type - The type of mouse to create
* @param {number} row - The row the mouse belongs to
* @returns @returns {Mouse|undefined} The created mouse instance or undefined if type is invalid
*/
function createMouse(type, row) {
switch (type) { switch (type) {
case 'basicMouse': case 'basicMouse':
return new BasicMouse(x, y, row); return new BasicMouse(row);
case 'helmetMouse': case 'helmetMouse':
return new HelmetMouse(x, y, row); return new HelmetMouse(row);
case 'sportyMouse': case 'sportyMouse':
return new SportyMouse(x, y, row); return new SportyMouse(row);
case 'bossMouse': case 'bossMouse':
return new BossMouse(x, y, row); return new BossMouse(row);
default: default:
return undefined; return undefined;
} }
}
/**
* Spawns a mouse of a specified type and adds it to the game
* @param {string} type - The type of mouse to spawn
* @param {number} row - The row to spawn the mouse in
*/
export function spawnMouse(type, row) {
let newMouse = new createMouse(type, row);
if (newMouse) {
activeMice[row].push(newMouse);
if (type == 'bossMouse') {
if (row - 1 >= 0) activeMice[row - 1].push(newMouse);
if (row + 1 < gameFrame.rows) activeMice[row + 1].push(newMouse);
}
mouseGroup.add(newMouse.sprite);
gameSprites.push(newMouse.sprite);
}
} }

View File

@ -1,6 +1,6 @@
import { gameFrame } from '../constants/Prototype.js'; import { gameFrame } from '../constants/Prototype.js';
import { imageAssets } from '../sketch.js'; import { imageAssets } from '../sketch.js';
import { activeMice, catGroup, throwableGroup } from '../GameScene.js'; import { activeMice, catGroup, throwableGroup, gameSprites, robotVacuums } from '../GameScene.js';
export class RobotVacuum { export class RobotVacuum {
constructor(x, y, row) { constructor(x, y, row) {
@ -10,10 +10,12 @@ export class RobotVacuum {
this.sprite.layer = 2; this.sprite.layer = 2;
this.sprite.overlaps(catGroup); this.sprite.overlaps(catGroup);
this.sprite.overlaps(throwableGroup); this.sprite.overlaps(throwableGroup);
this.activated = false; this.activated = false;
this.row = row; this.row = row;
} }
// If activated, kills all the active mice in its row
action() { action() {
if (!this.activated) { if (!this.activated) {
this.activated = true; this.activated = true;
@ -29,4 +31,19 @@ export class RobotVacuum {
} }
} }
}
/**
* Draws 1 vacuum robot on each row at the bginning of the game
*/
export function drawRobotVacuums() {
for (let row = 0; row < gameFrame.rows; row ++) {
let x = gameFrame.paddingRobot + gameFrame.robotSize / 2;
let y = gameFrame.padding_up + row * gameFrame.tileHeight + gameFrame.tileHeight / 2;
let vacuum = new RobotVacuum(x, y, row);
gameSprites.push(vacuum.sprite);
robotVacuums.push(vacuum);
}
} }

View File

@ -11,6 +11,7 @@ export class Throwable {
this.sprite.vel.x = 1; this.sprite.vel.x = 1;
this.sprite.rotationSpeed = 1; this.sprite.rotationSpeed = 1;
this.sprite.life = 600; this.sprite.life = 600;
this.point = point; this.point = point;
this.width = width; this.width = width;
} }
@ -20,12 +21,14 @@ export class Throwable {
} }
} }
// Yarn is thrown by singleYarnCat and doubleYarnCat
export class Yarn extends Throwable { export class Yarn extends Throwable {
constructor(x, y) { constructor(x, y) {
super(x, y, 15, imageAssets.yarn, gameFrame.tileWidth / 4); super(x, y, 15, imageAssets.yarn, gameFrame.tileWidth / 4);
} }
} }
// Snowball is thrown by IceCat
export class Snowball extends Throwable { export class Snowball extends Throwable {
constructor(x, y) { constructor(x, y) {
super(x, y, 20, imageAssets.snowball, gameFrame.tileWidth / 4); super(x, y, 20, imageAssets.snowball, gameFrame.tileWidth / 4);

View File

@ -1,5 +1,7 @@
export const Colors = { export const Colors = {
dark_brown: '#B09472', dark_brown: '#503E28',
med_brown: '#B09472',
light_brown: '#CAB49A',
dark_yellow: '#F7E7BE', dark_yellow: '#F7E7BE',
light_yellow: '#FDF4E5' light_yellow: '#FDF4E5'
} }

View File

@ -1,3 +1,4 @@
// Numbers from the prototype designed on Figma
export const prototypeFrame = { export const prototypeFrame = {
border: 10, border: 10,
width: 800, width: 800,
@ -13,6 +14,7 @@ export const prototypeFrame = {
controlPanelGap: 8 controlPanelGap: 8
} }
// Numbers used in the actual gameFrame
export const gameFrame = { export const gameFrame = {
x: 0, x: 0,
y: 0, y: 0,

View File

@ -2,7 +2,9 @@
--dark-brown: #503E28; --dark-brown: #503E28;
--med-brown: #B09472; --med-brown: #B09472;
--light-brown: #CAB49A; --light-brown: #CAB49A;
--highlight-brown: #A8845D;
--dark-yellow: #F7E7BE; --dark-yellow: #F7E7BE;
--med-yellow: #EDDBBD;
--light-yellow: #FDF4E5; --light-yellow: #FDF4E5;
} }
@ -15,11 +17,18 @@ body {
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-family: "Inter", sans-serif;
font-weight: 600;
}
#title {
color: var(--dark-brown);
font-weight: 600;
font-family: "Fredoka", sans-serif;;
} }
#gameFrame { #gameFrame {
position: relative; position: relative;
/* flex-shrink: 0; */
max-width: 800px; max-width: 800px;
width: 60vw; width: 60vw;
aspect-ratio: 800/569; aspect-ratio: 800/569;
@ -44,18 +53,23 @@ body {
#endingText { #endingText {
color: var(--dark-yellow); color: var(--dark-yellow);
font-weight: 600;
font-size: x-large;
font-family: "Fredoka", sans-serif;
} }
canvas { canvas {
display: block; display: block;
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 25px;
z-index: 0; z-index: 0;
background-color: var(--med-brown);
} }
#upperContainer { #upperContainer {
position: absolute; position: absolute;
display: flex;
flex-direction: row;
align-items: center; align-items: center;
background: var(--med-brown); background: var(--med-brown);
border-radius: 25px 25px 0 0; border-radius: 25px 25px 0 0;
@ -63,8 +77,7 @@ canvas {
} }
#controlPanel { #controlPanel {
/* background: var(--light-brown); */ width: 73.4%;
border-radius: 30px 30px 0 0;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
@ -81,8 +94,8 @@ canvas {
#cheeseDisplay { #cheeseDisplay {
background: var(--light-brown); background: var(--light-brown);
height: 100%; height: 100%;
width: 9.7%; width: 13.5%;
border-radius: 8px; border-radius: 12%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@ -93,12 +106,7 @@ canvas {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
height: 100%; height: 100%;
width: auto; width: 65%
aspect-ratio: 330/83;
/* gap: 1px; */
background: var(--light-brown);
/* padding: 4px 8px; */
border-radius: 6px;
} }
.catButton { .catButton {
@ -107,16 +115,25 @@ canvas {
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
background: var(--light-brown); background: var(--light-brown);
border: 1px solid var(--dark-brown); border: 1px solid var(--med-brown);
border-radius: 4px;
padding: 4px 6px; padding: 4px 6px;
cursor: pointer; cursor: pointer;
transition: background 0.2s; transition: background 0.2s ease;
}
#chefCat {
border-radius: 12% 0 0 12%;
}
#iceCat {
border-radius: 0 12% 12% 0;
} }
.catButton span { .catButton span {
font-size: 12px; margin-top: 5%;
color: #333; font-size: small;
font-weight: 600;
color: var(--dark-brown);
} }
.catButton:not(:disabled):hover { .catButton:not(:disabled):hover {
@ -124,7 +141,11 @@ canvas {
} }
.catButton.activeButton { .catButton.activeButton {
background: red; background: var(--light-yellow);
}
.catButton.activeButton:hover {
background: var(--med-yellow);
} }
.divider { .divider {
@ -136,6 +157,7 @@ canvas {
width: auto; width: auto;
aspect-ratio: 60/83; aspect-ratio: 60/83;
justify-content: center; justify-content: center;
border-radius: 12%;
} }
.catIcon { .catIcon {
@ -156,8 +178,13 @@ canvas {
object-fit: contain; object-fit: contain;
} }
#cheeseCount {
margin-top: 10%;
font-size: medium;
}
#gameProgressWrapper { #gameProgressWrapper {
width: 22%; width: 24%;
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -187,7 +214,7 @@ canvas {
} }
#gameProgressLabel { #gameProgressLabel {
height: 20%; font-size: 0.75em;
font-weight: 600; font-weight: 600;
font-family: "Inter", sans-serif; font-family: "Inter", sans-serif;
margin-top: 4%; margin-top: 4%;
@ -198,7 +225,6 @@ canvas {
position: absolute; position: absolute;
translate: -50%; translate: -50%;
width: 100%; width: 100%;
/* z-index: -1; */
} }
.Button { .Button {
@ -213,5 +239,11 @@ canvas {
} }
.Button:hover { .Button:hover {
background: #a8845d; background: var(--highlight-brown);
}
#menuButton {
display: flex;
flex-direction: row;
gap: 15px;
} }

View File

@ -16,7 +16,7 @@
<link rel="stylesheet" type="text/css" href="css/style.css" /> <link rel="stylesheet" type="text/css" href="css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@300..700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Paytone+One&display=swap" rel="stylesheet">
</head> </head>
<body> <body>
@ -24,7 +24,7 @@
<div id="gameFrame"> <div id="gameFrame">
<div id="endingOverlay"> <div id="endingOverlay">
<h1 id="endingText">Congrats! You've finished level 1!</h1> <h1 id="endingText">Congrats! You've finished level 1!</h1>
<button class="Button" id="quitButton">Quit Game</button> <button class="Button" id="quitGameButton">Quit Game</button>
</div> </div>
<div id="upperContainer"> <div id="upperContainer">
<div id="controlPanel"> <div id="controlPanel">
@ -65,19 +65,18 @@
<button class="catButton" id="petCage"> <button class="catButton" id="petCage">
<img src="assets/petCage.png" alt="Pet Cage" id="cageIcon" /> <img src="assets/petCage.png" alt="Pet Cage" id="cageIcon" />
</button> </button>
</div>
<span class="divider"></span> <div id="gameProgressWrapper">
<progress id="gameProgress" value="0" max="100"></progress>
<div id="gameProgressWrapper"> <label id="gameProgressLabel">Game Progress</label>
<progress id="gameProgress" value="0" max="100"></progress>
<label id="gameProgressLabel">Game Progress</label>
</div>
</div> </div>
</div> </div>
</div> </div>
<button class="Button" id="startButton">Start Game</button> <button class="Button" id="startButton">Start Game</button>
<button class="Button" id="menuButton">Menu</button> <div id="menuButton">
<button class="Button" id="restartButton">Restart Game</button>
<button class="Button" id="quitButton">Quit Game</button>
</div>
</body> </body>
</html> </html>

View File

@ -1,6 +1,5 @@
export const level1Mice = [ export const level1Mice = [
// First 30 seconds — Setup Time (no mice) // First 30 seconds — Setup Time (no mice)
// { time: 5, type: 'basicMouse', row: 2 },
// First minute (30 - 89) — Basic Mice only // First minute (30 - 89) — Basic Mice only
{ time: 30, type: 'basicMouse', row: 2 }, { time: 30, type: 'basicMouse', row: 2 },
@ -53,6 +52,7 @@ export const level1Mice = [
{ time: 296, type: 'sportyMouse', row: 2}, { time: 296, type: 'sportyMouse', row: 2},
{ time: 299, type: 'basicMouse', row: 4 }, { time: 299, type: 'basicMouse', row: 4 },
{ time: 303, type: 'helmetMouse', row: 2 }, { time: 303, type: 'helmetMouse', row: 2 },
{ time: 305, type: 'bossMouse', row: 3},
{ time: 307, type: 'sportyMouse', row: 0 }, { time: 307, type: 'sportyMouse', row: 0 },
{ time: 310, type: 'sportyMouse', row: 1 }, { time: 310, type: 'sportyMouse', row: 1 },
{ time: 312, type: 'basicMouse', row: 0}, { time: 312, type: 'basicMouse', row: 0},

View File

@ -1,17 +1,25 @@
const endingOverlay = document.getElementById('endingOverlay'); const endingOverlay = document.getElementById('endingOverlay');
const endingText = document.getElementById('endingText'); const endingText = document.getElementById('endingText');
const menuButton = document.getElementById('menuButton');
const endingMessage = { const endingMessage = {
win: "Nice job! The Cheese Feast is safe!", win: "Nice job! The Cheese Feast is safe!",
lose: "Oh no! The mice crashed the Cheese Feast!<br>Give it another shot! (whiskers crossed)" lose: "Oh no! The mice crashed the Cheese Feast!<br>Give it another shot! (whiskers crossed)"
} }
/**
* Displays the winning screen with a congratulatory message
*/
export function showWinningScreen() { export function showWinningScreen() {
endingText.innerHTML = endingMessage.win; endingText.innerHTML = endingMessage.win;
endingOverlay.style.display = 'flex'; endingOverlay.style.display = 'flex';
menuButton.style.display = 'none';
} }
/**
* Displays the losing screen with a retry encouragement message
*/
export function showLosingScreen() { export function showLosingScreen() {
endingText.innerHTML = endingMessage.lose; endingText.innerHTML = endingMessage.lose;
endingOverlay.style.display = 'flex'; endingOverlay.style.display = 'flex';
menuButton.style.display = 'none';
} }

View File

@ -2,8 +2,6 @@ import { StartScene } from './StartScene.js';
import { GameScene } from './GameScene.js'; import { GameScene } from './GameScene.js';
export let mgr; export let mgr;
const gameParent = document.getElementById('gameFrame');
const startButton = document.getElementById('startButton');
export let startPageAni; export let startPageAni;
export const imageAssets = {}; export const imageAssets = {};
export const catImages = {}; export const catImages = {};
@ -11,7 +9,14 @@ export const catAnimation = {};
export const mouseAnimation = {}; export const mouseAnimation = {};
export let selectedCatType = null; export let selectedCatType = null;
const gameParent = document.getElementById('gameFrame');
const startButton = document.getElementById('startButton');
const restartButton = document.getElementById('restartButton');
const quitButton = document.getElementById('quitButton');
const quitGameButton = document.getElementById('quitGameButton');
function preload() { function preload() {
// Load all images and animations
startPageAni = loadAni('assets/start_page_ani.png', { startPageAni = loadAni('assets/start_page_ani.png', {
width: 1440, height: 1024, frames: 5 width: 1440, height: 1024, frames: 5
}); });
@ -22,7 +27,6 @@ function preload() {
imageAssets.snowball = loadImage('assets/snowball.png'); imageAssets.snowball = loadImage('assets/snowball.png');
imageAssets.robotVacuum = loadImage('assets/robot_vacuum.png'); imageAssets.robotVacuum = loadImage('assets/robot_vacuum.png');
imageAssets.gameBackground = loadImage('assets/game_background.png'); imageAssets.gameBackground = loadImage('assets/game_background.png');
imageAssets.mouse = loadImage('assets/mouse.png');
imageAssets.redExplosion = loadImage('assets/red_explosion.png'); imageAssets.redExplosion = loadImage('assets/red_explosion.png');
imageAssets.grayExplosion = loadImage('assets/gray_explosion.png'); imageAssets.grayExplosion = loadImage('assets/gray_explosion.png');
@ -45,6 +49,7 @@ function preload() {
} }
function setup() { function setup() {
// Set the canvas to #gameFrame
const {width, height} = gameParent.getBoundingClientRect(); const {width, height} = gameParent.getBoundingClientRect();
const canvas = createCanvas(width, height); const canvas = createCanvas(width, height);
@ -53,9 +58,8 @@ function setup() {
mgr.addScene(StartScene); mgr.addScene(StartScene);
mgr.addScene(GameScene); mgr.addScene(GameScene);
// mgr.addScene(PauseScene);
mgr.showScene(GameScene); mgr.showScene(StartScene);
} }
function draw() { function draw() {
@ -66,25 +70,33 @@ function mousePressed() {
mgr.handleEvent("mousePressed"); mgr.handleEvent("mousePressed");
} }
/**
* Reset selectedCatType to null
*/
export function resetCatType() { export function resetCatType() {
console.log(`reset is called`)
selectedCatType = null; selectedCatType = null;
document.querySelectorAll('.catButton').forEach(button => document.querySelectorAll('.catButton').forEach(button =>
button.classList.remove('activeButton') button.classList.remove('activeButton')
); );
} }
// Add event listener to the buttons
startButton.addEventListener('click', function (event) { startButton.addEventListener('click', function (event) {
event.preventDefault(); event.preventDefault();
mgr.showScene(GameScene); mgr.showScene(GameScene);
}); });
menuButton.addEventListener('click', function (event) { restartButton.addEventListener('click', function (event) {
event.preventDefault();
mgr.showScene(GameScene);
});
quitButton.addEventListener('click', function (event) {
event.preventDefault(); event.preventDefault();
mgr.showScene(StartScene); mgr.showScene(StartScene);
}); });
quitButton.addEventListener('click', function (event) { quitGameButton.addEventListener('click', function (event) {
event.preventDefault(); event.preventDefault();
mgr.showScene(StartScene); mgr.showScene(StartScene);
}); });
@ -102,12 +114,9 @@ document.querySelectorAll('.catButton').forEach(button => {
); );
button.classList.add('activeButton'); button.classList.add('activeButton');
} }
console.log('Selected cat type:', selectedCatType);
}); });
}); });
window.preload = preload; window.preload = preload;
window.setup = setup; window.setup = setup;
window.draw = draw; window.draw = draw;