前端技术搭建贪吃蛇小游戏(内含源码)

功能介绍

以下是贪吃蛇小游戏的玩法和规则:游戏开始时,玩家控制一条小蛇在游戏区域内移动,通过吃食物来增加分数。小蛇的移动方向由玩家控制,可以使用键盘上的方向键来控制小蛇的移动方向。当小蛇吃到食物时,它会变长,并且玩家的分数会增加。如果小蛇撞到了游戏区域的边界或者自己的身体,游戏结束。

 页面搭建

这段代码是贪吃蛇小游戏的DOM结构代码,它包含了游戏的各个元素和界面布局。具体来说:

<p>贪吃蛇</p>:这是一个段落元素,用于显示游戏的标题。<div class="gamBox">:这是一个div元素,用于包裹整个游戏界面。<div class="screen">:这是一个div元素,用于显示游戏区域。<div class="snake">:这是一个div元素,用于显示贪吃蛇。<div class="snake-head">:这是一个div元素,用于显示贪吃蛇的头部。<span>😡</span>:这是一个span元素,用于显示贪吃蛇头部的表情。<div class="snake-body">:这是一个div元素,用于显示贪吃蛇的身体。<div class="food">:这是一个div元素,用于显示食物。<span>🐷</span>:这是一个span元素,用于显示食物的图标。<div class="integral">:这是一个div元素,用于显示游戏的积分信息。<div>等级(grade)<span class="grade"></span></div>:这是一个div元素,用于显示游戏的等级信息。<div>分数(score)<span class="score"></span></div>:这是一个div元素,用于显示游戏的分数信息。
 

<body>

  <p>贪吃蛇</p>
  <div class="gamBox">

    <div class="screen">
      <div class="snake">
        <div class="snake-head">

          <span>😡</span>

        </div>
        <div class="snake-body">
        </div>
      </div>

      <div class="food">
        <span>🐷</span>
      </div>
    </div>
    <div class="integral">
      <div>等级(grade)<span class="grade"></span></div>
      <div>分数(score)<span class="score"></span></div>
    </div>
  </div>

</body>

 样式设置

*:设置所有元素的样式。margin: 0;padding: 0;:将所有元素的外边距和内边距设置为0。box-sizing: border-box;:将元素的盒模型设置为border-boxp:设置段落元素的样式。text-align: center;:将段落元素的文本居中对齐。font-size: 23px;font-weight: 600;:设置段落元素的字体大小和字体粗细。.gamBox:设置游戏界面的样式,包括宽度、高度、边框、背景颜色、圆角、布局等。.integral:设置游戏积分信息的样式,包括宽度、高度、布局、字体大小、字体粗细等。.screen:设置游戏区域的样式,包括宽度、高度、边框、位置等。.snake:设置贪吃蛇的样式,包括头部和身体的样式。.food:设置食物的样式,包括宽度、高度、字体大小、位置等。

<style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }

    p {
        text-align: center;
        font-size: 23px;
        font-weight: 600;
    }

    .gamBox {
        width: 500px;
        height: 500px;
        border: 10px solid #393c1b;
        margin: 20px auto;
        background-color: #b6b327;
        border-radius: 20px;
        display: flex;
        flex-direction: column;
        justify-content: space-around;
        align-items: center;


    }

    /* //下方等级、得分盒子/ */
    .integral {
        width: 398px;
        height: 25px;
        display: flex;
        justify-content: space-between;
        font-size: 16px;
        font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande",
            "Lucida Sans", Arial, sans-serif;
        font-weight: 700;
    }

    /* //屏幕样式 */
    .screen {
        width: 400px;
        height: 400px;
        border: 1px solid #000;
        position: relative;



    }

    /* //蛇的样式 */
    .snake .snake-head {
        width: 20px;
        height: 20px;
        border: 1px solid #4d7d2b;
        background-color: #000;
        position: absolute;
        top: 0;
        left: 0;

    }

    .snake span {
        font-size: 17px;
        position: absolute;
        left: -2.7px;
        top: -3px;
    }

    .snake-body>div {
        position: absolute;
        top: 0;
        left: 0;
        width: 20px;
        height: 20px;
        border: 1px solid #4d7d2b;
        background-color: #000;
    }


    /* //食物的样式 */

    .food {
        width: 20px;
        height: 20px;
        font-size: 8px;
        text-align: left;
        position: absolute;
        top: 10px;
        left: 0;

    }

    .food span {
        font-size: 17px;
        position: absolute;
        left: -1.7px;
        top: -2px;
    }
</style>

 js逻辑部分

  •  foundationNumber:基础倍数,用于移动和食物随机位置计算。
  • maxGrade:最大等级。

以下是函数的作用:

  • randomNumber(min, max):生成指定范围内的随机整数。
  • changeFoodSeat():改变食物的位置。
  • changeScore():改变分数和等级。
  • handleWatchEnter(e):处理按键事件,控制蛇的移动和吃食物。
  • throttle(fn, wait):函数节流,用于控制蛇的移动速度。
  • init():初始化游戏,设置初始状态和界面。

以下是变量的作用:

  • direction:蛇的移动方向。
  • snakeLength:蛇身体的长度数组。
  • snakeSeat:蛇头的位置。
  • foodSeat:食物的位置。
  • register:存储分数和等级的对象。

在页面加载完成后,监听键盘按下事件,根据按键改变移动方向。然后调用 init 函数初始化游戏。在 init 函数中,设置蛇头位置,清空蛇身体,显示等级和分数,改变食物位置,并调用 handleWatchEnter 函数开始处理蛇的移动。在 handleWatchEnter 函数中,根据移动方向更新蛇身体的位置,判断是否吃到食物并处理相关逻辑,检测是否碰到墙壁或自身,更新蛇头位置,最后通过递归调用自身实现连续移动。整体代码实现了贪吃蛇游戏的逻辑,包括蛇的移动、食物的生成和吃食物的判定,以及游戏结束的条件判断

<script>


  /***
   * 公用变量
   * @foundationNumber 基础倍数:移动、食物随机位置量的倍数
   * @maxGrade 最大的等级
   */

  const foundationNumber = 20
  const maxGrade = 10



  /***
   * 食物相关
   */
  const randomNumber = (min, max) => {
    return Math.floor(Math.random() * (max - min)) + min
  }
  let foodSeat = {
    top: 20,
    left: 20
  }
  const changeFoodSeat = () => {
    foodSeat.top = randomNumber(0, 20) * foundationNumber
    foodSeat.left = randomNumber(0, 20) * foundationNumber

    document.querySelector('.food').style.cssText = 'left:' + foodSeat.left + 'px;top:' + foodSeat.top + 'px'
  }


  /***
   * 等级、分数相关
   */
  let register = {
    score: 0,
    grade: 1
  }
  const changeScore = () => {
    register.score++
    if (register.grade < 10) {
      register.grade = Math.ceil(register.score / 10)
    }

    document.querySelector('.grade').innerText = register.grade
    document.querySelector('.score').innerText = register.score
  }


  /***
   * 蛇相关
   */

  let direction = ''//移动方向
  let snakeLength = []
  let snakeSeat = {
    top: 0,
    left: 0
  }
  const handleWatchEnter = e => {
    let previousTop = snakeSeat.top
    let previousLeft = snakeSeat.left
    //通过便利每个身体部分来进行移动
    snakeLength.forEach((ele, index) => {
      let temporaryTop = ele.top
      let temporaryLeft = ele.left
      ele.top = previousTop
      ele.left = previousLeft
      previousTop = temporaryTop
      previousLeft = temporaryLeft
      document.querySelectorAll('.snake-body>div')[index].style.cssText = 'left:' + ele.left + 'px;top:' + ele.top + 'px'
    });

    switch (direction) {
      case 'ArrowUp':
        snakeSeat.top -= 20
        break;
      case 'ArrowLeft':
        snakeSeat.left -= 20
        break;
      case 'ArrowRight':
        snakeSeat.left += 20
        break;
      case 'ArrowDown':
        snakeSeat.top += 20
        break;
    }


    if (snakeSeat.top == foodSeat.top && snakeSeat.left == foodSeat.left) {
      changeScore()
      changeFoodSeat()
      snakeLength.push({
        top: previousTop,
        left: previousLeft
      })

      var div = document.createElement('div');
      div.style.left = previousLeft + 'px';
      div.style.top = previousTop + 'px';
      div.class = 'bodyItem'


      document.querySelector('.snake-body').appendChild(div)

    }


    if (snakeSeat.top < 0 || snakeSeat.left < 0 || snakeSeat.left > 380 || snakeSeat.top > 380) {
      alert('撞墙身亡')
      snakeSeat.top = 0
      snakeSeat.left = 0
      direction = ''
      snakeLength = []
      init()

      return
    }

    let bodySeats = snakeLength.map(item => JSON.stringify(item))

    if ((bodySeats.indexOf(JSON.stringify({ top: snakeSeat.top, left: snakeSeat.left })) != -1)) {
      alert('把自己撞死了')
      snakeSeat.top = 0
      snakeSeat.left = 0
      snakeLength = []
      direction = ''
      init()
      return
    }
    document.querySelector('.snake-head').style.cssText = 'left:' + snakeSeat.left + 'px;top:' + snakeSeat.top + 'px'
    setTimeout(() => {
      handleWatchEnter()
    }, 400 - (register.grade - 1) * 15);
  }




  //函数节流
  const throttle = (fn, wait) => {
    var timer = null;
    return function () {
      var _this = this;
      var args = arguments;
      if (!timer) {
        timer = setTimeout(function () {
          fn.apply(_this, args);
          timer = null;
        }, wait);
      }
    }
  }


  const init = () => {

    document.querySelector('.snake-head').style.cssText = 'left:' + 0 + 'px;top:' + 0 + 'px'
    document.querySelector('.snake-body').innerHTML = ""
    document.querySelector('.grade').innerText = register.grade
    document.querySelector('.score').innerText = register.score
    changeFoodSeat()
    handleWatchEnter()
  }



  document.addEventListener('keydown', (e) => {

    if ((e.code == 'ArrowUp' && direction != 'ArrowDown') || (e.code == 'ArrowLeft' && direction != 'ArrowRight') || (e.code == 'ArrowRight' && direction != 'ArrowLeft') || (e.code == 'ArrowDown' && direction != 'ArrowUp')) {
      direction = e.code
    }
  });
  init()

</script>

完整代码


<!-- 

  Author profile:

  欢迎您朋友,感谢你的认可,我是几何心凉
  CSDN博客专家、内容合伙人、新星计划导师,
  Vue技能树构建者、阿里云社区专家博主,
  前端领域优质创作者致力于新技术的推广与优秀技术的普及。

  可提供简历、就业指导服务

  CSDN博客:https://blog.csdn.net/JHXL_
  公众号:#几何心凉的核心圈
  
 -->

<!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>凉哥的简易版贪吃蛇</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    p {
      text-align: center;
      font-size: 23px;
      font-weight: 600;
    }

    .gamBox {
      width: 500px;
      height: 500px;
      border: 10px solid #393c1b;
      margin: 20px auto;
      background-color: #b6b327;
      border-radius: 20px;
      display: flex;
      flex-direction: column;
      justify-content: space-around;
      align-items: center;


    }

    /* //下方等级、得分盒子/ */
    .integral {
      width: 398px;
      height: 25px;
      display: flex;
      justify-content: space-between;
      font-size: 16px;
      font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande",
        "Lucida Sans", Arial, sans-serif;
      font-weight: 700;
    }

    /* //屏幕样式 */
    .screen {
      width: 400px;
      height: 400px;
      border: 1px solid #000;
      position: relative;



    }

    /* //蛇的样式 */
    .snake .snake-head {
      width: 20px;
      height: 20px;
      border: 1px solid #4d7d2b;
      background-color: #000;
      position: absolute;
      top: 0;
      left: 0;

    }

    .snake span {
      font-size: 17px;
      position: absolute;
      left: -2.7px;
      top: -3px;
    }

    .snake-body>div {
      position: absolute;
      top: 0;
      left: 0;
      width: 20px;
      height: 20px;
      border: 1px solid #4d7d2b;
      background-color: #000;
    }


    /* //食物的样式 */

    .food {
      width: 20px;
      height: 20px;
      font-size: 8px;
      text-align: left;
      position: absolute;
      top: 10px;
      left: 0;

    }

    .food span {
      font-size: 17px;
      position: absolute;
      left: -1.7px;
      top: -2px;
    }
  </style>
</head>

<body>

  <p>贪吃蛇</p>
  <div class="gamBox">

    <div class="screen">
      <div class="snake">
        <div class="snake-head">

          <span>😡</span>

        </div>
        <div class="snake-body">
        </div>
      </div>

      <div class="food">
        <span>🐷</span>
      </div>
    </div>
    <div class="integral">
      <div>等级(grade)<span class="grade"></span></div>
      <div>分数(score)<span class="score"></span></div>
    </div>
  </div>

</body>

<script>


  /***
   * 公用变量
   * @foundationNumber 基础倍数:移动、食物随机位置量的倍数
   * @maxGrade 最大的等级
   */

  const foundationNumber = 20
  const maxGrade = 10



  /***
   * 食物相关
   */
  const randomNumber = (min, max) => {
    return Math.floor(Math.random() * (max - min)) + min
  }
  let foodSeat = {
    top: 20,
    left: 20
  }
  const changeFoodSeat = () => {
    foodSeat.top = randomNumber(0, 20) * foundationNumber
    foodSeat.left = randomNumber(0, 20) * foundationNumber

    document.querySelector('.food').style.cssText = 'left:' + foodSeat.left + 'px;top:' + foodSeat.top + 'px'
  }


  /***
   * 等级、分数相关
   */
  let register = {
    score: 0,
    grade: 1
  }
  const changeScore = () => {
    register.score++
    if (register.grade < 10) {
      register.grade = Math.ceil(register.score / 10)
    }

    document.querySelector('.grade').innerText = register.grade
    document.querySelector('.score').innerText = register.score
  }


  /***
   * 蛇相关
   */

  let direction = ''//移动方向
  let snakeLength = []
  let snakeSeat = {
    top: 0,
    left: 0
  }
  const handleWatchEnter = e => {
    let previousTop = snakeSeat.top
    let previousLeft = snakeSeat.left
    //通过便利每个身体部分来进行移动
    snakeLength.forEach((ele, index) => {
      let temporaryTop = ele.top
      let temporaryLeft = ele.left
      ele.top = previousTop
      ele.left = previousLeft
      previousTop = temporaryTop
      previousLeft = temporaryLeft
      document.querySelectorAll('.snake-body>div')[index].style.cssText = 'left:' + ele.left + 'px;top:' + ele.top + 'px'
    });

    switch (direction) {
      case 'ArrowUp':
        snakeSeat.top -= 20
        break;
      case 'ArrowLeft':
        snakeSeat.left -= 20
        break;
      case 'ArrowRight':
        snakeSeat.left += 20
        break;
      case 'ArrowDown':
        snakeSeat.top += 20
        break;
    }


    if (snakeSeat.top == foodSeat.top && snakeSeat.left == foodSeat.left) {
      changeScore()
      changeFoodSeat()
      snakeLength.push({
        top: previousTop,
        left: previousLeft
      })

      var div = document.createElement('div');
      div.style.left = previousLeft + 'px';
      div.style.top = previousTop + 'px';
      div.class = 'bodyItem'


      document.querySelector('.snake-body').appendChild(div)

    }


    if (snakeSeat.top < 0 || snakeSeat.left < 0 || snakeSeat.left > 380 || snakeSeat.top > 380) {
      alert('撞墙身亡')
      snakeSeat.top = 0
      snakeSeat.left = 0
      direction = ''
      snakeLength = []
      init()

      return
    }

    let bodySeats = snakeLength.map(item => JSON.stringify(item))

    if ((bodySeats.indexOf(JSON.stringify({ top: snakeSeat.top, left: snakeSeat.left })) != -1)) {
      alert('把自己撞死了')
      snakeSeat.top = 0
      snakeSeat.left = 0
      snakeLength = []
      direction = ''
      init()
      return
    }
    document.querySelector('.snake-head').style.cssText = 'left:' + snakeSeat.left + 'px;top:' + snakeSeat.top + 'px'
    setTimeout(() => {
      handleWatchEnter()
    }, 400 - (register.grade - 1) * 15);
  }




  //函数节流
  const throttle = (fn, wait) => {
    var timer = null;
    return function () {
      var _this = this;
      var args = arguments;
      if (!timer) {
        timer = setTimeout(function () {
          fn.apply(_this, args);
          timer = null;
        }, wait);
      }
    }
  }


  const init = () => {

    document.querySelector('.snake-head').style.cssText = 'left:' + 0 + 'px;top:' + 0 + 'px'
    document.querySelector('.snake-body').innerHTML = ""
    document.querySelector('.grade').innerText = register.grade
    document.querySelector('.score').innerText = register.score
    changeFoodSeat()
    handleWatchEnter()
  }



  document.addEventListener('keydown', (e) => {

    if ((e.code == 'ArrowUp' && direction != 'ArrowDown') || (e.code == 'ArrowLeft' && direction != 'ArrowRight') || (e.code == 'ArrowRight' && direction != 'ArrowLeft') || (e.code == 'ArrowDown' && direction != 'ArrowUp')) {
      direction = e.code
    }
  });
  init()

</script>

</html>

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

耀南.

你的鼓励将是我最最最最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值