Home > other >  The snake remembers the last key input after the game restarts - Javascript
The snake remembers the last key input after the game restarts - Javascript

Time:10-05

I'm kind of a novice in the Javascript field, and I'm working on a snake game, where I've been facing an unusual problem: after I restart the game by pressing the restart button, drawn on the canvas board, the snake starts to move by itself, remembering the last key input before game over.

Remember that when you start the game for the first time, the snake begins moving by pressing any key, and the problem after the game reset occurred after I fixed the event listener trigger(when pressing too fast, the snake runs into itself from reverse direction).

I will attach below the code to showcase what I've been working on so far, thanks a lot for your time!

The HTML code

    <!-- the snake game section -->
<div  data-hover="Press any key to start">
    <div >
        Score: <p id="score-number">0</p>
    </div>
<canvas id="game-board">    
</canvas>
</div>

The JS code

const gameBoard = document.getElementById("game-board");
const context = gameBoard.getContext("2d");

let rows = 20;
let cols = 20;

let gridBoard = 20; // per row 30 grids
let gameOver = false;
let snakeSize = 1; // initializing snake's body size

let x = new Array(900);
let y = new Array(900);

gameBoard.height = rows * gridBoard;
gameBoard.width = cols * gridBoard;


for (let i = 0; i < snakeSize; i  ){
    x[i] = 40 - i*20
    y[i] = 40 //the head of the snake
}


// to come up with a random position for the apple

let eatenApple = true;
let appleX;
let appleY;

let score = 0;
let scoreNumber = document.getElementById("score-number");

const path = new Path2D(); // for the reset button

function mainGame(){

    //when the snake eats the apple and grows
    eatApple();

    //movement validation and check the collision
    movementValidation();

    // keep record of head&body in canvas for movement
    move(); // or change the snake position 

    //to display the snake's head, body, and the apple
    display();

    setTimeout(mainGame, 150);

}

function display(){
    context.clearRect(0,0, gameBoard.width, gameBoard.height);
    if(gameOver){
        isGameOver();
        } else {
            //apple
            if(eatenApple){
                appleRandomPlace();
                eatenApple = false;
            }

            //the apple's head
            context.beginPath()
            context.fillStyle = "red";
            context.fillRect(appleX, appleY, gridBoard / 1, gridBoard / 1);
            context.closePath();


            for (let i = 0; i < snakeSize; i  ){
            //the snake's head
            if(i === 0){
                const snake_head = new Path2D();
                context.fillStyle = "#86626E";
                snake_head.rect(x[0], y[0], gridBoard / 1, gridBoard / 1);
                context.fill(snake_head);
                
            
            } else {
                //the snake's body
                const snake_body = new Path2D();
                context.fillStyle = "#201335";
                context.strokeStyle = "#fff";
                context.lineWidth = 3;
                snake_body.rect(x[i], y[i], gridBoard / 1, gridBoard / 1);
                context.fill(snake_body);
                context.stroke(snake_body);
            }
        }
    }
}


function isGameOver(){
    //game over text
    context.fillStyle = "black";
    context.textBaseline = "middle";
    context.textAlign = "center";
    context.font = "35px Adonay";
    context.fillText("game over", gameBoard.width / 2, gameBoard.height / 2);

    // the reset button and text
    path.rect(150,240,100,40); //x, y, width, height
    path.closePath();
    context.fillStyle = "black";
    context.textBaseline = "middle";
    context.textAlign = "center";
    context.font = "20px Adonay";
    context.strokeStyle = "#0B1D51";    
    context.lineWidth = 1;
    context.fillText("restart", 200, 261, 111, 40);
    context.stroke(path);
}


function eatApple(){
    if(x[0] === appleX && y[0] === appleY){
        snakeSize  
        eatenApple = true;
        score  = 1;
        scoreNumber.innerText = score;
    }

}

function appleRandomPlace(){
    appleX = Math.floor(Math.random() * (cols - 5)) * gridBoard   20;
    appleY = Math.floor(Math.random() * (rows - 5)) * gridBoard   20;

}

let direction;
let nextDirection;

document.addEventListener("keydown", function(event){

    if(event.keyCode === 38 && direction !== "down") {
        nextDirection = "up";
    }

    else if(event.keyCode === 40 && direction !== "up"){
        nextDirection = "down";
    }

    else if(event.keyCode === 37 && direction !== "right"){
        nextDirection = "left";
    }

    else if(event.keyCode === 39 && direction !== "left"){
        nextDirection = "right";
    }

});


function movementValidation(){

    // snake's collision with the walls
    if(y[0] >= gameBoard.height / 1.1) {
        gameOver = true;

    } else if(y[0] < 1) {
        gameOver = true;

    } else if(x[0] >= gameBoard.width / 1.1) {
        gameOver = true;

    } else if(x[0] < 1) {
        gameOver = true;
    }

    //x[0] and y[0] represent the head of the snake

    // snake eats its own body
    for (let i = 1; i < snakeSize; i =1){
        if(x[0] === x[i] && y[0] === y[i]){
            gameOver = true;
        }
    }
}

function move(){
    // for snake's body
    for (let i = snakeSize; i > 0; i--){
        x[i] = x[(i-1)];
        y[i] = y[(i-1)];
    }

    // for snake's head

            if(nextDirection === "left"){
                x[0] -= gridBoard;
            }
        
            else if(nextDirection === "right"){
                x[0]  = gridBoard;
            }
        
            else if(nextDirection === "up"){
                y[0] -= gridBoard;
            }
        
            else if(nextDirection === "down"){
                y[0]  = gridBoard;
            }

            direction = nextDirection;

        }
    


        function buttonReset(gameBoard, event){
            const rect = gameBoard.getBoundingClientRect();
            const x = event.clientX - rect.left;
            const y = event.clientY - rect.top;
            return {x:x, y:y};
        }


document.addEventListener("click", function (e){
    const x_y = buttonReset(gameBoard, e);
    if(context.isPointInPath(path, x_y.x, x_y.y)){

    gameOver = false;
    snakeSize = 1; // initializing snake's body size
   
    x = new Array(900);
    y = new Array(900);
   
   gameBoard.height = rows * gridBoard;
   gameBoard.width = cols * gridBoard;
   
   for (let i = 0; i < snakeSize; i  ){
       x[i] = 40 - i*10
       y[i] = 40 //the head of the snake
   }
   
    eatenApple = false;
    appleX;
    appleY;
   
    score = 0;
    scoreNumber.innerText = score;
    
    direction;
    nextDirection;

    display();
    move();
    eatApple();
    movementValidation();

}

}, false);

mainGame();

CodePudding user response:

Reset the movement-related variables at the start of your "new game" function, where you're setting gameOver = false and so on.

direction = undefined;
nextDirection = undefined;
  • Related