html+js实现贪吃蛇小游戏

思路:

  1. 绘制一张40×40的格子,一共1600个格子,也就是一个长度为1600的数组,每个格子代表数组里的一个值,作为游戏区。
  2. 蛇的默认值为:[[0, 12], [0, 13], [0, 14]]的一个二位数组,每一项都代表着蛇身的一部分,例如:[0,12]代表从左上角开始x轴坐标为12,y轴坐标为0的哪一个格子,数组的最后一项为蛇头。
  3. 食物:随机生成一个二维数组,例如:[[5,5]]
  4. 绘制:从第一个格子开始绘制,碰到蛇身变色,碰到蛇头变色,碰到食物变色。
  5. 移动:监听键盘的方向键,判断当前方向,例如:按上键,从蛇数组最后一项开始,蛇头x-1,y不变,以后每一项等于前一项,就形成了蛇前进的效果,,不允许直接掉头。
  6. 设定计时器,每隔一定时间重新绘制一次,就形成了,蛇一直移动的效果。
  7. 蛇头碰到食物,从蛇头开始成长。
  8. 蛇碰到游戏区边缘或者碰到自己均死亡。

1. html及样式代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.box {width: 400px;height: 400px;border: 1px #999 solid;margin: 10px auto 0;}.item {width: 9px;height: 9px;background-color: #fff;float: left;margin: 0 1px 1px 0;}.snakeHead {background-color: #f00;}.snakeBody {background-color: #f0f;}.food {background-color: #ff0;}.score {margin: 10px auto;text-align: center;font-size: 26px;font-weight: 600;}.bot-box {display: flex;justify-content: space-around;}.handle-box {display: grid;grid-template-columns: repeat(3, 1fr);width: 140px;grid-gap: 10px;height: 100px;}.handle-box div,.key {border: 1px #f00 solid;width: 40px;height: 40px;display: flex;justify-content: center;align-items: center;font-size: 18px;font-weight: 600;}.direction-1 {grid-column: span 3 / auto;margin: 0 auto;}.key-box {display: flex;align-items: center;margin: 10px 0;}.key-box .key {margin-right: 10px;}</style>
</head><body><!-- 游戏区 --><div class="box" id="box"></div><!-- 得分 --><div class="score">0</div><!-- 操作按钮提示 --><div class="bot-box"><!-- 方向键 --><div class="handle-box"><div class="direction-1"></div><div class="direction-2"></div><div class="direction-3"></div><div class="direction-4"></div></div><!-- 功能键 --><div><div class="key-box"><div class="key">J</div><span>:开始游戏</span></div><div class="key-box"><div class="key">K</div><span>:游戏暂停</span></div><div class="key-box"><div class="key">R</div><span>:重新开始游戏</span></div></div></div>
</body></html>

2、 设置初始值设置

    // 游戏区domconst box = document.querySelector('.box')// 得分domconst score = document.querySelector('.score')// 游戏格子let gameBox = [40, 40]// 游戏开始标志(计时器)let start = null// 当前速度let velocity = 200// 食物let food = [[5, 5]]// 蛇身let snake = [[0, 12], [0, 13], [0, 14]]// 方向let direction = 3

3. 绘制方法

由于y轴对应的游戏区位置是40的倍数,所以使用transferPosition方法进行坐标转换,例如点[5,6],对应的游戏区格子是第40*5+6个格子。

    // 数组转化为相应点坐标function transferPosition(array) {let ary = []for (let i = 0; i < array.length; i++) {const e = [...array[i]];ary.push(e[0] * gameBox[0] + e[1])}return ary}// 绘制function draw() {// 蛇身+蛇头对应的坐标const snakeAry = transferPosition(snake)// 食物对应的坐标const foodAry = transferPosition(food)box.innerHTML = ''// 游戏区格子总长度const allBox = gameBox[0] * gameBox[0]for (let i = 0; i < allBox; i++) {let div = document.createElement('div')if (snakeAry.indexOf(i) === snakeAry.length - 1) { // 蛇头样式div.className = 'item snakeHead'} else if (snakeAry.indexOf(i) !== -1) {// 蛇身样式div.className = 'item snakeBody'} else if (foodAry.indexOf(i) !== -1) {// 食物样式div.className = 'item food'} else {// 空白区div.className = 'item'}box.appendChild(div)}}

4. 蛇移动

蛇移动前要先记录蛇当前的位置,蛇头按照方向键的方向进行前进,蛇身要按照蛇身轨迹进行移动,例如:向下走一步,[[0, 12], [0, 13], [0, 14]] ---->[[0, 13], [0, 14], [1, 14]]

    // 蛇移动function move() {// 深拷贝蛇行走之前的数组let inventedSnake = []for (let n = 0; n < snake.length; n++) {const e = snake[n];inventedSnake.push([...e])}// 判断行进方向,蛇身前进 direction:1左 2上 3右 4下const lng = snake.length;for (let i = lng - 1; i >= 0; i--) {if (i === lng - 1) { // 蛇头前进if (direction === 1) {snake[i][1] = snake[i][1] - 1} else if (direction === 2) {snake[i][0] = snake[i][0] - 1} else if (direction === 3) {snake[i][1] = snake[i][1] + 1} else if (direction === 4) {snake[i][0] = snake[i][0] + 1}}else { // 蛇身前进snake[i] = inventedSnake[i + 1]}}}

5. 随机生成食物

此处每次仅生成一个食物

  // 生成随机数function randomNumber() {return Number.parseInt(Math.random() * 40)}// 随机生成食物function createFood() {food = [[randomNumber(), randomNumber()]]}

6. 判断吃到食物,进行成长

	// 判断是否吃到食物function eatFood() {if (food.length === 0) return// 蛇头和食物重合及吃到食物if (snake[snake.length - 1].toString() === food[0].toString()) {// 成长growUp()// 重新生成食物createFood()}}// 吃到食物 进行成长function growUp() {let snakeFood = []let [x, y] = snake[snake.length - 1]// 按照蛇头的方向在蛇头处成长if (direction === 1) {snakeFood = [x, y - 1]} else if (direction === 2) {snakeFood = [x - 1, y]} else if (direction === 3) {snakeFood = [x, y + 1]} else if (direction === 4) {snakeFood = [x + 1, y]}snake.push(snakeFood)// 重算积分(积分=蛇当前长度-初始长度)score.innerHTML = snake.length - 3}

7. 判断死亡

	// 判断死亡function judgingDeath() {// 撞墙死亡if (snake[snake.length - 1][0] > (gameBox[0] - 1) ||snake[snake.length - 1][0] < 0 ||snake[snake.length - 1][1] > (gameBox[1] - 1) ||snake[snake.length - 1][1] < 0) {// 游戏结束endGame()return true}// 咬到自己死亡for (let i = 0; i < snake.length; i++) {for (let j = 0; j < i - 1; j++) {if (snake[i].toString() === snake[j].toString()) {// 游戏结束endGame()return true}}}return false}

8. 游戏结束

// 游戏结束(蛇死亡)function endGame() {clearInterval(start)alert(`本局得分:${snake.length - 3}分,再接再厉`, '游戏结束', {confirmButtonText: '确定',callback: action => {}});}

9. 游戏开始、暂停、重新开始

	// 游戏开始 蛇开始爬行function beginGame() {// 游戏开始计时器start = setInterval(() => {// 判断死亡if (judgingDeath()) return clearInterval(start)// 蛇移动move()// 判断是否吃到食物eatFood()// 重绘draw()}, velocity);}// 游戏暂停function suspendGame() {clearInterval(start)}// 重新开始function reBeginGame() {food = [[5, 5]]snake = [[0, 12], [0, 13], [0, 14]]direction = 3score.innerHTML = 0beginGame()}

10. 全部代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.box {width: 400px;height: 400px;border: 1px #999 solid;margin: 10px auto 0;}.item {width: 9px;height: 9px;background-color: #fff;float: left;margin: 0 1px 1px 0;}.snakeHead {background-color: #f00;}.snakeBody {background-color: #f0f;}.food {background-color: #ff0;}.score {margin: 10px auto;text-align: center;font-size: 26px;font-weight: 600;}.bot-box {display: flex;justify-content: space-around;}.handle-box {display: grid;grid-template-columns: repeat(3, 1fr);width: 140px;grid-gap: 10px;height: 100px;}.handle-box div,.key {border: 1px #f00 solid;width: 40px;height: 40px;display: flex;justify-content: center;align-items: center;font-size: 18px;font-weight: 600;}.direction-1 {grid-column: span 3 / auto;margin: 0 auto;}.key-box {display: flex;align-items: center;margin: 10px 0;}.key-box .key {margin-right: 10px;}</style>
</head><body><!-- 游戏区 --><div class="box" id="box"></div><!-- 得分 --><div class="score">0</div><!-- 操作按钮提示 --><div class="bot-box"><!-- 方向键 --><div class="handle-box"><div class="direction-1"></div><div class="direction-2"></div><div class="direction-3"></div><div class="direction-4"></div></div><!-- 功能键 --><div><div class="key-box"><div class="key">J</div><span>:开始游戏</span></div><div class="key-box"><div class="key">K</div><span>:游戏暂停</span></div><div class="key-box"><div class="key">R</div><span>:重新开始游戏</span></div></div></div>
</body></html>
<script type="text/javascript">(function () {// 游戏区domconst box = document.querySelector('.box')// 分值domconst score = document.querySelector('.score')// 游戏格子let gameBox = [40, 40]// 游戏开始标志(计时器)let start = null// 当前速度let velocity = 200// 食物let food = [[5, 5]]// 蛇身let snake = [[0, 12], [0, 13], [0, 14]]// 方向let direction = 3// 数组转化为相应点坐标addfunction transferPosition(array) {let ary = []for (let i = 0; i < array.length; i++) {const e = [...array[i]];ary.push(e[0] * gameBox[0] + e[1])}return ary}// 随机生成食物function createFood() {food = [[randomNumber(), randomNumber()]]}// 生成随机数function randomNumber() {return Number.parseInt(Math.random() * 40)}// 绘制function draw() {// 蛇身+蛇头对应的坐标const snakeAry = transferPosition(snake)// 食物对应的坐标const foodAry = transferPosition(food)box.innerHTML = ''// 游戏区格子总长度const allBox = gameBox[0] * gameBox[0]for (let i = 0; i < allBox; i++) {let div = document.createElement('div')if (snakeAry.indexOf(i) === snakeAry.length - 1) { // 蛇头样式div.className = 'item snakeHead'} else if (snakeAry.indexOf(i) !== -1) {// 蛇身样式div.className = 'item snakeBody'} else if (foodAry.indexOf(i) !== -1) {// 食物样式div.className = 'item food'} else {// 空白区div.className = 'item'}box.appendChild(div)}}// 开始游戏之前先绘制一次draw()// 游戏结束(蛇死亡)function endGame() {clearInterval(start)alert(`本局得分:${snake.length - 3}分,再接再厉`, '游戏结束', {confirmButtonText: '确定',callback: action => {}});}// 蛇移动function move() {// 深拷贝蛇行走之前的数组let inventedSnake = []for (let n = 0; n < snake.length; n++) {const e = snake[n];inventedSnake.push([...e])}// 判断行进方向,蛇身前进 direction:1左 2上 3右 4下const lng = snake.length;for (let i = lng - 1; i >= 0; i--) {if (i === lng - 1) { // 蛇头前进if (direction === 1) {snake[i][1] = snake[i][1] - 1} else if (direction === 2) {snake[i][0] = snake[i][0] - 1} else if (direction === 3) {snake[i][1] = snake[i][1] + 1} else if (direction === 4) {snake[i][0] = snake[i][0] + 1}}else { // 蛇身前进snake[i] = inventedSnake[i + 1]}}}// 判断死亡function judgingDeath() {// 撞墙死亡if (snake[snake.length - 1][0] > (gameBox[0] - 1) ||snake[snake.length - 1][0] < 0 ||snake[snake.length - 1][1] > (gameBox[1] - 1) ||snake[snake.length - 1][1] < 0) {// 游戏结束endGame()return true}// 咬到自己死亡for (let i = 0; i < snake.length; i++) {for (let j = 0; j < i - 1; j++) {if (snake[i].toString() === snake[j].toString()) {// 游戏结束endGame()return true}}}return false}// 游戏开始 蛇开始爬行function beginGame() {// 游戏开始计时器start = setInterval(() => {// 判断死亡if (judgingDeath()) return clearInterval(start)// 蛇移动move()// 判断是否吃到食物eatFood()// 重绘draw()}, velocity);}// 重新开始function reBeginGame() {food = [[5, 5]]snake = [[0, 12], [0, 13], [0, 14]]direction = 3score.innerHTML = 0beginGame()}// 游戏暂停function suspendGame() {clearInterval(start)}// 监听键盘事件 爬行方向window.onkeydown = function (e) {const { keyCode } = eif (keyCode === 74) {return beginGame()}if (keyCode === 75) {return suspendGame()}if (keyCode === 82) {return reBeginGame()}if (keyCode === 37 && direction !== 3) {return direction = 1}if (keyCode === 38 && direction !== 4) {return direction = 2}if (keyCode === 39 && direction !== 1) {return direction = 3}if (keyCode === 40 && direction !== 2) {return direction = 4}}// 判断是否吃到食物function eatFood() {if (food.length === 0) return// 蛇头和食物重合及吃到食物if (snake[snake.length - 1].toString() === food[0].toString()) {// 成长growUp()// 重新生成食物createFood()}}// 吃到食物 进行成长function growUp() {let snakeFood = []let [x, y] = snake[snake.length - 1]// 按照蛇头的方向在蛇头处成长if (direction === 1) {snakeFood = [x, y - 1]} else if (direction === 2) {snakeFood = [x - 1, y]} else if (direction === 3) {snakeFood = [x, y + 1]} else if (direction === 4) {snakeFood = [x + 1, y]}snake.push(snakeFood)// 重算积分(积分=蛇当前长度-初始长度)score.innerHTML = snake.length - 3}})()
</script>

后续继续补充…


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部