html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.bd {
width: 500px;
position: absolute;
transform: translateX(-50%) translateY(-50%);
left: 50%;
top: 50%
}
body {
background-color: rgba(0, 0, 0, 0.1);
}
.row {
display: flex;
justify-content: space-around;
}
span {
display: block;
width: 25px;
height: 25px;
background-color: skyblue;
/* border: 1px solid black; */
}
.bdgreen {
background-color: chartreuse;
}
.bdblack {
background-color: black;
}
.head {
background-color: coral;
}
</style>
</head>
<body>
<h1>当前积分</h1>
<br>
<h2></h2>
<br>
<div>使用wasd或者上下左右操作,按下esc可暂停游戏</div>
<br>
<div>
输入地图大小(输入一个正数,比如10):<br><br><input> <button>确认</button>
</div>
<div class="bd"></div>
<script>
// 这里修改地图大小
let base = 10;
// 这里修改蛇的前进速度
let speed = 150;
let x = 0, y = 0;
let direction = { x: 0, y: 0 }
let hassnake = []
let reward
let score = 0
let sankeLength = 1;
(function () {
if (localStorage.getItem("base") == null) {
base = 10;
localStorage.setItem("base", 10);
} else {
base = Number(localStorage.getItem("base"))
}
}());
// console.log(base)
function changeBase() {
base = document.querySelector("input").value == '' ? 10 : Number(document.querySelector("input").value)
// init()
localStorage.setItem("base", base);
location.reload()
}
document.querySelector("button").addEventListener("click", () => {
changeBase()
})
document.querySelector(".bd").style.width = base * 25 + "px";
// document.querySelector(".bd").style.height = base * 20 + "px";
let arr = new Array(base)
let h = document.querySelector("h1")
const h2 = document.querySelector("h2")
localStorage.getItem("")
h2.innerHTML = `最高分数为:${localStorage.getItem("score") || 0}分`
for (let i = 0; i < arr.length; i++) {
arr[i] = new Array(base)
for (let j = 0; j < arr[i].length; j++) {
arr[i][j] = 0
}
}
for (let i = 0; i < arr.length; i++) {
const div = document.createElement("div")
for (let j = 0; j < arr.length; j++) {
const span = document.createElement("span")
div.appendChild(span)
}
div.className = "row"
div.innerHTML += "<br>"
document.querySelector(".bd").appendChild(div)
}
const spanarr = document.querySelectorAll("span")
function rand() {
const x = parseInt(Math.random() * base)
const y = parseInt(Math.random() * base)
return { x, y }
}
function addReward() {
const { x, y } = rand()
spanarr[x * base + y].classList.add("bdgreen")
return { x, y }
}
function Location(x, y, lastX, lastY) {
this.x = x;
this.y = y;
this.lastX = lastX;
this.lastY = lastY;
}
function breakGame() {
alert("游戏结束")
localStorage.setItem("score", Math.max(score, localStorage.getItem("score")));
clearInterval(timer)
init()
location.reload()
}
const timer = setInterval(() => {
// 此时x和y保存上一次的位置信息
let lastX = x, lastY = y;
x += direction.x;
y += direction.y;
// console.log("当前蛇头在:", x, y)
if (x >= base || x < 0 || y >= base || y < 0) {
breakGame()
}
// console.log("snake:")
for (let i = 0; i < sankeLength; i++) {
for (let j = 0; j < sankeLength; j++) {
if (i == j)
continue;
if (hassnake[i].x == hassnake[j].x && hassnake[i].y == hassnake[j].y) {
breakGame()
}
}
}
//每一个元素都要获取前一个元素信息,
for (let i = sankeLength - 1; i >= 1; i--) {
if (i == sankeLength - 1) {
lastX = hassnake[i].x;
lastY = hassnake[i].y
}
hassnake[i].x = hassnake[i - 1].x;
hassnake[i].y = hassnake[i - 1].y;
}
//头部的信息
hassnake[0].x = x;
hassnake[0].y = y;
hassnake[sankeLength - 1].lastX = lastX
hassnake[sankeLength - 1].lastY = lastY
for (let i = 0; i < base * base; i++) {
spanarr[i].classList.remove("bdblack")
spanarr[i].classList.remove("head")
}
spanarr[reward.x * base + reward.y].classList.add("bdgreen")
for (let i = 0; i < sankeLength; i++) {
spanarr[hassnake[i].x * base + hassnake[i].y].classList.add("bdblack")
}
spanarr[hassnake[0].x * base + hassnake[0].y].classList.remove("bdblack");
spanarr[hassnake[0].x * base + hassnake[0].y].classList.add("head");
if (x == reward.x && y == reward.y) {
spanarr[x * base + y].classList.remove("bdgreen")
reward = addReward()
const Controls = new Location(hassnake[sankeLength - 1].lastX, hassnake[sankeLength - 1].lastY, 0, 0)
hassnake.push(Controls)
score += 1
h.innerHTML = `当前积分:${score}`
sankeLength += 1
}
}, speed)
function init() {
reward = addReward()
spanarr[0].classList.add("bdblack")
direction = { x: 0, y: 0 }
his = []
score = 0
sankeLength = 1
h.innerHTML = `当前积分:${score}分`
hassnake = []
const init = new Location(0, 0, 0, 0)
hassnake.push(init)
}
init()
window.addEventListener("keyup", function (e) {
console.log(e)
if (e.code == "KeyW" || e.code == "ArrowUp") {
direction = { x: -1, y: 0 }
}
if (e.code == "KeyD" || e.code == "ArrowRight") {
direction = { x: 0, y: 1 }
}
if (e.code == "KeyS" || e.code == "ArrowDown") {
direction = { x: 1, y: 0 }
}
if (e.code == "KeyA" || e.code == "ArrowLeft") {
direction = { x: 0, y: -1 }
}
if (e.code == "Escape") {
direction = { x: 0, y: 0 }
}
if (e.code == "Enter") {
changeBase()
}
})
</script>
</body>
</html>
学js的时候突然发现贪吃蛇好像就是保存到一个二维数组,然后根据不同的状态渲染页面就行,于是就手写出来了,不过感觉时间复杂度有点高,应该有更好的实现方式(每一次移动只需要按照方向添加一个黑色方块然后去掉最后一个黑色方块就行,如果吃到了绿色方块就不需要去掉最后一个黑色方法),只要能跑就行了
调整移动速度可以修改speed(单位是毫秒),直接用speed做定时器的循环时间
没有写绿色方块不能生成在黑色方块的逻辑(只要循环一下黑色方块,然后判断一下随机数在不在里面,在里面就重新生成一个,直到没有)
看起来应该没有BUG吧......