I’m making a simple 2d endless runner game for a project. The game is simple,
- it has one infinitely repeating obstacle,
- it is supposed to have 3 difficulty levels that the player can choose.
- The score starts at 0
- the score updates when a collision is detected above the obstacle
- ends the game when the player hits the obstacle.
(thanks to kikon for helping i modified your code a little)
I do have some other problems with my code I need to fix as well, but all help is appreciated. So if any of you seeing this spot any extra errors or questionable logic then please let me know.
Very sorry if it’s just a small syntax error I missed. Here’s the code:
const player = document.getElementById('player');
const obstacle = document.getElementById('obstacle');
const scoreValue = document.getElementById('score-value');
let score = 0;
let gameRunning = false;
let hasJumpedOver = false;
function updateScore() {
score++;
scoreValue.innerText = score;
}
function gameOver() {
gameRunning = false;
alert('Game Over! Your score is ' + score);
}
function moveObstacle() {
if (!gameRunning) return;
let obstaclePosition = parseInt(window.getComputedStyle(obstacle).getPropertyValue('right')) + speed;
if (obstaclePosition < window.innerWidth) {
obstacle.style.right = `${obstaclePosition + speed}px`;
} else {
obstacle.style.right = '0';
hasJumpedOver = false; // Reset this flag when the obstacle resets
}
detectCollision();
}
function jump() {
if (!player.classList.contains('jump')) {
player.classList.add('jump');
setTimeout(() => {
player.classList.remove('jump');
}, 500);
}
}
function detectCollision() {
let playerRect = player.getBoundingClientRect();
let obstacleRect = obstacle.getBoundingClientRect();
if (playerRect.left < obstacleRect.right &&
playerRect.right > obstacleRect.left &&
playerRect.top < obstacleRect.bottom &&
playerRect.bottom > obstacleRect.top) {
// Collision detected, end the game
gameOver();
} else if (playerRect.right < obstacleRect.left && !hasJumpedOver) {
// Player has successfully jumped over the obstacle
hasJumpedOver = true;
updateScore();
}
}
document.addEventListener('keydown', (event) => {
if (event.code === 'Space') {
jump();
}
});
setInterval(moveObstacle, 20);
const difficultyButtons = document.querySelectorAll('#difficulty-buttons button');
difficultyButtons.forEach(button => {
button.addEventListener('click', function() {
// remove selected class from all buttons
difficultyButtons.forEach(btn => {
btn.classList.remove('button-selected');
});
// add the selected class to clicked button
this.classList.add('button-selected');
});
});
// misc code for fade in and out on same page
document.getElementById('start-button').addEventListener('click', function() {
document.getElementById('game-container').classList.add('visible');
document.getElementById('main-page').classList.add('fade-out-up');
gameRunning = true; // game starts when start button gets clicked
});
body {
margin: 0;
overflow: hidden;
}
#main-page {
z-index: 1;
}
#game-container {
position: absolute;
width: 100%;
height: 100vh;
opacity: 0;
transition: opacity 2s ease-in-out;
background-image: url('background.jpg');
background-repeat: no-repeat;
background-size: big;
background-position: center center;
}
/*for game container fade in */
#game-container.visible {
opacity: 1;
}
/*stuff for main elements of the game*/
#player {
position: absolute;
bottom: 0;
left: 50px;
width: 50px;
height: 50px;
background-color: pink;
}
#obstacle {
position: absolute;
bottom: 0;
right: 0;
width: 50px;
height: 50px;
background-color: grey;
}
#score {
position: relative;
top: 15px;
left: 10px;
font-size: 25px;
text-align: center;
font-family: sans-serif;
color: aliceblue;
}
/*for jump*/
.jump {
transform: translateY(-100px);
}
/*for the main page div to fade out*/
.fade-out-up {
animation: fadeOutUp 1s forwards;
}
@keyframes fadeOutUp {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-20px);
}
}
/*for difficulty selectors */
.button-selected {
transform: scale(0.9);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Endless Runner Game</title>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="w3.css">
</head>
<body>
<div id="main-page" class="w3-container">
<h1 class="">Cube Runner 2D</h1>
<p>Cube Runner 2D is an endless 2D runner game in where the object of the game is to get your score as high as possible before you run into the obstacle (you die).
</p>
<p>The game has <span style="font-weight: bold;">Three Difficulty levels </span>you can choose from below,
<span class="w3-text-green" style="font-weight: bold;">Easy, </span>
<span class="w3-text-yellow" style="font-weight: bold;">Medium, </span>and
<span class="w3-text-red" style="font-weight: bold;">Hard.</span></p>
<div id="difficulty-buttons">
<button onclick="setDifficulty('easy')" class="w3-green">Easy</button>
<button onclick="setDifficulty('medium')" class="w3-yellow">Medium</button>
<button onclick="setDifficulty('hard')" class="w3-red">Hard</button>
</div>
<button id="start-button" class="w3-display-middle">Start Game</button>
</div>
<div id="game-container">
<div id="player"></div>
<div id="obstacle"></div>
<div id="score">Score: <span id="score-value">-1</span></div>
<script src="script.js"></script>
</div>
</body>
</html>
2
Answers
There are a lot of issues which I won’t get into for the sake of brevity, but let’s try to solve the ones that might be blocking you so that you can continue learning:
speed
in your game loopmoveObstacle()
setDifficulty()
you’re trying to use in yourindex.html
is not definedTry this:
As others indicated a number of issues with undeclared variable/values, issues with the start/stop/restart code; speed is still messed up here and does not reset properly IF you were to choose a new one etc.
Here I simply "made it work" albeit with probably terrible UI/usability etc.
I placed all your game specific global variables in a
game
namespace object as properties and then usedthis
to reference them in the functions. The other parts could also be placed within this but I left that our for you as a learning exercise.I also added a simple message function to show what was happening as it occurred a bit.