贪吃蛇
一、html
<div class="container" id="app"></div><script src="./js/index.js"></script>
二、css
* {margin: 0;top: 0;}
.set {margin: 15px auto;width: 600px;
}
.container {width: 600px;height: 600px;background-color: #225675;margin: 40px auto;outline: 20px solid #7dd9ff;position: relative;
}
.snake {position: absolute;
}
.snake-head {width: 0px;height: 0px;border-bottom: 10px solid transparent;border-left: 10px solid rgb(157, 219, 177);border-right: 10px solid transparent;border-top: 10px solid transparent;transform: rotate(0deg);
}.snake-body {border-radius: 50%;background-color: #7db5ff;
}
.egg {position: absolute;background-color: rgb(241, 54, 232);border-radius: 50%;
}.cover {position: absolute;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.5);display: flex;justify-content: center;align-items: center;
}
.cover .content {width: 60%;height: 50px;background-color: rgb(134, 225, 237);display: flex;justify-content: center;align-items: center;
}
三、JavaScript
function getRandom(rate) {return Math.floor(Math.random() * rate);
}
class Snake {constructor(snakeBody, size, direction) {this.direction = direction; this.size = size; this.snakeBody =snakeBody.length > 0 &&snakeBody.map((pos) => ({left: pos.left * size,top: pos.top * size,}));}render() {let template = "";let transformDeg = 0;switch (this.direction) {case "right":transformDeg = 0;break;case "down":transformDeg = 90;break;case "left":transformDeg = 180;break;case "up":transformDeg = -90;break;}return this.snakeBody.reduce((prev, next, currentIndex) => {if (currentIndex === 0) {template =prev +`<div class="snake-head snake" style="left:${next.left}px;top:${next.top}px;border-width:${this.size / 2}px;transform: rotate(${transformDeg}deg);"></div>\n`;} else {template =prev +`<div class="snake-body snake" style="left:${next.left}px;top:${next.top}px;width:${this.size}px;height:${this.size}px;transform: rotate(${transformDeg}deg);"></div>`;}return template;}, "");}nextStep() {const head = this.snakeBody[0];let newHead;switch (this.direction) {case "right":newHead = { left: head.left + this.size, top: head.top };break;case "down":newHead = { left: head.left, top: head.top + this.size };break;case "left":newHead = { left: head.left - this.size, top: head.top };break;case "up":newHead = { left: head.left, top: head.top - this.size };break;}this.snakeBody.unshift(newHead);this.snakeBody.pop();console.log(this.direction);console.log(this.size);console.log(this.snakeBody);}snakeGrowUp() {let snake = this.snakeBody;let lens = snake.length;let snakeTail;const prev = snake[lens - 2]; const next = snake[lens - 1]; if (prev.top === next.top && prev.left < next.left) {snakeTail = { ...next, left: next.left + this.size };} else if (prev.top === next.top && prev.left > next.left) {snakeTail = { ...next, left: next.left - this.size };} else if (prev.left === next.left && prev.top > next.top) {snakeTail = { ...next, top: next.top - this.size };} else {snakeTail = { ...next, top: next.top + this.size };}this.snakeBody.push(snakeTail); this.render(); }isArriveWall() {const snake = this.snakeBody;let isEnd;if (snake[0].left >= this.size * MAPSIZE ||snake[0].top >= this.size * MAPSIZE ||snake[0].left < 0 ||snake[0].top < 0) {isEnd = true;}for (let i = 1; i < snake.length; i++) {if (snake[0].left === snake[i].left && snake[0].top === snake[i].top) {isEnd = true;break;}}return isEnd;}changeSnakeDirection(direction) {this.direction = direction;}
}
class Egg {constructor(size) {this.position = { left: 3 * size, top: 0 * size }; this.size = size; }render() {const div = document.createElement("div");div.innerHTML = `<div class='egg' style="left:${this.position.left}px;top:${this.position.top}px;width:${this.size}px;height:${this.size}px">`;return div.children[0];}flushed() {this.position = {left: getRandom(MAPSIZE) * this.size,top: getRandom(MAPSIZE) * this.size,};}
}
function isArriveEgg(snake, egg) {const snakeBody = snake.snakeBody;return (snakeBody[0].left === egg.position.left &&snakeBody[0].top === egg.position.top);
}const MAPSIZE = 30;
let timer;
function init(app) {const snake = new Snake([{ left: 2, top: 0 },{ left: 1, top: 0 },{ left: 0, top: 0 },],20);const egg = new Egg(20);render(app, snake, egg);let direction;document.addEventListener("keydown", (e) => {if (e.key === "ArrowUp" || e.key.toLocaleLowerCase() === "w") {direction != "down" && (direction = "up");} else if (e.key === "ArrowDown" || e.key.toLocaleLowerCase() === "s") {direction != "up" && (direction = "down");} else if (e.key === "ArrowRight" || e.key.toLocaleLowerCase() === "d") {direction != "left" && (direction = "right");} else if (e.key === "ArrowLeft" || e.key.toLocaleLowerCase() === "a") {direction != "right" && (direction = "left");} else {return;}snake.changeSnakeDirection(direction);timer && clearInterval(timer);direction && autoMove(app, snake, egg);});
}
function autoMove(app, snake, egg) {timer = setInterval(() => {snake.nextStep();if (isArriveEgg(snake, egg)) {snake.snakeGrowUp();egg.flushed();}if (snake.isArriveWall()) {endGame(app, snake);} else {render(app, snake, egg);}}, Math.floor(1000 / 5));
}
function render(app, snake, egg) {const snakeTemplate = snake.render();const eggDom = egg.render();app.innerHTML = snakeTemplate;app.appendChild(eggDom);
}
function endGame(App, snake) {timer && clearInterval(timer);const div = document.createElement("div");div.innerHTML = `<div class="cover"><div class="content">游戏结束,得分${snake.snakeBody.length - 3}</div></div>`;const endGameDom = div.children[0];App.parentNode.appendChild(endGameDom);endGameDom.addEventListener("click", () => {App.parentNode.removeChild(endGameDom);init(App);});
}
四、样式截图