Webbserver - Love Blomberg

Show sourcecode

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

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

cookie-clicker.js
fidget-spinner.js
snake.js

snake.js

338 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");
const musicButton = document.getElementById("musicButton");

// 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 musicPlayer = document.getElementById("musicPlayer");
var playing = true;

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);
  musicButton.addEventListener("click", toggleMusic)

  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>High Score: ${highScore}</p>
    <p>Score: ${currentScore}</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 toggleMusic() {
  if (playing == true) {
    musicPlayer.pause()
    musicButton.innerHTML = '🔇';
    playing = false;
  } else {
    musicPlayer.play()
    musicButton.innerHTML = '🔊';
    playing = true;
  }
}

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, 41, 74)";
  snakeX += velocityX * blockSize;
  snakeY += velocityY * blockSize;
  ctx.fillRect(snakeX, snakeY, blockSize, blockSize);
  
  for (let i = 0; i < snakeBody.length; i++) {
    // Calculate position in gradient (0 to 1)
    let gradientPosition = 1 - Math.min(i / Math.max(snakeBody.length, 1), 1);
    
    // Create a blue gradient that transitions from bright blue to deep blue
    let r = Math.floor(0 + (30 * gradientPosition));  // Slight red increase toward tail
    let g = Math.floor(140 - (90 * gradientPosition)); // Green decreases
    let b = Math.floor(255 - (100 * gradientPosition)); // Blue decreases more slowly
    
    ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
    
    // Add subtle border to snake segments
    ctx.fillRect(snakeBody[i][0], snakeBody[i][1], blockSize, blockSize);
    // ctx.strokeStyle = "rgba(0, 70, 120, 0.5)";
    // ctx.strokeRect(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 = [];
  currentLevel = levels[0];
  placeFood();
  updateScoreboard();
  gameOver = false;
}

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

function forest() {
  ctx.fillStyle = "forestGreen";
  ctx.fillRect(0, 0, board.width, board.height);
  setThemeColor(76, 175, 80);
}

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

  // 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() {
  ctx.fillStyle = "darkRed";
  ctx.fillRect(0, 0, board.width, board.height);
  setThemeColor(255, 87, 34);
}

function setThemeColor(r, g, b, intensity = 0.4) {
  document.documentElement.style.setProperty(
    "--glow-color",
    `${r}, ${g}, ${b}`
  );
  document.documentElement.style.setProperty("--glow-intensity", intensity);
  document.documentElement.style.setProperty(
    "--border-color",
    `rgb(${r}, ${g}, ${b})`
  );
}