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.js
459 lines UTF-8 Windows (CRLF)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
// Grundläggande spelvariabler
const blockSize = 25;
const rows = 18;
const cols = 18;
const board = document.getElementById("board");
const ctx = board.getContext("2d");
const scoreBoard = document.getElementById("scoreBoard");
// 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 };
let blocks = [];
// Speltillstånd
let gameLoop;
let isPaused = true;
let gameOver = false;
let directionChanged = false;
let highScore = localStorage.getItem("snakeHighScore") || 0;
// Spelkonfiguration
const gameOptions = {
enableWalls: true,
gameSpeed: 10,
speedIncreaseThreshold: 5, // Öka hastighet var 5:e poäng
enableWrapAround: false
};
// 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);
document.querySelectorAll(".game-option").forEach(el =>
el.addEventListener("change", updateSettings)
);
// 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 väggar om aktiverade
if (gameOptions.enableWalls) {
ctx.fillStyle = colors.wall;
blocks.forEach(block => {
ctx.fillRect(block[0], block[1], 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 5e 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
) {
if (gameOptions.enableWrapAround) {
// Wrap around logik
if (snake.x < 0) {
snake.x = (cols - 1) * blockSize;
} else if (snake.x >= cols * blockSize) {
snake.x = 0;
}
if (snake.y < 0) {
snake.y = (rows - 1) * blockSize;
} else if (snake.y >= rows * blockSize) {
snake.y = 0;
}
} else {
// Vanlig kollisionslogik
endGame();
return;
}
}
// Kontrollera kollision med block
for (let i = 0; i < blocks.length; i++) {
if (snake.x === blocks[i][0] && snake.y === blocks[i][1]) {
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;
}
// Uppdatera poängtavla och rita allt
updateScoreboard();
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
};
// Återställ block
blocks = [];
// Lägg till väggar om aktiverade
if (gameOptions.enableWalls) {
for (let i = 0; i < 10; i++) {
spawnBlock();
}
}
// Placera ny mat
placeFood();
updateScoreboard();
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() {
let isValid;
// Hitta en giltig position
do {
isValid = true;
food = {
x: Math.floor(Math.random() * cols) * blockSize,
y: Math.floor(Math.random() * rows) * blockSize
};
// Kontrollera kollision med ormhuvud
if (food.x === snake.x && food.y === snake.y) {
isValid = false;
continue;
}
// Kontrollera kollision med ormkropp
for (let i = 0; i < snake.body.length; i++) {
if (food.x === snake.body[i][0] && food.y === snake.body[i][1]) {
isValid = false;
break;
}
}
// Kontrollera kollision med block
for (let i = 0; i < blocks.length; i++) {
if (food.x === blocks[i][0] && food.y === blocks[i][1]) {
isValid = false;
break;
}
}
} while (!isValid);
}
// Skapa blockhinder
function spawnBlock() {
let x, y;
let isValid;
// Hitta en giltig position
do {
isValid = true;
x = Math.floor(Math.random() * cols) * blockSize;
y = Math.floor(Math.random() * rows) * blockSize;
// Kontrollera kollision med orm
if (x === snake.x && y === snake.y) {
isValid = false;
continue;
}
// Kontrollera kollision med ormkropp
for (let i = 0; i < snake.body.length; i++) {
if (x === snake.body[i][0] && y === snake.body[i][1]) {
isValid = false;
break;
}
}
// Kontrollera kollision med mat
if (x === food.x && y === food.y) {
isValid = false;
continue;
}
// Kontrollera kollision med andra block
for (let i = 0; i < blocks.length; i++) {
if (x === blocks[i][0] && y === blocks[i][1]) {
isValid = false;
break;
}
}
} while (!isValid);
blocks.push([x, y]);
}
// Uppdatera poängtavla
function updateScoreboard() {
scoreBoard.innerHTML = `
<p>Högsta poäng: ${highScore}</p>
<p>Poäng: ${snake.score}</p>
`;
}
// Uppdatera spelinställningar
function updateSettings() {
const wallsToggle = document.getElementById("toggleWalls");
const speedSlider = document.getElementById("gameSpeed");
const wrapToggle = document.getElementById("toggleWrap");
// Uppdatera vägginställning
if (wallsToggle) {
gameOptions.enableWalls = wallsToggle.checked;
if (!gameOptions.enableWalls) {
blocks = [];
} else if (blocks.length === 0) {
// Lägg till väggar om aktiverade
if (gameOptions.enableWalls) {
for (let i = 0; i < 10; i++) {
spawnBlock();
}
}
}
}
// Uppdatera wrap around-inställning
if (wrapToggle) {
gameOptions.enableWrapAround = wrapToggle.checked;
}
// Uppdatera hastighetsinställning
if (speedSlider) {
gameOptions.gameSpeed = parseInt(speedSlider.value);
if (!isPaused && !gameOver) {
clearInterval(gameLoop);
gameLoop = setInterval(update, 1000 / getCurrentSpeed());
}
}
updateScoreboard();
draw();
}