JavaScript实现贪吃蛇游戏完整教程

作者:木棉时间:2026-10-23 16:36:14浏览:626

本文详细介绍如何使用JavaScript从零构建贪吃蛇游戏。内容涵盖HTML结构搭建、CSS绝对定位样式设置,以及核心脚本逻辑:包括蛇身初始化、随机食物生成算法、定时器控制移动、边界穿越处理、方向键监听与防反向判定,以及碰撞检测机制。提供完整可运行代码,适合前端初学者理解游戏开发基础。

本文分享了一个使用JavaScript编写的贪吃蛇游戏完整示例,供读者参考学习。

页面结构与样式设计

1. 页面结构

首先构建HTML结构,创建一个id为box的容器作为蛇身的载体。初始状态下,box内仅包含一个子div,代表蛇的初始长度为1。同时,创建一个id为food的div元素,用于显示游戏目标食物。


<div id="box">
  <div></div>
</div>
<div id="food"></div>

2. CSS样式设计

定义蛇身和食物的视觉样式。关键点在于将蛇身子元素和食物元素均设置为绝对定位(absolute),以便通过JavaScript动态控制其坐标位置。


<style>
 *{
  padding: 0px;
  margin: 0px;
 }
 #box div{
  width: 30px;
  height: 30px;
  box-sizing: border-box;
  background: green;
  border: 1px solid black;
  position: absolute;
 }
 #food{
  width: 30px;
  height: 30px;
  background: brown;
  position: absolute;
 }
 </style>

3. 脚本逻辑实现

在JavaScript中,首先获取蛇身容器box及其内部所有子元素(代表蛇的每一节身体)。


var box = document.getElementById("box");
var boxs = document.getElementById("box").children;

接着,定义变量来记录蛇头当前的X和Y坐标位置。


var snackX = 0;
var snackY = 0;

获取浏览器窗口的可视区域宽度和高度,据此计算蛇身移动的最大边界值(minsnackX, maxsnackX, minsnackY, maxsnackY),从而限制蛇的活动范围。


var cw = document.documentElement.clientWidth;
 var ch = document.documentElement.clientHeight;
 var minsnackX = 0;
 var maxsnackX = Math.floor(cw / boxs[0].offsetWidth)*boxs[0].offsetWidth;
 var minsnackY = 0;
 var maxsnackY = Math.floor(ch / boxs[0].offsetHeight)*boxs[0].offsetHeight;

初始化蛇的移动方向,默认设置为向右("right")。


var turn = "right";

获取食物DOM元素,并定义变量存储食物的坐标位置。


 var foodele = document.getElementById("food");
 var foodX,foodY;

执行蛇的初始化操作,通过循环向box容器中克隆添加子元素,使蛇的初始长度达到设定值(例如6节)。


for(var i = 0; i <6 ; i++){
  box.appendChild(boxs[0].cloneNode(true));
 }

实现食物刷新逻辑,确保每次生成新食物时,其位置不与蛇身任何一节重合。


function food(){
 //此处的坐标要先获取页面最大支持的蛇身体的块数,然后在块数中随机,然后乘以块数的大小,
 //因为蛇的移动每一步都是固定的,想要判定食物和蛇头重合就必须坐标是整块的倍数。
  foodX = parseInt( Math.random()*Math.floor(cw / boxs[0].offsetWidth))*boxs[0].offsetWidth;
  foodY = parseInt( Math.random()*Math.floor(ch / boxs[0].offsetHeight))*boxs[0].offsetHeight;
  //判定当食物的产生位置和蛇的任何一个位置重合时就重新生成食物。
  for(var i = 0;i<boxs.length;i++){
   if(foodX + "px" === boxs[i].style.left && foodY + "px" === boxs[i].style.top){
    food();
   }
  }
  foodele.style.left = foodX + "px";
  foodele.style.top = foodY + "px";
 }

调用food()函数生成游戏开始时的第一个食物位置。


food();

使用setInterval设置定时器,每隔固定时间(如150毫秒)执行一次蛇的移动函数,控制游戏节奏。


var timer = setInterval(function(){
  snackMOve();
 },150)

核心脚本逻辑实现

封装核心移动函数snackMOve(),负责更新蛇头坐标、处理边界穿越、检测碰撞及更新DOM位置。


//移动和判定边界
 function snackMOve(){
//此处为判定方向 根据判定的方向,向改方向前进一个方块
  switch(turn){
   case "right":snackX +=30;break;
   case "left":snackX -=30;break;
   case "bottom":snackY +=30;break;
   case "top":snackY -=30;break;
  }
  //如果蛇越过了墙就从另一端出现
  if(snackX > maxsnackX){
   snackX = 0;
  }
  if(snackX < minsnackX){
   snackX = maxsnackX;
  }
  if(snackY > maxsnackY){
   snackY = 0;
  } 
  if(snackY < minsnackY){
   snackY = maxsnackY;
  }
  //从最后一个开始,每个元素跟随上一个元素的位置
  for(var i = boxs.length-1; i >0 ; i--){
   boxs[i].style.left = boxs[i-1].style.left;
   boxs[i].style.top = boxs[i-1].style.top ;
  }
  //第一个也就是蛇头的位置,永远是根据方向获取的位置
  boxs[0].style.left = snackX + "px";
  boxs[0].style.top = snackY + "px" ;


  //判定吃到食物 就长大和刷新
  //当蛇头位置移动之后与食物重合 那么刷新食物,并且在蛇的身体中插入一个克隆的元素,相当于长度+1
  if(snackX === foodX && snackY === foodY){
   food();
   box.appendChild(boxs[0].cloneNode(true));
  }else{
  //判定撞死 
  //当蛇头与身体中的任何一个元素重合,那么判定结束游戏,停止定时器
   for(var i = 1;i<boxs.length;i++){
    if(snackX + "px" === boxs[i].style.left && snackY + "px" === boxs[i].style.top){
     clearInterval(timer);
     alert("失败");
    }
   }
  }
 }

通过监听键盘事件(keydown)改变移动方向变量turn,实现玩家对蛇运动方向的控制。


document.onkeydown = function(eve){
 var e = eve||event;
 var keyCode = e.keyCode||e.which;
 switch(keyCode){
  case 37:if(turn === "right"){break;}turn = "left";break;
  case 38:if(turn === "bottom"){break;}turn = "top";break;
  case 39:if(turn === "left"){break;}turn = "right";break;
  case 40:if(turn === "top"){break;}turn = "bottom";break;
 }  
}

以下是完整的HTML、CSS和JavaScript代码实现。


<!DOCTYPE html>
<html lang="en">
<head>
 <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>Document</title>
 <style>
 *{
  padding: 0px;
  margin: 0px;
 }
 #box div{
  width: 30px;
  height: 30px;
  box-sizing: border-box;
  background: green;
  border: 1px solid black;
  position: absolute;
 }
 #food{
  width: 30px;
  height: 30px;
  background: brown;
  position: absolute;
 }
 </style>
</head>
<body>
 <div id="box">
  <div></div>
 </div>
 <div id="food"></div>
 <script>
  var box = document.getElementById("box");
  var boxs = document.getElementById("box").children;
  var snackX = 0;
  var snackY = 0;
  var cw = document.documentElement.clientWidth;
  var ch = document.documentElement.clientHeight;
  var minsnackX = 0;
  var maxsnackX = Math.floor(cw / boxs[0].offsetWidth)*boxs[0].offsetWidth;
  var minsnackY = 0;
  var maxsnackY = Math.floor(ch / boxs[0].offsetHeight)*boxs[0].offsetHeight;
  var turn = "right";
  var foodele = document.getElementById("food");
  var foodX,foodY;

  for(var i = 0; i <6 ; i++){
   box.appendChild(boxs[0].cloneNode(true));
  }


  //随机食物
  function food(){
   foodX = parseInt( Math.random()*Math.floor(cw / boxs[0].offsetWidth))*boxs[0].offsetWidth;
   foodY = parseInt( Math.random()*Math.floor(ch / boxs[0].offsetHeight))*boxs[0].offsetHeight;
   for(var i = 0;i<boxs.length;i++){
    if(foodX + "px" === boxs[i].style.left && foodY + "px" === boxs[i].style.top){
     food();
    }
   }
   foodele.style.left = foodX + "px";
   foodele.style.top = foodY + "px";
  }
  food();

  //设置定时器 移动
  var timer = setInterval(function(){
   snackMOve();
  },150)


  //移动和判定边界
  function snackMOve(){
   switch(turn){
    case "right":snackX +=30;break;
    case "left":snackX -=30;break;
    case "bottom":snackY +=30;break;
    case "top":snackY -=30;break;
   }
   //根据边界归零
   if(snackX > maxsnackX){
    snackX = 0;
   }
   if(snackX < minsnackX){
    snackX = maxsnackX;
   }
   if(snackY > maxsnackY){
    snackY = 0;
   } 
   if(snackY < minsnackY){
    snackY = maxsnackY;
   }
   for(var i = boxs.length-1; i >0 ; i--){
    boxs[i].style.left = boxs[i-1].style.left;
    boxs[i].style.top = boxs[i-1].style.top ;
   }
   boxs[0].style.left = snackX + "px";
   boxs[0].style.top = snackY + "px" ;


   //判定吃到食物 就长大和刷新
   if(snackX === foodX && snackY === foodY){
    food();
    box.appendChild(boxs[0].cloneNode(true));
   }else{
   //判定撞死 暂停计时器 刷新
    for(var i = 1;i<boxs.length;i++){
     // console.log(boxs[i].style.left);
     if(snackX + "px" === boxs[i].style.left && snackY + "px" === boxs[i].style.top){
      clearInterval(timer);
      alert("失败");
      // console.log(1)
     }
    }
   }
  }


  //方向
  document.onkeydown = function(eve){
   var e = eve||event;
   var keyCode = e.keyCode||e.which;
   switch(keyCode){
    case 37:if(turn === "right"){break;}turn = "left";break;
    case 38:if(turn === "bottom"){break;}turn = "top";break;
    case 39:if(turn === "left"){break;}turn = "right";break;
    case 40:if(turn === "top"){break;}turn = "bottom";break;
   }  
  }
 </script>
</body>
</html>

游戏逻辑总结

总结

贪吃蛇游戏的核心开发思路主要包含以下关键环节:

1. 食物随机生成逻辑(需确保不生成在蛇身坐标上); 2. 利用定时器(setInterval)控制蛇的移动频率; 3. 边界碰撞判定(穿越墙壁后从另一侧出现); 4. 蛇身运动逻辑(头部移动,身体跟随); 5. 运动方向判定与键盘事件监听; 6. 吃到食物的判定(头部坐标与食物坐标重合); 7. 蛇头与身体碰撞判定(即游戏结束条件)。

此外,还推荐参考JavaScript经典小游戏汇总专题,获取更多游戏开发案例。

以上就是JavaScript实现贪吃蛇游戏的完整教程,希望能为读者的前端学习提供有益帮助。

作者最新文章