game init
This commit is contained in:
parent
bcb4594afa
commit
6b0fedfabf
3 changed files with 351 additions and 0 deletions
|
@ -14,6 +14,13 @@ public class GeneralWebController {
|
||||||
model.addAttribute("currentPage", "merge-pdfs");
|
model.addAttribute("currentPage", "merge-pdfs");
|
||||||
return "merge-pdfs";
|
return "merge-pdfs";
|
||||||
}
|
}
|
||||||
|
@GetMapping("/game")
|
||||||
|
@Hidden
|
||||||
|
public String gameForm(Model model) {
|
||||||
|
model.addAttribute("currentPage", "game");
|
||||||
|
return "game";
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/multi-tool")
|
@GetMapping("/multi-tool")
|
||||||
@Hidden
|
@Hidden
|
||||||
public String multiToolForm(Model model) {
|
public String multiToolForm(Model model) {
|
||||||
|
|
264
src/main/resources/static/js/game.js
Normal file
264
src/main/resources/static/js/game.js
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
|
||||||
|
const gameContainer = document.getElementById('game-container');
|
||||||
|
const player = document.getElementById('player');
|
||||||
|
const scoreElement = document.getElementById('score');
|
||||||
|
const levelElement = document.getElementById('level');
|
||||||
|
const livesElement = document.getElementById('lives');
|
||||||
|
const highScoreElement = document.getElementById('high-score');
|
||||||
|
|
||||||
|
|
||||||
|
let playerX = gameContainer.clientWidth / 2;
|
||||||
|
let playerY = 50;
|
||||||
|
let paused = false;
|
||||||
|
const fireRate = 200; // Time between shots in milliseconds
|
||||||
|
let lastProjectileTime = 0;
|
||||||
|
let lives = 3;
|
||||||
|
let highScore = localStorage.getItem('highScore') ? parseInt(localStorage.getItem('highScore')) : 0;
|
||||||
|
updateHighScore();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const keysPressed = {};
|
||||||
|
const pdfs = [];
|
||||||
|
const projectiles = [];
|
||||||
|
let score = 0;
|
||||||
|
let level = 1;
|
||||||
|
let pdfSpeed = 1;
|
||||||
|
let gameOver = false;
|
||||||
|
|
||||||
|
function handleKeys() {
|
||||||
|
if (keysPressed['ArrowLeft']) {
|
||||||
|
playerX -= 10;
|
||||||
|
}
|
||||||
|
if (keysPressed['ArrowRight']) {
|
||||||
|
playerX += 10;
|
||||||
|
}
|
||||||
|
if (keysPressed[' '] && !gameOver) {
|
||||||
|
const currentTime = new Date().getTime();
|
||||||
|
if (currentTime - lastProjectileTime >= fireRate) {
|
||||||
|
shootProjectile();
|
||||||
|
lastProjectileTime = currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updatePlayerPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('keydown', (event) => {
|
||||||
|
keysPressed[event.key] = true;
|
||||||
|
handleKeys();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keyup', (event) => {
|
||||||
|
keysPressed[event.key] = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function updatePlayerPosition() {
|
||||||
|
player.style.left = playerX + 'px';
|
||||||
|
player.style.bottom = playerY + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLives() {
|
||||||
|
livesElement.textContent = 'Lives: ' + lives;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHighScore() {
|
||||||
|
highScoreElement.textContent = 'High Score: ' + highScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function shootProjectile() {
|
||||||
|
const projectile = document.createElement('div');
|
||||||
|
projectile.classList.add('projectile');
|
||||||
|
projectile.style.backgroundColor = 'black';
|
||||||
|
projectile.style.width = '5px';
|
||||||
|
projectile.style.height = '10px';
|
||||||
|
projectile.style.left = playerX + 20 + 'px';
|
||||||
|
projectile.style.top = (gameContainer.clientHeight - playerY - 20) + 'px';
|
||||||
|
gameContainer.appendChild(projectile);
|
||||||
|
projectiles.push(projectile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function spawnPdf() {
|
||||||
|
const pdf = document.createElement('img');
|
||||||
|
pdf.src = 'images/file-earmark-pdf.svg';
|
||||||
|
pdf.classList.add('pdf');
|
||||||
|
pdf.style.left = Math.floor(Math.random() * (gameContainer.clientWidth - 50)) + 'px';
|
||||||
|
pdf.style.top = '0px';
|
||||||
|
gameContainer.appendChild(pdf);
|
||||||
|
pdfs.push(pdf);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetEnemies() {
|
||||||
|
pdfs.forEach((pdf) => gameContainer.removeChild(pdf));
|
||||||
|
pdfs.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function updateGame() {
|
||||||
|
if (gameOver || paused) return;
|
||||||
|
|
||||||
|
pdfs.forEach((pdf, pdfIndex) => {
|
||||||
|
const pdfY = parseInt(pdf.style.top) + pdfSpeed;
|
||||||
|
if (pdfY + 50 > gameContainer.clientHeight) {
|
||||||
|
gameContainer.removeChild(pdf);
|
||||||
|
pdfs.splice(pdfIndex, 1);
|
||||||
|
|
||||||
|
// Deduct 2 points when a PDF gets past the player
|
||||||
|
score -= 0;
|
||||||
|
updateScore();
|
||||||
|
|
||||||
|
// Decrease lives and check if game over
|
||||||
|
lives--;
|
||||||
|
updateLives();
|
||||||
|
if (lives <= 0) {
|
||||||
|
endGame();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pdf.style.top = pdfY + 'px';
|
||||||
|
|
||||||
|
// Check for collision with player
|
||||||
|
if (collisionDetected(player, pdf)) {
|
||||||
|
lives--;
|
||||||
|
updateLives();
|
||||||
|
resetEnemies();
|
||||||
|
if (lives <= 0) {
|
||||||
|
endGame();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function resetGame() {
|
||||||
|
playerX = gameContainer.clientWidth / 2;
|
||||||
|
playerY = 50;
|
||||||
|
updatePlayerPosition();
|
||||||
|
|
||||||
|
pdfs.forEach((pdf) => gameContainer.removeChild(pdf));
|
||||||
|
projectiles.forEach((projectile) => gameContainer.removeChild(projectile));
|
||||||
|
|
||||||
|
pdfs.length = 0;
|
||||||
|
projectiles.length = 0;
|
||||||
|
|
||||||
|
score = 0;
|
||||||
|
level = 1;
|
||||||
|
lives = 3;
|
||||||
|
pdfSpeed = 2;
|
||||||
|
gameOver = false;
|
||||||
|
|
||||||
|
updateScore();
|
||||||
|
updateLevel();
|
||||||
|
updateLives();
|
||||||
|
|
||||||
|
setTimeout(updateGame, 1000 / 60);
|
||||||
|
spawnPdfInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
projectiles.forEach((projectile, projectileIndex) => {
|
||||||
|
const projectileY = parseInt(projectile.style.top) - 10;
|
||||||
|
if (projectileY < 0) {
|
||||||
|
gameContainer.removeChild(projectile);
|
||||||
|
projectiles.splice(projectileIndex, 1);
|
||||||
|
} else {
|
||||||
|
projectile.style.top = projectileY + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let pdfIndex = 0; pdfIndex < pdfs.length; pdfIndex++) {
|
||||||
|
const pdf = pdfs[pdfIndex];
|
||||||
|
if (collisionDetected(projectile, pdf)) {
|
||||||
|
gameContainer.removeChild(pdf);
|
||||||
|
gameContainer.removeChild(projectile);
|
||||||
|
pdfs.splice(pdfIndex, 1);
|
||||||
|
projectiles.splice(projectileIndex, 1);
|
||||||
|
score = score + 10;
|
||||||
|
updateScore();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(updateGame, 1000 / 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function updateScore() {
|
||||||
|
scoreElement.textContent = 'Score: ' + score;
|
||||||
|
checkLevelUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function checkLevelUp() {
|
||||||
|
const newLevel = Math.floor(score / 100) + 1;
|
||||||
|
if (newLevel > level) {
|
||||||
|
level = newLevel;
|
||||||
|
levelElement.textContent = 'Level: ' + level;
|
||||||
|
pdfSpeed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function collisionDetected(a, b) {
|
||||||
|
const rectA = a.getBoundingClientRect();
|
||||||
|
const rectB = b.getBoundingClientRect();
|
||||||
|
return (
|
||||||
|
rectA.left < rectB.right &&
|
||||||
|
rectA.right > rectB.left &&
|
||||||
|
rectA.top < rectB.bottom &&
|
||||||
|
rectA.bottom > rectB.top
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function endGame() {
|
||||||
|
gameOver = true;
|
||||||
|
if (score > highScore) {
|
||||||
|
highScore = score;
|
||||||
|
localStorage.setItem('highScore', highScore);
|
||||||
|
updateHighScore();
|
||||||
|
}
|
||||||
|
alert('Game Over! Your final score is: ' + score);
|
||||||
|
resetGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let spawnPdfTimeout;
|
||||||
|
|
||||||
|
function spawnPdfInterval() {
|
||||||
|
if (gameOver || paused) {
|
||||||
|
clearTimeout(spawnPdfTimeout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spawnPdf();
|
||||||
|
spawnPdfTimeout = setTimeout(spawnPdfInterval, 1000 - level * 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePlayerPosition();
|
||||||
|
updateGame();
|
||||||
|
spawnPdfInterval();
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('visibilitychange', function() {
|
||||||
|
if (document.hidden) {
|
||||||
|
paused = true;
|
||||||
|
} else {
|
||||||
|
paused = false;
|
||||||
|
updateGame();
|
||||||
|
spawnPdfInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
80
src/main/resources/templates/game.html
Normal file
80
src/main/resources/templates/game.html
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html th:lang="${#locale.toString()}" th:lang-direction="#{language.direction}" xmlns:th="http://www.thymeleaf.org">
|
||||||
|
|
||||||
|
<th:block th:insert="~{fragments/common :: head(title=#{pageRemover.title})}"></th:block>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="page-container">
|
||||||
|
<div id="content-wrap">
|
||||||
|
<div th:insert="~{fragments/navbar.html :: navbar}"></div>
|
||||||
|
<br> <br>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="game-container-wrapper" style="position: relative;">
|
||||||
|
<div id="game-container">
|
||||||
|
<div id="score">Score: 0</div>
|
||||||
|
<div id="lives">Lives: 3</div>
|
||||||
|
<div id="level">Level: 1</div>
|
||||||
|
<div id="high-score">High Score: 0</div>
|
||||||
|
<img src="favicon.svg" class="player" id="player">
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
#game-container {
|
||||||
|
position: relative;
|
||||||
|
width: 800px;
|
||||||
|
height: 600px;
|
||||||
|
background-color: white;
|
||||||
|
margin: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.pdf, .player, .projectile {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
.pdf {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
.player {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
.projectile {
|
||||||
|
background-color: black !important;
|
||||||
|
width: 5px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
#score, #level, #lives,#high-score {
|
||||||
|
color: black;
|
||||||
|
font-family: sans-serif;
|
||||||
|
position: absolute;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
#score {
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
#level {
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
#lives {
|
||||||
|
top: 10px;
|
||||||
|
left: 190px;
|
||||||
|
}
|
||||||
|
#high-score {
|
||||||
|
top: 10px;
|
||||||
|
left: 290px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="js/game.js"></script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div th:insert="~{fragments/footer.html :: footer}"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
Reference in a new issue