diff --git a/GameScene.js b/GameScene.js index 053ee7a..6f1db36 100644 --- a/GameScene.js +++ b/GameScene.js @@ -5,6 +5,7 @@ import { createCat, SleepyCat, sleepyCats, throwables } from './classes/Cat.js'; import { createMouse } from './classes/Mouse.js'; import { RobotVacuum } from './classes/RobotVacuum.js'; import { level1Mice } from './level/Level1.js'; +import { showWinningScreen, showLosingScreen } from './level/WinLose.js'; const gameParent = document.getElementById('gameFrame'); const upperContainer = document.getElementById('upperContainer'); @@ -14,6 +15,7 @@ const gameProgress = document.getElementById('gameProgress'); export const activeCats = []; export const activeMice = Array.from({ length: 5 }, () => []); const robotVacuums = []; +let leftBar, rightBar, cheeseFeast; export let gameSprites = []; export let cheeses = []; export let grid = Array(5).fill().map(() => Array(9).fill(null)); @@ -40,6 +42,7 @@ function isCellValid(row, col) { export function GameScene() { this.enter = function() { select('#upperContainer').show(); + select('#endingOverlay').hide(); select('#menuButton').show(); select('#startButton').hide(); @@ -52,6 +55,23 @@ export function GameScene() { 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; @@ -111,6 +131,11 @@ export function GameScene() { for (let i = 0; i < activeMice[row].length; i++) { const currMouse = activeMice[row][i]; currMouse.attack(); + + if (cheeseFeast.overlaps(currMouse.sprite)) { + showLosingScreen(); + } + sleepyCats.forEach((cat) => { if (cat.sprite.overlaps(currMouse.sprite)) { cat.awake = true; @@ -227,13 +252,13 @@ function updateCheeseCount(n) { function spawnMouse(type, row) { let x = width; let y = gameFrame.padding_up + row * gameFrame.tileHeight + gameFrame.tileHeight / 2; - + let newMouse = new createMouse(type, x, y, 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); + if (row + 1 < gameFrame.rows) activeMice[row + 1].push(newMouse); } mouseGroup.add(newMouse.sprite); gameSprites.push(newMouse.sprite); @@ -244,6 +269,10 @@ export function updateProgressBar() { miceKilled++; const percentage = Math.floor((miceKilled / level1Mice.length) * 100); gameProgress.value = percentage; + + if (percentage >= 100) { + showWinningScreen(); + } console.log(`killed ${miceKilled} out of ${level1Mice.length}, % = ${percentage}`); } @@ -260,7 +289,7 @@ function updateCatButtons() { const catType = button.id; const cost = catCosts[catType]; - if (int(cheeseCount.textContent) < cost) { + if (parseInt(cheeseCount.textContent) < cost) { button.disabled = true; button.style.cursor = 'not-allowed'; button.style.opacity = '0.5'; diff --git a/StartScene.js b/StartScene.js index b2a3d7a..432d603 100644 --- a/StartScene.js +++ b/StartScene.js @@ -5,6 +5,7 @@ export function StartScene() { const self = this; select('#upperContainer').hide(); + select('#endingOverlay').hide(); select('#menuButton').hide(); select('#startButton').show(); } diff --git a/assets/catsLabel.png b/assets/catsLabel.png index d8dc347..6754a85 100644 Binary files a/assets/catsLabel.png and b/assets/catsLabel.png differ diff --git a/assets/cheeseLabel.png b/assets/cheeseLabel.png index 22a9f59..c656307 100644 Binary files a/assets/cheeseLabel.png and b/assets/cheeseLabel.png differ diff --git a/assets/game_background.png b/assets/game_background.png new file mode 100644 index 0000000..9cf03ed Binary files /dev/null and b/assets/game_background.png differ diff --git a/assets/gamebg3.png b/assets/gamebg3.png deleted file mode 100644 index b83285a..0000000 Binary files a/assets/gamebg3.png and /dev/null differ diff --git a/css/style.css b/css/style.css index 126f355..9b607c7 100644 --- a/css/style.css +++ b/css/style.css @@ -28,6 +28,24 @@ body { overflow: hidden; } +#endingOverlay { + position: fixed; + max-width: 800px; + width: 60vw; + aspect-ratio: 800/569; + border-radius: 35px; + background-color: rgba(80, 62, 40, 0.75); + z-index: 100; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +#endingText { + color: var(--dark-yellow); +} + canvas { display: block; width: 100%; @@ -38,9 +56,6 @@ canvas { #upperContainer { position: absolute; - display: flex; - flex-direction: row; - gap: 16px; align-items: center; background: var(--med-brown); border-radius: 25px 25px 0 0; @@ -52,13 +67,10 @@ canvas { border-radius: 30px 30px 0 0; display: flex; flex-direction: row; - gap: 10px; - /* TODO: ganti ke % apa ya, 10px magic number bgt */ align-items: center; } #cheeseLabel { - margin-left: 20px; height: 100%; } @@ -69,8 +81,7 @@ canvas { #cheeseDisplay { background: var(--light-brown); height: 100%; - width: auto; - aspect-ratio: 80/83; + width: 9.7%; border-radius: 8px; display: flex; flex-direction: column; @@ -99,7 +110,6 @@ canvas { border: 1px solid var(--dark-brown); border-radius: 4px; padding: 4px 6px; - font-size: 18px; cursor: pointer; transition: background 0.2s; } @@ -117,6 +127,10 @@ canvas { background: red; } +.divider { + width: 1.5%; +} + #petCage { height: 100%; width: auto; @@ -143,17 +157,22 @@ canvas { } #gameProgressWrapper { + width: 22%; + height: 100%; display: flex; flex-direction: column; align-items: center; - height: 50%; + justify-content: center; } #gameProgress { appearance: none; + width: 75%; + height: 20%; border-radius: 100px; + margin-top: 5%; background-color: var(--dark-brown); - border: 4px solid #4b392b; + border: 4px solid var(--dark-brown); overflow: hidden; } @@ -168,9 +187,11 @@ canvas { } #gameProgressLabel { - margin-top: 0.5rem; - font-size: 1.2rem; - font-weight: bold; + height: 20%; + font-weight: 600; + font-family: "Inter", sans-serif; + margin-top: 4%; + color: var(--dark-brown); } #gameBackground { diff --git a/index.html b/index.html index 4b16b41..a3e88d7 100644 --- a/index.html +++ b/index.html @@ -14,19 +14,29 @@ + + +

Cats vs Mice

+
+

Congrats! You've finished level 1!

+ +
Cheese Label +
Cheese Icon 50
+ Cat Label +
+ + + + +
- +
+ diff --git a/level/Level1.js b/level/Level1.js index 01a1d09..1f0dc62 100644 --- a/level/Level1.js +++ b/level/Level1.js @@ -1,6 +1,6 @@ export const level1Mice = [ // First 30 seconds — Setup Time (no mice) - { time: 5, type: 'bossMouse', row: 2 }, + // { time: 5, type: 'basicMouse', row: 2 }, // First minute (30 - 89) — Basic Mice only { time: 30, type: 'basicMouse', row: 2 }, diff --git a/level/WinLose.js b/level/WinLose.js new file mode 100644 index 0000000..37797a5 --- /dev/null +++ b/level/WinLose.js @@ -0,0 +1,17 @@ +const endingOverlay = document.getElementById('endingOverlay'); +const endingText = document.getElementById('endingText'); + +const endingMessage = { + win: "Nice job! The Cheese Feast is safe!", + lose: "Oh no! The mice crashed the Cheese Feast!
Give it another shot! (whiskers crossed)" +} + +export function showWinningScreen() { + endingText.innerHTML = endingMessage.win; + endingOverlay.style.display = 'flex'; +} + +export function showLosingScreen() { + endingText.innerHTML = endingMessage.lose; + endingOverlay.style.display = 'flex'; +} \ No newline at end of file diff --git a/sketch.js b/sketch.js index 03e7d01..ff4fa04 100644 --- a/sketch.js +++ b/sketch.js @@ -4,7 +4,7 @@ import { GameScene } from './GameScene.js'; export let mgr; const gameParent = document.getElementById('gameFrame'); const startButton = document.getElementById('startButton'); -export let startPageAni, robotVacuum, gameBackground; +export let startPageAni; export const imageAssets = {}; export const catImages = {}; export const catAnimation = {}; @@ -16,14 +16,12 @@ function preload() { width: 1440, height: 1024, frames: 5 }); startPageAni.frameDelay = 10; - robotVacuum = loadImage('assets/robot_vacuum.png'); - gameBackground = loadImage('assets/gamebg3.png'); imageAssets.cheese = loadImage('assets/cheese.png'); imageAssets.yarn = loadImage('assets/yarn.png'); imageAssets.snowball = loadImage('assets/snowball.png'); imageAssets.robotVacuum = loadImage('assets/robot_vacuum.png'); - imageAssets.gameBackground = loadImage('assets/gamebg3.png'); + imageAssets.gameBackground = loadImage('assets/game_background.png'); imageAssets.mouse = loadImage('assets/mouse.png'); imageAssets.redExplosion = loadImage('assets/red_explosion.png'); imageAssets.grayExplosion = loadImage('assets/gray_explosion.png'); @@ -86,6 +84,11 @@ menuButton.addEventListener('click', function (event) { mgr.showScene(StartScene); }); +quitButton.addEventListener('click', function (event) { + event.preventDefault(); + mgr.showScene(StartScene); +}); + document.querySelectorAll('.catButton').forEach(button => { button.addEventListener('click', () => { if (selectedCatType === button.id) {