Skip to content

Commit 8ff8d13

Browse files
Merge pull request #596 from siri-004/feature/snake-game-pause-resume
Feature: Add pause/resume functionality to snake game
2 parents 5e0f686 + 49d132d commit 8ff8d13

2 files changed

Lines changed: 98 additions & 64 deletions

File tree

web-app/js/projects.js

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,17 @@
1-
// Project Registry
1+
// Project Registry
22
// Each project's HTML and logic lives in its own file under js/projects/
33

44
//To Prevent duplicate intialisation
55
let activeProject=null;
66

77
function getProjectHTML(projectName) {
88
const projects = {
9-
'rock-paper-scissor': getRockPaperScissorHTML(),
10-
'dice-rolling': getDiceRollingHTML(),
11-
'coin-flip': getCoinFlipHTML(),
12-
'number-guessing': getNumberGuessingHTML(),
13-
'hangman': getHangmanHTML(),
14-
'flames': getFlamesHTML(),
15-
'emoji-memory': getEmojiMemoryGameHTML(),
16-
'fibonacci': getFibonacciHTML(),
17-
'progression-recognizer': getProgressionRecognizerHTML(),
18-
'pascal-triangle': getPascalTriangleHTML(),
19-
'armstrong': getArmstrongHTML(),
20-
'calculator': getCalculatorHTML(),
21-
'collatz': getCollatzHTML(),
22-
'prime-analyzer': getPrimeAnalyzerHTML(),
23-
'projectile-motion': getProjectileMotionHTML(),
24-
'coordinate-polar-transform': getCoordinatePolarTransformHTML(),
25-
'derivative-calculator': getDerivativeCalculatorHTML(),
26-
'morse-code': getMorseCodeHTML(),
27-
'tower-of-hanoi': getTowerOfHanoiHTML(),
28-
'number-converter': getNumberConverterHTML(),
29-
'typing-speed-tester': getTypingSpeedTesterHTML(),
30-
'snake-game': getsnakeGameHTML(),
31-
'password-forge': getPasswordForgeHTML(),
32-
'whack-a-mole': getWhackaMoleHTML(),
33-
'tic-tac-toe': () => getTicTacToeHTML(),
349
'rock-paper-scissor': () => getRockPaperScissorHTML(),
3510
'dice-rolling': () => getDiceRollingHTML(),
3611
'coin-flip': () => getCoinFlipHTML(),
37-
'Blackjack-21': () => getBlackjackHTML(),
3812
'number-guessing': () => getNumberGuessingHTML(),
3913
'hangman': () => getHangmanHTML(),
40-
'word-scramble': () => getWordScrambleHTML(),
4114
'flames': () => getFlamesHTML(),
42-
'dots-boxes': () => getDotsBoxesHTML(),
4315
'emoji-memory': () => getEmojiMemoryGameHTML(),
4416
'fibonacci': () => getFibonacciHTML(),
4517
'progression-recognizer': () => getProgressionRecognizerHTML(),
@@ -57,13 +29,17 @@ function getProjectHTML(projectName) {
5729
'typing-speed-tester': () => getTypingSpeedTesterHTML(),
5830
'snake-game': () => getSnakeGameHTML(),
5931
'password-forge': () => getPasswordForgeHTML(),
60-
'math-quiz': () => getMathQuizHTML(),
6132
'whack-a-mole': () => getWhackaMoleHTML(),
33+
'tic-tac-toe': () => getTicTacToeHTML(),
34+
'blackjack-21': () => getBlackjackHTML(),
35+
'word-scramble': () => getWordScrambleHTML(),
36+
'dots-boxes': () => getDotsBoxesHTML(),
37+
'math-quiz': () => getMathQuizHTML(),
6238
'simon-says': () => getSimonSaysHTML(),
6339
'spot-the-difference': () => getSpotTheDifferenceHTML(),
6440
'flappy-game': () => getFlappyGameHTML(),
6541
'2048-game': () => get2048GameHTML(),
66-
"productive-pet": () => getProductivePetHTML(),
42+
'productive-pet': () => getProductivePetHTML(),
6743
'color-palette': () => getColorPaletteHTML(),
6844
};
6945

web-app/js/projects/snake.js

Lines changed: 91 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ function getSnakeGameHTML() {
1717
<div class="game-area">
1818
<div id="canvas-wrapper" class="ui-canvas-frame">
1919
<canvas id="snakeCanvas" width="600" height="400"></canvas>
20+
<div id="pause-overlay" class="hidden">
21+
<h1>⏸ PAUSED</h1>
22+
</div>
2023
2124
<div id="game-over-overlay" class="hidden">
2225
<h1>GAME OVER!!</h1>
@@ -39,6 +42,7 @@ function getSnakeGameHTML() {
3942
4043
<div class="button-group">
4144
<button id="startGameBtn" class="btn-primary">Start Game</button>
45+
<button id="pauseGameBtn" class="btn-primary">Pause</button>
4246
<button id="restartSnakeBtn" class="btn-primary">Restart Game</button>
4347
</div>
4448
<div class="instruction-box">
@@ -171,6 +175,23 @@ function getSnakeGameHTML() {
171175
padding: 12px 25px;
172176
cursor: pointer;
173177
}
178+
#pause-overlay {
179+
position: absolute;
180+
top: 0;
181+
left: 0;
182+
width: 100%;
183+
height: 100%;
184+
background: rgba(0,0,0,0.6);
185+
display: flex;
186+
justify-content: center;
187+
align-items: center;
188+
z-index: 9;
189+
color: white;
190+
}
191+
192+
#pause-overlay h1 {
193+
font-size: 3rem;
194+
}
174195
</style>
175196
`;
176197
}
@@ -181,26 +202,29 @@ let speed = 9; // System baseline operational configuration state
181202
let scoreMultiplier = 2; // Baseline multiplier scalar state
182203
let score = 0;
183204
let lastPaintTime = 0;
205+
let isPaused = false;
184206
let snakeArr = [{ x: 13, y: 10 }];
185207
let food = { x: 6, y: 7 };
186208

187209
// Profile configuration mapping matrices
188210
const CONFIG_DIFFICULTY = {
189-
easy: { speed: 5, multiplier: 1 },
190-
medium: { speed: 9, multiplier: 2 },
191-
hard: { speed: 14, multiplier: 3 }
211+
easy: { speed: 5, multiplier: 1 },
212+
medium: { speed: 9, multiplier: 2 },
213+
hard: { speed: 14, multiplier: 3 }
192214
};
193215

194216
function main(ctime) {
195217
const canvas = document.getElementById('snakeCanvas');
196218
if (!canvas) return; // Exit loop if the game modal has been closed
197-
219+
198220
window.requestAnimationFrame(main);
199221
if ((ctime - lastPaintTime) / 1000 < 1 / speed) {
200222
return;
201223
}
202224
lastPaintTime = ctime;
203-
gameEngine();
225+
if (!isPaused) {
226+
gameEngine();
227+
}
204228
}
205229

206230
function isCollide(snake) {
@@ -244,10 +268,10 @@ function gameEngine() {
244268
direction = { x: 0, y: 0 };
245269
document.getElementById('final-score').innerHTML = score;
246270
document.getElementById('game-over-overlay').classList.remove('hidden');
247-
271+
248272
// Execute persistent local evaluations
249273
checkAndSaveHighScore();
250-
274+
251275
// Restore controls visibility states
252276
const selector = document.getElementById('difficultySelect');
253277
if (selector) selector.disabled = false;
@@ -297,44 +321,73 @@ function restartGame() {
297321
direction = { x: 1, y: 0 };
298322
snakeArr = [{ x: 13, y: 10 }];
299323
score = 0;
324+
isPaused = false;
325+
326+
const pauseOverlay = document.getElementById('pause-overlay');
327+
if (pauseOverlay) {
328+
pauseOverlay.classList.add('hidden');
329+
}
330+
331+
const pauseBtn = document.getElementById('pauseGameBtn');
332+
if (pauseBtn) {
333+
pauseBtn.textContent = 'Pause';
334+
}
300335
document.getElementById('score').innerHTML = score;
301336
food = { x: 6, y: 7 };
337+
338+
}
339+
function togglePause() {
340+
const pauseOverlay = document.getElementById('pause-overlay');
341+
const pauseBtn = document.getElementById('pauseGameBtn');
342+
343+
// Don't pause before game starts
344+
if (direction.x === 0 && direction.y === 0) return;
345+
346+
isPaused = !isPaused;
347+
348+
if (isPaused) {
349+
pauseOverlay.classList.remove('hidden');
350+
pauseBtn.textContent = 'Resume';
351+
} else {
352+
pauseOverlay.classList.add('hidden');
353+
pauseBtn.textContent = 'Pause';
354+
}
302355
}
303356

304357
// Initialize execution listeners
305358
function initSnakeGame() {
306359
window.requestAnimationFrame(main);
307-
360+
308361
// Set initial historic rendering metrics
309362
updateBestScoreUI();
310363
function restartGame() {
311-
// Hide game over overlay
312-
document.getElementById('game-over-overlay').classList.add('hidden');
364+
// Hide game over overlay
365+
document.getElementById('game-over-overlay').classList.add('hidden');
313366

314-
// Reset snake
315-
snakeArr = [{ x: 13, y: 10 }];
367+
// Reset snake
368+
snakeArr = [{ x: 13, y: 10 }];
316369

317-
// Reset score
318-
score = 0;
319-
document.getElementById('score').innerHTML = score;
370+
// Reset score
371+
score = 0;
372+
document.getElementById('score').innerHTML = score;
320373

321-
// Reset direction and start moving
322-
direction = { x: 1, y: 0 };
374+
// Reset direction and start moving
375+
direction = { x: 1, y: 0 };
323376

324-
// Generate new food
325-
food = {
326-
x: Math.round(2 + (16 - 2) * Math.random()),
327-
y: Math.round(2 + (16 - 2) * Math.random())
328-
};
377+
// Generate new food
378+
food = {
379+
x: Math.round(2 + (16 - 2) * Math.random()),
380+
y: Math.round(2 + (16 - 2) * Math.random())
381+
};
329382

330-
// Re-enable difficulty selection before start
331-
if (selector) {
332-
selector.disabled = true;
333-
}
383+
// Re-enable difficulty selection before start
384+
if (selector) {
385+
selector.disabled = true;
386+
}
334387

335-
// Reset frame timing
336-
lastPaintTime = 0;
337-
}
388+
// Reset frame timing
389+
lastPaintTime = 0;
390+
}
338391

339392
// Map difficulty listener parameters
340393
const selector = document.getElementById('difficultySelect');
@@ -353,7 +406,7 @@ function initSnakeGame() {
353406
});
354407

355408
document.getElementById('restartSnakeBtn').addEventListener('click', restartGame);
356-
409+
document.getElementById('pauseGameBtn').addEventListener('click', togglePause);
357410
document.getElementById('overlayRestartBtn').addEventListener('click', restartGame);
358411

359412
window.addEventListener('keydown', e => {
@@ -363,7 +416,12 @@ function initSnakeGame() {
363416
selector.disabled = true;
364417
}
365418
}
366-
419+
if (e.code === 'Space' || e.key.toLowerCase() === 'p') {
420+
e.preventDefault();
421+
togglePause();
422+
return;
423+
}
424+
if (isPaused) return;
367425
switch (e.key) {
368426
case "ArrowUp": if (direction.y !== 1) { direction.x = 0; direction.y = -1; } break;
369427
case "ArrowDown": if (direction.y !== -1) { direction.x = 0; direction.y = 1; } break;
@@ -386,10 +444,10 @@ function initSnakeGame() {
386444
e.preventDefault();
387445
let touchEndX = e.changedTouches[0].screenX;
388446
let touchEndY = e.changedTouches[0].screenY;
389-
447+
390448
let dx = touchEndX - touchStartX;
391449
let dy = touchEndY - touchStartY;
392-
450+
393451
if (Math.abs(dx) > Math.abs(dy)) {
394452
if (dx > 30 && direction.x !== -1) { direction.x = 1; direction.y = 0; }
395453
else if (dx < -30 && direction.x !== 1) { direction.x = -1; direction.y = 0; }

0 commit comments

Comments
 (0)