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)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
// 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() {
}