web开发课程4--贪吃蛇小游戏

Last updated on August 11, 2024 pm

网页端的贪吃蛇小游戏,支持定制,目前功能尚少

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css" />
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Snake</title>
<script src="snake.js"></script>
<script src="input.js"></script>
<script src="food.js"></script>
<script src="snakeUtils.js"></script>
<script src="game.js" defer></script>
</head>
<body>
<div id="game-board"></div>
<div id="game-start">
<h1>Start Game</h1>
<button id="start-button">Start</button>
</div>
<div id="game-over">
<h1>Game Over</h1>
<button id="restart-button">Restart</button>
</div>
</body>
</html>

style.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* No need to edit this file! */

body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
background-color: gray;
}

#game-board {
background-color: black;
width: 100vmin;
height: 100vmin;
display: grid;
grid-template-rows: repeat(21, 1fr);
grid-template-columns: repeat(21, 1fr);
}

/* .snake {
background-color: rgb(58, 90, 160);
border: 0.25vmin solid rgb(78, 66, 126);
} */

.snake{
background-image: url('IMG_20240731_162343.jpg'); /* 替换为你的蛇头图片路径 */
background-size: 4.76vmin 4.76vmin; /* 设置图片的大小,使其适应像素块 */
background-position: center; /* 图片居中对齐 */
}

/* .food {
background-color: rgb(182, 111, 139);
border: 0.25vmin solid gray;
} */

.food {
background-image: url('th.jpg'); /* 替换为你的蛇头图片路径 */
background-size: 4.76vmin 4.76vmin; /* 设置图片的大小,使其适应像素块 */
}

#game-start, #game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: rgba(0, 0, 0, 0.8); /* 添加半透明背景 */
color: white; /* 文字颜色 */
padding: 20px;
border-radius: 10px;
text-align: center;
z-index: 1000; /* 确保它们在其他内容上面 */
}

#game-start {
display: flex;
}

#game-over {
display: none;
/* display: flex; */
}

button {
margin-top: 20px;
padding: 10px 20px;
font-size: 16px;
}

game.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
const SNAKE_SPEED = 5;

const gameBoard = document.getElementById('game-board');
const gameStartOverlay = document.getElementById('game-start');
const gameOverOverlay = document.getElementById('game-over');

let isGameRunning = false;
let gameInterval;

const init = () => {
document.getElementById('start-button').addEventListener('click', startGame);
document.getElementById('restart-button').addEventListener('click', restartGame);
};

window.onload = init;

const main = () => {
if (!isGameRunning) return;
update();
draw();
if (checkGameOver()) {
gameOver();
}
// TODO 4.3, 4.4: Add Game Over Alert, and clear interval!
};

const startGame = () => {
console.log('Starting game...');
isGameRunning = true;
gameStartOverlay.style.display = 'none'; // 隐藏游戏开始界面
gameOverOverlay.style.display = 'none'; // 隐藏游戏结束界面
gameBoard.innerHTML = ''; // 清空游戏板
resetGame(); // 重置游戏状态
if (gameInterval) clearInterval(gameInterval); // 清除之前的定时器
gameInterval = setInterval(main, 1000 / SNAKE_SPEED); // 启动新的游戏循环
};

const restartGame = () => {
console.log('Restarting game...');
isGameRunning = true;
gameOverOverlay.style.display = 'none'; // 隐藏游戏结束界面
gameBoard.innerHTML = ''; // 清空游戏板
resetGame(); // 重置游戏状态
if (gameInterval) clearInterval(gameInterval); // 清除之前的定时器
gameInterval = setInterval(main, 1000 / SNAKE_SPEED); // 启动新的游戏循环
};

const gameOver = () => {
console.log('Game Over');
isGameRunning = false;
clearInterval(gameInterval); // 停止游戏循环
gameOverOverlay.style.display = 'block'; // 显示游戏结束界面
};
// TODO 4.4: Define the interval ID
// HINT: ONLY EDIT THE LINE BELOW!
//setInterval(main, 1000 / SNAKE_SPEED);

const update = () => {
console.log('Updating');
updateSnake();
updateFood();
// TODO 4.2: Update Game State
};

const draw = () => {
gameBoard.innerHTML = '';
drawSnake(gameBoard);
drawFood(gameBoard);
};

const checkGameOver = () => {
return snakeOutOfBounds() || snakeIntersectSelf(); // 检查游戏结束条件
};

const resetGame = () => {
// 重置蛇的位置
snakeBody = [
{ x: 11, y: 11 },
{ x: 11, y: 10 },
{ x: 11, y: 9 }
];

// 重置食物的位置
food = getNewFoodPosition();

// 可以添加其他初始化逻辑
};


// TODO 4.1: Create a function that checks if the game is over

food.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let food = { x: 4, y: 16 };

const updateFood = () => {
if (onSnake(food)) {
growSnake();
food = getNewFoodPosition();
}
};

// Don't change me!
const drawFood = (gameBoard) => {
const foodElement = document.createElement('div');
foodElement.style.gridRowStart = food.y;
foodElement.style.gridColumnStart = food.x;
foodElement.classList.add('food');
gameBoard.appendChild(foodElement);
};

snake.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
let snakeBody = [
{ x: 11, y: 11 },
{ x: 11, y: 10 },
{ x: 11, y: 9 },
];

const updateSnake = () => {
// Remove tail segment
snakeBody.pop();

// Add new head segment
const newHead = { ...snakeBody[0] };
const snakeDirection = getInputDirection();

newHead.x += snakeDirection.x;
newHead.y += snakeDirection.y;

if (outOfBounds(newHead)) {
gameOver(); // 处理游戏结束逻辑
return;
}

snakeBody.unshift(newHead);
};

// Don't change this function!
const drawSnake = (gameBoard) => {
for (let i = 0; i < snakeBody.length; i++) {
const segment = snakeBody[i];
const snakeElement = document.createElement('div');
snakeElement.style.gridRowStart = segment.y;
snakeElement.style.gridColumnStart = segment.x;
// if (i === 0) {
// snakeElement.classList.add('snake-head');
// } else {
// snakeElement.classList.add('snake');
// }
snakeElement.classList.add('snake');
gameBoard.appendChild(snakeElement);
}
};

snakeUtils.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
const GRID_SIZE = 21;

const onSnake = (position) => {
for (let i = 0; i < snakeBody.length; i++) {
if (equalPositions(position, snakeBody[i])) {
return true;
}
}
return false;
};

// const gameOver = () => {
// console.log('Game Over');
// // 清空游戏板
// gameBoard.innerHTML = '';
// };


const equalPositions = (pos1, pos2) => {
return pos1.x === pos2.x && pos1.y === pos2.y;
};

const growSnake = () => {
snakeBody.push({ ...snakeBody[snakeBody.length - 1] });
};

const getNewFoodPosition = () => {
let randomFoodPosition = randomGridPosition();
while (onSnake(randomFoodPosition)) {
randomFoodPosition = randomGridPosition();
}
return randomFoodPosition;
};

const randomGridPosition = () => {
return {
x: Math.floor(Math.random() * GRID_SIZE) + 1,
y: Math.floor(Math.random() * GRID_SIZE) + 1,
};
};

const outOfBounds = (position) => {
return position.x < 1 || position.x > GRID_SIZE || position.y < 1 || position.y > GRID_SIZE;
}

const snakeOutOfBounds = () => {
return outOfBounds(snakeBody[0]);
}

const snakeIntersectSelf = () => {
for (let i = 1; i < snakeBody.length; i++) {
if (equalPositions(snakeBody[0], snakeBody[i])) {
return true;
}
}
return false;
}

input.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let inputDirection = { x: 0, y: 1 };

window.addEventListener('keydown', (event) => {
if (event.key === 'ArrowUp' && inputDirection.x !== 0) {
inputDirection = { x: 0, y: -1 };
} else if (event.key === 'ArrowDown' && inputDirection.x !== 0) {
inputDirection = { x: 0, y: 1 };
} else if (event.key === 'ArrowRight' && inputDirection.y !== 0) {
inputDirection = { x: 1, y: 0 };
} else if (event.key === 'ArrowLeft' && inputDirection.y !== 0) {
inputDirection = { x: -1, y: 0 };
}
});

const getInputDirection = () => {
return inputDirection;
};


web开发课程4--贪吃蛇小游戏
http://example.com/2024/08/07/2024-08-07-web开发课程4--贪吃蛇小游戏/
Author
Yaodeer
Posted on
August 7, 2024
Licensed under