Webbserver - Love Blomberg

Show sourcecode

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

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

snake.js

snake.js

288 lines UTF-8 Windows (CRLF)
// Grundläggande spelvariabler
const blockSize = 25;
const rows = 18;
const cols = 18;
const board = document.getElementById("board");
const ctx = board.getContext("2d");

// Orm och mat
let snake = {
  x: blockSize * 5,
  y: blockSize * 5,
  dx: 0,
  dy: 0,
  body: [],
  score: 0,
  color: "#3498db"
};
let food = { x: 0, y: 0 };

// Speltillstånd
let gameLoop;
let isPaused = true;
let gameOver = false;
let directionChanged = false;
let highScore = localStorage.getItem("snakeHighScore") || 0;

// Spelkonfiguration
const gameOptions = {
  gameSpeed: 10,
  speedIncreaseThreshold: 5, // Öka hastighet var 5:e poäng
};

// Färger
const colors = {
  background: "#1e1e1e",
  grid: "#2a2a2a",
  food: "#e74c3c",
  wall: "#95a5a6",
  snake: "#3498db"
};

// Initialisera spelet
window.onload = function() {
  // Sätt spelplanens storlek
  board.height = rows * blockSize;
  board.width = cols * blockSize;
  
  // Lägg till händelselyssnare
  document.addEventListener("keydown", handleKeyPress);
  
  // Starta spelet
  restart();
};

// Rita spelplanen
function draw() {
  // Rita bakgrund
  ctx.fillStyle = colors.background;
  ctx.fillRect(0, 0, board.width, board.height);
  
  // Rita rutnät
  ctx.fillStyle = colors.grid;
  for (let row = 0; row < rows; row++) {
    for (let col = 0; col < cols; col++) {
      if ((row + col) % 2 === 1) {
        ctx.fillRect(col * blockSize, row * blockSize, blockSize, blockSize);
      }
    }
  }
  
  // Rita mat
  ctx.fillStyle = colors.food;
  ctx.fillRect(food.x, food.y, blockSize, blockSize);
  
  // Rita ormkropp
  for (let i = 0; i < snake.body.length; i++) {
    ctx.fillStyle = colors.snake;
    ctx.fillRect(snake.body[i][0], snake.body[i][1], blockSize, blockSize);
    ctx.strokeStyle = "rgba(0, 0, 0, 0.2)";
    ctx.strokeRect(snake.body[i][0], snake.body[i][1], blockSize, blockSize);
  }
  
  // Rita ormhuvud
  ctx.fillStyle = colors.snake;
  ctx.fillRect(snake.x, snake.y, blockSize, blockSize);
}

// Hantera tangentkontroller
function handleKeyPress(e) {
  // Förhindra sidorullning
  if (["Space", "ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", 
       "KeyW", "KeyS", "KeyA", "KeyD"].includes(e.code)) {
    e.preventDefault();
  }
  
  // Hantera mellanslag för paus/fortsätt
  if (e.code === "Space") {
    togglePause();
    return;
  }
  
  if (!isPaused) {
    // Ormkontroller (pilar eller WASD)
    if ((e.code === "ArrowUp" || e.code === "KeyW") && snake.dy !== 1) {
      if (!directionChanged) {
        snake.dx = 0;
        snake.dy = -1;
        directionChanged = true;
      }
    } else if ((e.code === "ArrowDown" || e.code === "KeyS") && snake.dy !== -1) {
      if (!directionChanged) {
        snake.dx = 0;
        snake.dy = 1;
        directionChanged = true;
      }
    } else if ((e.code === "ArrowLeft" || e.code === "KeyA") && snake.dx !== 1) {
      if (!directionChanged) {
        snake.dx = -1;
        snake.dy = 0;
        directionChanged = true;
      }
    } else if ((e.code === "ArrowRight" || e.code === "KeyD") && snake.dx !== -1) {
      if (!directionChanged) {
        snake.dx = 1;
        snake.dy = 0;
        directionChanged = true;
      }
    }
  }
}

// Växla spelpausstatus
function togglePause() {
  const overlay = document.getElementById("gameOverlay");
  
  if (gameOver) {
    restart();
    gameOver = false;
    isPaused = false;
    overlay.style.display = "none";
    gameLoop = setInterval(update, 1000 / getCurrentSpeed());
    return;
  }
  
  if (isPaused) {
    isPaused = false;
    overlay.style.display = "none";
    gameLoop = setInterval(update, 1000 / getCurrentSpeed());
  } else {
    isPaused = true;
    document.getElementById("overlayMessage").textContent = "PAUSAD";
    document.getElementById("overlaySubMessage").textContent = "Tryck på mellanslag för att fortsätta";
    overlay.style.display = "flex";
    clearInterval(gameLoop);
  }
}

// Beräkna aktuell spelhastighet baserat på poäng
function getCurrentSpeed() {
  // Hastigheten ökar med 1 var 5:e poäng
  const speed = gameOptions.gameSpeed + Math.floor(snake.score / gameOptions.speedIncreaseThreshold);
  return speed;
}

// Huvuduppdateringsfunktion för spelet
function update() {
  if (gameOver) {
    restart();
    return;
  }
  
  directionChanged = false;
  
  // Flytta ormens kroppsdelar
  if (snake.body.length) {
    for (let i = snake.body.length - 1; i > 0; i--) {
      snake.body[i] = snake.body[i - 1];
    }
    snake.body[0] = [snake.x, snake.y];
  }
  
  // Flytta ormhuvudet
  snake.x += snake.dx * blockSize;
  snake.y += snake.dy * blockSize;
  
  // Kontrollera väggkollision
  if (
    snake.x < 0 || 
    snake.x >= cols * blockSize || 
    snake.y < 0 || 
    snake.y >= rows * blockSize
  ) {
    // Vanlig kollisionslogik
    endGame();
    return;
  }
  
  // Kontrollera kollision med ormkropp (men skippa första segmentet om vi precis ätit)
  let startIndex = snake.justAte ? 1 : 0;
  for (let i = startIndex; i < snake.body.length; i++) {
    if (snake.x === snake.body[i][0] && snake.y === snake.body[i][1]) {
      endGame();
      return;
    }
  }
  
  // Kontrollera matkollision
  if (snake.x === food.x && snake.y === food.y) {
    // Markera att vi precis ätit
    snake.justAte = true;
    
    // Lägg till ny kroppsdel (använd sista positionen i kropppen eller huvudet)
    if (snake.body.length > 0) {
      snake.body.push([...snake.body[snake.body.length - 1]]);
    } else {
      snake.body.push([snake.x - snake.dx * blockSize, snake.y - snake.dy * blockSize]);
    }
    
    // Öka poäng
    snake.score++;
    
    // Uppdatera högsta poäng
    if (snake.score > highScore) {
      highScore = snake.score;
      localStorage.setItem("snakeHighScore", highScore);
    }
    
    // Placera ny mat
    placeFood();
    
    // Uppdatera spelhastighet om poängen når tröskelvärdet
    if (snake.score % gameOptions.speedIncreaseThreshold === 0) {
      clearInterval(gameLoop);
      gameLoop = setInterval(update, 1000 / getCurrentSpeed());
    }
  } else {
    // Om vi inte ätit mat denna uppdatering, återställ justAte-flaggan
    snake.justAte = false;
  }
  
  draw();
}

// Avsluta spelet
function endGame() {
  clearInterval(gameLoop);
  gameOver = true;
  const overlay = document.getElementById("gameOverlay");
  document.getElementById("overlayMessage").textContent = "SPELET SLUT";
  document.getElementById("overlaySubMessage").textContent = "Tryck på mellanslag för att spela igen";
  overlay.style.display = "flex";
}

// Starta om spelet
function restart() {
  clearInterval(gameLoop);
  
  // Återställ ormen
  snake = {
    x: blockSize * 5,
    y: blockSize * 5,
    dx: 0,
    dy: 0,
    body: [],
    score: 0,
    color: "#3498db",
    justAte: false
  };
  
  // Placera ny mat
  placeFood();
  draw();
  
  // Visa startmeddelande
  isPaused = true;
  document.getElementById("overlayMessage").textContent = "Tryck på mellanslag för att starta";
  document.getElementById("overlaySubMessage").textContent = "";
  document.getElementById("gameOverlay").style.display = "flex";
}

// Placera mat slumpmässigt
function placeFood() {
  food = {
    x: Math.floor(Math.random() * cols) * blockSize,
    y: Math.floor(Math.random() * rows) * blockSize
  };
}