Why doesn't my collision detection/update score work on my game?

53 views Asked by At

So I'm making a simple 2d endless runner like the chrome dino game for a small project. It's very basic and I want it to update the score by one each time the player successfully jumps over the obstacle.

When I tried to implement my collision detection t was supposed to detect the obstacle if the player missed it and either end the game (which i haven't done yet) or update the score. Here's the code.

const player = document.getElementById('player');
const obstacle = document.getElementById('obstacle');
const scoreValue = document.getElementById('score-value');
let score = 0

function updateScore() {
    score++;
    scoreValue.innerText = score;
}

function moveObstacle() {
    const speed = 5
    let obstaclePosition = parseInt(window.getComputedStyle(obstacle).getPropertyValue('right'));

    if (obstaclePosition < window.innerWidth) { 
        obstacle.style.right = `${obstaclePosition + speed}px`
    } else {
        obstacle.style.right = '0';
    }

    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, update the score
        updateScore();
    }
}

document.addEventListener('keydown', (event) => {
    if (event.code === 'Space') {
        jump();
    }
});

setInterval(moveObstacle, 20);
body {
    margin: 0;
    overflow: hidden;
}

#game-container { 
    position: relative;
    width: 100%;
    height: 100vh;
    background-color: #f0f0f0;
}

#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: gray;
}

#score { 
    position: absolute;
    top: 10px; 
    left: 10px;
    font-size: 20px;
}

.jump { 
    transform: translateY(-100px);
}
<!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">
</head>
<body>
    <div id="game-container">
        <div id="player"></div>
        <div id="obstacle"></div>
        <div id="score">Score: <span id="score-value">0</span></div>
        <script src="script.js"></script>
    </div>
</body>
</html>

1

There are 1 answers

0
kikon On

Your collision detection works fine. But you want to detect jumps, which should be defined geometrically by only the x coordinates overlapping and the y coordinates not overlapping.

So you have to slightly adjust the logic of your code, to separate x overlapping conditions form y overlapping. You should keep track of what's happening with these conditions, in boolean variables, so you avoid repeating the same actions during the same event. For instance, if a collision is detected, there could be no score update in that pass.

And you logic should take into consideration obstacle "passes" - a pass begins from the moment the obstacle is placed to the right and ends at the next moment it is placed to the right - in such a pass there will always be either a score increment, or a collision; thus all variables should be reset when the obstacle is reset to the right.

const player = document.getElementById('player');
const obstacle = document.getElementById('obstacle');
const scoreValue = document.getElementById('score-value');
const collisionsValue = document.getElementById('collisions-value');
let score = 0, collisions = 0;

function updateScore() {
    score++;
    scoreValue.innerText = score;
}

function updateCollisions() {
    collisions++;
    collisionsValue.innerText = collisions;
}


let jumpStarted = false, jumpFull = false, collision = false; 
function moveObstacle() {
    const speed = 5
    let obstaclePosition = parseInt(window.getComputedStyle(obstacle).getPropertyValue('right'));

    if (obstaclePosition < window.innerWidth) { 
        obstacle.style.right = `${obstaclePosition + speed}px`
    } else {
        obstacle.style.right = '0';
        if(jumpStarted && !collision && !jumpFull){
           // jumpFull failed to register for lack of space 
           updateScore();
        }
        // reset jump logic each time the obstacle is repositioned at right
        jumpStarted = false;
        jumpFull = false;
        collision = false;
    }

    detectCollision();
}

function jump() {
    if (!player.classList.contains('jump')) {
        player.classList.add('jump');

        setTimeout(() => {
             player.classList.remove('jump') 
        }, 500);
    }
}

function detectCollision() {
    if(collision || jumpFull){
      return;
    }
    let playerRect = player.getBoundingClientRect();
    let obstacleRect = obstacle.getBoundingClientRect();

    if (playerRect.left < obstacleRect.right &&
          playerRect.right > obstacleRect.left){
        if( playerRect.top < obstacleRect.bottom && 
            playerRect.bottom > obstacleRect.top){
          collision = true;
          updateCollisions();
          return;
        }
        jumpStarted = true;
    }
    else if(jumpStarted){
      jumpFull = true;
      updateScore();
    }
}

document.addEventListener('keydown', (event) => {
    if (event.code === 'Space') {
        jump();
    }
});

setInterval(moveObstacle, 20);
body {
    margin: 0;
    overflow: hidden;
}

#game-container { 
    position: relative;
    width: 100%;
    height: 100vh;
    background-color: #f0f0f0;
}

#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: gray;
}

#score { 
    position: absolute;
    top: 10px; 
    left: 10px;
    font-size: 20px;
}


.jump { 
    transform: translateY(-100px);
}
<!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">
</head>
<body>
    <div id="game-container">
        <div id="player"></div>
        <div id="obstacle"></div>
        <div id="score">Score: <span id="score-value">0</span>
        &nbsp; Collisions: <span id="collisions-value">0</span>
        </div>
        <script src="script.js"></script>
    </div>
</body>
</html>