Skip to content

Commit 3fb13e5

Browse files
author
jjteoh
committed
feat: add power-up
1 parent a3cf84e commit 3fb13e5

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

media/rat.png

526 Bytes
Loading

script.js

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,20 @@ const canvasContainer = document.querySelector(".canvas-container");
1212
const easterEggVideo = document.getElementById("easterEggVideo");
1313
const pausedMessageElement = document.getElementById("pausedMessage");
1414

15-
// --- Audio Elements ---
16-
const eatSound = new Audio('media/eat.mp3');
17-
const gameOverSound = new Audio('media/game-over.mp3');
18-
1915
// --- Game Constants ---
2016
const GRID_SIZE = 20; // Number of cells in the grid
2117
let CANVAS_WIDTH, CANVAS_HEIGHT;
2218
let CELL_SIZE;
19+
const POWER_UP_POINTS = 3;
20+
const EATER_EGG_TRIGGER = 50;
21+
22+
// --- Audio Elements ---
23+
const eatSound = new Audio('media/eat.mp3');
24+
const gameOverSound = new Audio('media/game-over.mp3');
25+
26+
// --- Image Elements ---
27+
const powerUpImage = new Image();
28+
powerUpImage.src = 'media/rat.png';
2329

2430
// --- Define color gradient start/end colors ---
2531
// Head has darker color and gradually becomes lighter towards the tail
@@ -29,10 +35,13 @@ const SNAKE_TAIL_COLOR_RGB = [134, 239, 172]; // Lighter Green (tailwind green-4
2935
const FOOD_COLOR = "#ef4444"; // Red (tailwind red-500)
3036
const BORDER_COLOR = "#555555"; // Slightly lighter border for contrast on white
3137
const INITIAL_SPEED_MS = 150;
38+
const MAX_SPEED_MS = 80;
39+
3240

3341
// --- Game State ---
3442
let snake = [];
3543
let food = { x: 0, y: 0 };
44+
let powerUp = null;
3645
let dx = 0;
3746
let dy = 0;
3847
let score = 0;
@@ -128,6 +137,21 @@ function drawFood() {
128137
ctx.strokeRect(food.x * CELL_SIZE, food.y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
129138
}
130139

140+
// Function to draw the power-up
141+
function drawPowerUp() {
142+
143+
// image must fit into the cell
144+
if (powerUp) {
145+
ctx.drawImage(
146+
powerUpImage,
147+
powerUp.x * CELL_SIZE,
148+
powerUp.y * CELL_SIZE,
149+
CELL_SIZE,
150+
CELL_SIZE
151+
);
152+
}
153+
}
154+
131155
function moveSnake() {
132156
if (!gameActive || isPaused) return;
133157

@@ -152,21 +176,34 @@ function moveSnake() {
152176
eatSound.play();
153177

154178
// Check for easter egg
155-
if (score === 100) { // Trigger at 100
179+
if (score === EATER_EGG_TRIGGER) {
156180
triggerEasterEgg();
157181
}
158182

159183
// create food at a new position
160184
generateFood();
161185

186+
// Generate power-up every 10 points
187+
if (score % 10 === 0) {
188+
generatePowerUp();
189+
}
190+
162191
// we increase the speed as the game progresses to make it more challenging
163192
// this can be achieved by reducing the interval time between each game loop
164193
// so that the snake get redrawn more frequently
165-
if (score % 5 === 0 && currentSpeed > 50) {
194+
if (score % 5 === 0 && currentSpeed > MAX_SPEED_MS) {
166195
currentSpeed -= 10;
196+
197+
console.log(currentSpeed)
167198
clearInterval(gameLoopInterval);
168199
gameLoopInterval = setInterval(gameLoop, currentSpeed);
169200
}
201+
} else if (powerUp && head.x === powerUp.x && head.y === powerUp.y) {
202+
// Handle power-up collection
203+
eatSound.play();
204+
score += POWER_UP_POINTS;
205+
scoreElement.textContent = `Score: ${score}`;
206+
powerUp = null; // Remove the power-up
170207
} else {
171208
// if the head did not hit the food, we remove the last part of the snake
172209
// making it look like the snake is moving forward
@@ -185,6 +222,20 @@ function generateFood() {
185222
food = { x: newFoodX, y: newFoodY };
186223
}
187224

225+
// Function to generate a power-up
226+
function generatePowerUp() {
227+
let newPowerUpX, newPowerUpY;
228+
do {
229+
newPowerUpX = Math.floor(Math.random() * GRID_SIZE);
230+
newPowerUpY = Math.floor(Math.random() * GRID_SIZE);
231+
} while (
232+
snake.some((part) => part.x === newPowerUpX && part.y === newPowerUpY) ||
233+
(food.x === newPowerUpX && food.y === newPowerUpY)
234+
);
235+
236+
powerUp = { x: newPowerUpX, y: newPowerUpY };
237+
}
238+
188239
function handleKeyDown(event) {
189240
// allow player to restart the game by pressing enter
190241
if (
@@ -281,6 +332,7 @@ function gameLoop() {
281332
}
282333
clearCanvas();
283334
drawFood();
335+
drawPowerUp();
284336
moveSnake();
285337
drawSnake();
286338
}
@@ -319,13 +371,19 @@ function startGame() {
319371
}
320372

321373
function endGame() {
374+
if(!gameOverElement.classList.contains("hidden")) {
375+
return; // Prevent multiple game over messages
376+
}
377+
322378
console.log("Game Over!");
323379
gameActive = false;
324380
clearInterval(gameLoopInterval);
325381
gameLoopInterval = null;
326382
finalScoreElement.textContent = score;
327383
gameOverElement.classList.remove("hidden");
328384
gameOverSound.play(); // Play game over sound effect
385+
powerUp = null;
386+
currentSpeed = INITIAL_SPEED_MS; // Reset speed for next game
329387
}
330388

331389
function showStartMessage() {
@@ -375,7 +433,6 @@ function showStartMessage() {
375433
function triggerEasterEgg() {
376434
// Pause the game
377435
gameActive = false;
378-
clearInterval(gameLoopInterval);
379436

380437
// Show and play the video
381438
easterEggVideo.classList.remove("hidden");
@@ -386,7 +443,6 @@ function triggerEasterEgg() {
386443
easterEggVideo.classList.add("hidden");
387444
// Resume the game
388445
gameActive = true;
389-
gameLoopInterval = setInterval(gameLoop, currentSpeed);
390446
};
391447
}
392448

@@ -433,6 +489,7 @@ window.addEventListener("resize", () => {
433489
} else if (gameActive) {
434490
clearCanvas(); // Clear with white
435491
drawFood();
492+
drawPowerUp(); // Draw the power-up
436493
drawSnake(); // Redraw gradient snake
437494
} else if (!gameOverElement.classList.contains("hidden")) {
438495
clearCanvas(); // Clear with white

0 commit comments

Comments
 (0)