Webbserver - Love Blomberg

Show sourcecode

The following files exists in this folder. Click to view.

public_html/gamla-kurser/webbutv2/projekt/snake/js/

snake.js
snake.sync-conflict-20250925-184038-H7ZHIM2.js

snake.sync-conflict-20250925-184038-H7ZHIM2.js

294 lines UTF-8 Windows (CRLF)
// Board
var blockSize = 25;
var rows = 18;
var cols = 18;
const board = document.getElementById("board");
const ctx = board.getContext("2d"); // Drawing

// Knappar
const startButton = document.getElementById("startButton");

// Ormens huvud
var snakeX = blockSize * 5;
var snakeY = blockSize * 5;

// Ormens riktning
var velocityX = 0;
var velocityY = 0;

var snakeBody = [];

// Mat koordinater
var foodX;
var foodY;

var isPaused = true;
var gameOver = false;
var directionChanged = false; // Riktningen ändras

const levels = ["forest", "city", "hell"];
var currentLevel = levels[0];
const levelText = document.getElementById("levelText");

const scoreBoard = document.getElementById("scoreBoard");
// Score
var currentScore = 0;
var highScore = 0;

var blocks = [];

const cityBackground = new Image();

cityBackground.src = './assets/city.jpg';  // Make sure this path is correct

// Körs när sidan laddas
window.onload = function () {
    board.height = rows * blockSize;
    board.width = cols * blockSize;
    // Rita spelplan
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, board.width, board.height);

    startButton.addEventListener("click", toggleGame);

    placeFood();
    document.addEventListener("keydown", changeDirection);

    //velocityX = 1
    updateScoreboard();
}

function updateScoreboard() {
    // Load highscore from localStorage if available
    highScore = localStorage.getItem("snakeHighScore") || 0;
    
    // Update the scoreboard HTML
    scoreBoard.innerHTML = `
        <p>Score: ${currentScore}</p>
        <p>High Score: ${highScore}</p>
    `;
}

function toggleGame() {
    if (isPaused == true) {
        isPaused = false;
        startButton.innerHTML = "Pause";
        // Spelets main loop
        gameLoop = setInterval(update, 1000 / 10);
    }
    else {
        isPaused = true;
        startButton.innerHTML = "Start";
        clearInterval(gameLoop);
    }
}

function update() {
    if (gameOver) {
        restart();
    }

    // Reset direction change flag at the beginning of each update
    directionChanged = false;

    if (currentLevel == "forest") {
        forest();
    } else if (currentLevel == "city") {
        city();
    } else if (currentLevel == "hell") {
        hell();
    } else {
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, board.width, board.height);
    }

    // Rita mat
    ctx.fillStyle = "red";
    ctx.fillRect(foodX, foodY, blockSize, blockSize);

    // Om snake huvud och mat har samma koordinat, ät maten
    if (snakeX == foodX && snakeY == foodY) {
        snakeBody.push([foodX, foodY]);
        placeFood();

        currentScore++;

        if (currentScore > highScore) {
            highScore = currentScore;
            localStorage.setItem("snakeHighScore", highScore);
        }

        updateScoreboard();

        if (currentLevel === "city") {
            spawnBlock();
        }

        // Level up
        // if (snakeBody.length === 5 && currentLevel === "forest") {
        //     currentLevel = "city";
        // } else if (snakeBody.length === 10 && currentLevel === "city") {
        //     currentLevel = "hell";
        // }
    }

    // Kollision med blocks
    if (currentLevel === "city") {
        for (let i = 0; i < blocks.length; i++) {
            if (snakeX === blocks[i][0] && snakeY === blocks[i][1]) {
                gameOver = true;
                alert("Game Over! You hit a block!");
            }
        }
    }

    levelText.innerHTML = "Level: " + currentLevel;

    // Rör kroppen med huvudet
    for (let i = snakeBody.length - 1; i > 0; i--) {
        snakeBody[i] = snakeBody[i - 1];
    }
    if (snakeBody.length) {
        snakeBody[0] = [snakeX, snakeY];
    }

    // Rita snake
    ctx.fillStyle = "rgb(0, 180, 255)";
    snakeX += velocityX * blockSize;
    snakeY += velocityY * blockSize;
    ctx.fillRect(snakeX, snakeY, blockSize, blockSize);
    for (let i = 0; i < snakeBody.length; i++) {
        // Calculate color based on position in snake body
        // Gradually decrease blue and green components as we move toward tail
        let blueValue = Math.max(0, 180 - (i * 10));
        let greenValue = Math.max(0, 180 - (i * 4));
        
        ctx.fillStyle = `rgb(0, ${greenValue}, ${blueValue})`;
        ctx.fillRect(snakeBody[i][0], snakeBody[i][1], blockSize, blockSize);
    }

    // Gave over
    // Krocka med bounds
    if (snakeX < 0 || snakeX > cols * blockSize - 1 || snakeY < 0 || snakeY > rows * blockSize - 1) {
        gameOver = true;
        alert("Game Over!");
    }
    // Krocka med sig själv
    for (let i = 0; i < snakeBody.length; i++) {
        if (snakeX == snakeBody[i][0] && snakeY == snakeBody[i][1]) {
            gameOver = true;
            alert("Game Over!");
        }
    }
}

// Ändra riktning på ormen
function changeDirection(e) {
    // Ändra endast rikting en gång per frame
    if (directionChanged) {
        return;
    }

    if ((e.code == "ArrowUp" || e.code == "KeyW") && velocityY != 1) {
        velocityX = 0;
        velocityY = -1;
        directionChanged = true;
    }
    else if ((e.code == "ArrowDown" || e.code == "KeyS") && velocityY != -1) {
        velocityX = 0;
        velocityY = 1;
        directionChanged = true;
    }
    else if ((e.code == "ArrowLeft" || e.code == "KeyA") && velocityX != 1) {
        velocityX = -1;
        velocityY = 0;
        directionChanged = true;
    }
    else if ((e.code == "ArrowRight" || e.code == "KeyD") && velocityX != -1) {
        velocityX = 1;
        velocityY = 0;
        directionChanged = true;
    }
}

// Placerar ut mat slumpmässigt
function placeFood() {
    foodX = Math.floor(Math.random() * cols) * blockSize;
    foodY = Math.floor(Math.random() * rows) * blockSize;
}

// Placerar ut blocks slumpmässigt
function spawnBlock() {
    // Generate random position
    let blockX = Math.floor(Math.random() * cols) * blockSize;
    let blockY = Math.floor(Math.random() * rows) * blockSize;
    
    // Make sure block doesn't spawn on snake or food
    let validPosition = false;
    while (!validPosition) {
        validPosition = true;
        
        // Check if block would spawn on food
        if (blockX === foodX && blockY === foodY) {
            validPosition = false;
        }
        
        // Check if block would spawn on snake head
        if (blockX === snakeX && blockY === snakeY) {
            validPosition = false;
        }
        
        // Check if block would spawn on snake body
        for (let i = 0; i < snakeBody.length; i++) {
            if (blockX === snakeBody[i][0] && blockY === snakeBody[i][1]) {
                validPosition = false;
                break;
            }
        }
        
        // If position is not valid, generate a new one
        if (!validPosition) {
            blockX = Math.floor(Math.random() * cols) * blockSize;
            blockY = Math.floor(Math.random() * rows) * blockSize;
        }
    }
    
    // Add block to blocks array
    blocks.push([blockX, blockY]);
}

// Starta om spelet
function restart() {
    currentScore = 0;
    snakeX = blockSize * 5;
    snakeY = blockSize * 5;
    velocityX = 0;
    velocityY = 0;
    snakeBody = [];
    blocks = [];
    placeFood();
    updateScoreboard();
    gameOver = false;
}

/// --- Levels --- ///

function forest() {
    ctx.fillStyle = "black";
    ctx.fillRect(0,0, board.width, board.height);
}

function city() {
    ctx.fillStyle = "darkGray";
    ctx.fillRect(0,0, board.width, board.height);

    // Rita blocks
    ctx.fillStyle = "white";
    for (let i = 0; i < blocks.length; i++) {
        ctx.fillRect(blocks[i][0], blocks[i][1], blockSize, blockSize);
    }
}

function hell() {

}