JS实现——贪吃蛇

把以下代码保存成Snake.html文件,使用Google或360浏览器打开

<!DOCTYPE HTML>
<html>

<head>
  <meta charset="utf-8" />
  <title>Snake</title>
<style>
</style>
</head>

<body>
<div style="position: relative">

  <div style="width: 400px; font-size: 22px; border: 3px solid black;">
    分数:<span id="score"></span>
  </div>

  <canvas id="myCanvas">your browser does not support the canvas</canvas>

  <div id="help" style="position: absolute; left: 420px; top: 40px;">
    Esc: 重新开始</br>
    Enter: 开始/暂停/继续</br>
    方向键: 改变蛇的移动方向</br>
    Ctrl: 切换控制模式(影响手感)</br>
    数字1: 加速</br>
    数字2: 减速</br>
  </div>

  <div id="gameStates" style="position: absolute; left: 420px; top: 200px; color: red">
    控制模式: <span id="controlMode"></span></br>
    运动状态: <span id="pause"></span></br>
    蛇的方向: <span id="snakeDir"></span></br>
    蛇的速度: <span id="snakeSpeed"></span></br>
    蛇的长度: <span id="snakeLength"></span></br>
    <span id="info"></span>
  </div>

</div>
</body>

<script type="text/javascript">
/*
 By Problue,2015.10.15
*/
var KEY_L = 37;
var KEY_U = 38;
var KEY_R = 39;
var KEY_D = 40;
var KEY_RESET = 27
var KEY_PAUSE = 13;
var KEY_CHANGE_CONTROL_MODE = 17;
var KEY_INC_SPEED = 49;
var KEY_DEC_SPEED = 50;
var MAP_R = 20;
var MAP_C = 20;
var SNAKE_LENGTH_MAX = MAP_R * MAP_C;
var OBJ_SIZE = 20;
var OBJ = {
  EMPTY: 0,
  SNAKE_HEAD: 1,
  SNAKE_BODY: 2,
  SNAKE_TAIL: 3,
  FOOD: 4,
  STONE: 5
};
var colors = [‘white‘, ‘midnightblue‘, ‘darkblue‘, ‘mediumblue‘, ‘midnightblue‘, ‘dimgray‘];

var mapData = "0000000000000000000000000000000000000000000000000000000000005000000050000005500000000000000000005000000550000000055000000005000000000050000000000550000550000000000005000000500000000000000000000000000000000000000000000000000000050000500000000000000550055000000000000500000000500000000005500000055000000005000000000000000000055000000000050005000000000000000000000000000000000000000000000000000000000000";

var map = [];

var snake = new Snake();
var food = new Point(0, 0);
//var time;

var pause;
var over;
var controlQueueMode;
var controlQueue = new Queue();
var score;

function Snake() {
  this.nodes = [];
  this.dir = 0;
  this.msSpeed = 0;
}

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.clone = function() {
  return new Point(this.x, this.y);
}

Point.prototype.equals = function(other) {
  if(other === this)
    return true;
  if(!(other instanceof Point))
    return false;
  return this.x == other.x && this.y == other.y;
}

function Queue() {
  this.arr = [];
  this.head = 0;
  this.tail = 0;
}

Queue.prototype.enQueue = function(elem) {
  this.tail++;
  this.arr[this.tail] = elem;
}

Queue.prototype.deQueue = function() {
  this.head++;
  return this.arr[this.head];
}

Queue.prototype.empty = function() {
  return this.head >= this.tail;
}

Queue.prototype.clear = function() {
  this.arr.length = 0;
  this.head = 0;
  this.tail = 0;
}

start();

function start() {
  initGame();
  initMap();
  initSnake();
  drawMap();
  showGameStates();
  updateScore();
  drawSnake();
  randFood();
  drawObj(food, OBJ.FOOD);
}

function initGame() {
  canvas = document.getElementById(‘myCanvas‘);
  cxt = canvas.getContext(‘2d‘);
  canvas.width = MAP_C * OBJ_SIZE;
  canvas.height = MAP_R * OBJ_SIZE;
  canvas.style.border = ‘3px solid black‘;
  document.onkeydown = keydown;
  //time = +new Date;
  pause = true;
  over = 0;
  controlQueueMode = true;
  score = 0;
}

function initMap() {
  for(var r = 0; r < MAP_R; r++) {
    map.push([]);
    for(var c = 0; c < MAP_C; c++) {
      var obj = mapData[r * MAP_C + c] - 0;
      map[r][c] = obj;
    }
  }
}

function initSnake() {
  snake.nodes.length = 0;
  snake.nodes.push(new Point(2, 0));
  snake.nodes.push(new Point(1, 0));
  snake.nodes.push(new Point(0, 0));
  snake.dir = KEY_R;
  snake.msSpeed = 150;
}

function keydown(event) {
  var key = window.event ? event.keyCode : event.which;
  switch(key) {
  case KEY_U:
    if(snake.dir != KEY_D) {
      snake.dir = key;
      controlQueue.enQueue(snake.dir);
    }
    break;
  case KEY_D:
    if(snake.dir != KEY_U) {
      snake.dir = key;
      controlQueue.enQueue(snake.dir);
    }
    break;
  case KEY_L:
    if(snake.dir != KEY_R) {
      snake.dir = key;
      controlQueue.enQueue(snake.dir);
    }
    break;
  case KEY_R:
    if(snake.dir != KEY_L) {
      snake.dir = key;
      controlQueue.enQueue(snake.dir);
    }
    break;
  case KEY_RESET:
    start();
    break;
  case KEY_PAUSE:
    pause = !pause;
    if(!pause) {
      controlQueue.clear();
      move();
    }
    break;
  case KEY_CHANGE_CONTROL_MODE:
    controlQueueMode = !controlQueueMode;
    controlQueue.clear();
    break;
  case KEY_INC_SPEED:
    snake.msSpeed -= 10;
    break;
  case KEY_DEC_SPEED:
    snake.msSpeed += 10;
    break;
  default: ;
  }
  showGameStates();
}

function moveStep() {
  showGameStates();
  var newHead = snake.nodes[0].clone();
  var oldTail = snake.nodes[snake.nodes.length - 1].clone();

  switch(snake.dir) {
  case KEY_U:
    newHead.y--;
    break;
  case KEY_R:
    newHead.x++;
    break;
  case KEY_L:
    newHead.x--;
    break;
  case KEY_D:
    newHead.y++;
    break;
  }

  var coord = ‘坐标(‘ + snake.nodes[0].x + ‘,‘ + snake.nodes[0].y + ‘)是‘;
  info(coord + ‘空‘);
  if((newHead.x > MAP_C - 1 || newHead.x < 0) ||
     (newHead.y > MAP_R - 1 || newHead.y < 0)) {
    info(coord + ‘墙壁‘);
    over = 1;
    return;
  }

  if(isInSnake(newHead)) {
    info(coord + ‘自己‘);
    over = 2;
    return;
  }

  var thing = map[newHead.y][newHead.x];

  if(thing == OBJ.STONE) {
    info(coord + ‘石头‘);
    over = 3;
    return;
  }

  if(thing == OBJ.FOOD) {
    info(coord + ‘食物‘);
    snake.nodes.push(new Point(0, 0));
    map[newHead.y][newHead.x] = OBJ.EMPTY;
    randFood();
    drawObj(food, OBJ.FOOD);
    updateScore();
    showGameStates();
  }

  for(var i = snake.nodes.length - 1; i >= 1; i--)
    snake.nodes[i] = snake.nodes[i - 1].clone();
  snake.nodes[0] = newHead;
  drawObj(oldTail, OBJ.EMPTY);
  drawSnake();
}

function move() {
  if(pause)
    return;

  if(controlQueueMode && !controlQueue.empty())
    snake.dir = controlQueue.deQueue();

  moveStep();

  if(over) {
    over = 0;
    var turn = [];
    turn[KEY_U] = KEY_R;
    turn[KEY_D] = KEY_L;
    turn[KEY_L] = KEY_U;
    turn[KEY_R] = KEY_D;
    snake.dir = turn[snake.dir];
  }

  setTimeout(move, snake.msSpeed);
}

function isInSnake(point) {
  for(var i = 0; i < snake.nodes.length; i++)
    if(snake.nodes[i].equals(point))
      return true;
  return false;
}

function randFood() {
  function randInt(n, m) {
    return Math.floor(Math.random() * (m - n)) + n;
  }
  function smart(pt) {
    if(pt.x == snake.nodes[0].x) {
      if(snake.dir == KEY_U)
        return pt.x - snake.nodes[0].x < 0;
      if(snake.dir == KEY_D)
        return pt.x - snake.nodes[0].x > 0;
    }
    if(pt.y == snake.nodes[0].y) {
      if(snake.dir == KEY_L)
        return pt.y - snake.nodes[0].y < 0;
      if(snake.dir == KEY_R)
        return pt.y - snake.nodes[0].y > 0;
    }
    return false;
  }
  do
  {
    food.x = randInt(0, MAP_C);
    food.y = randInt(0, MAP_R);
  } while(isInSnake(food) || smart(food) ||
    map[food.y][food.x] != OBJ.EMPTY);
  map[food.y][food.x] = OBJ.FOOD;
}

function info(str) {
  $(‘info‘).innerHTML = str;
}

function showGameStates() {
  $(‘pause‘).innerHTML = pause ? ‘静止‘ : ‘移动‘;
  $(‘controlMode‘).innerHTML = controlQueueMode ? ‘队列‘ : ‘普通‘;
  var toText = [];
  toText[KEY_L] = ‘左‘;
  toText[KEY_U] = ‘上‘;
  toText[KEY_R] = ‘右‘;
  toText[KEY_D] = ‘下‘;
  $(‘snakeDir‘).innerHTML = toText[snake.dir];
  $(‘snakeSpeed‘).innerHTML = snake.msSpeed + ‘ms/‘ + OBJ_SIZE + ‘px‘;
  $(‘snakeLength‘).innerHTML = snake.nodes.length;
}

function updateScore() {
  $(‘score‘).innerHTML = score++;
}

function drawMap() {
  var pt = new Point(0, 0);
  for(var r = 0; r < MAP_R; r++) {
    for(var c = 0; c < MAP_C; c++) {
      if(map[r][c] == OBJ.STONE) {
        pt.x = c;
        pt.y = r;
        drawObj(pt, OBJ.STONE);
      }
    }
  }
}

function drawSnake() {
  drawObj(snake.nodes[0], OBJ.SNAKE_HEAD);
  for(var i = 1; i < snake.nodes.length - 1; i++)
    drawObj(snake.nodes[i], OBJ.SNAKE_BODY);
  drawObj(snake.nodes[snake.nodes.length - 1], OBJ.SNAKE_TAIL);
}

function drawObj(point, type) {
  cxt.fillStyle = colors[type];
  cxt.fillRect(point.x * OBJ_SIZE, point.y * OBJ_SIZE,
    OBJ_SIZE, OBJ_SIZE);
}

function $(id) {
  return document.getElementById(id);
}
</script>

</html>

出处:qq群--编程算法&思想 459909287

时间: 2025-01-04 15:26:43

JS实现——贪吃蛇的相关文章

JS仿贪吃蛇:一串跟着鼠标的Div

贪吃蛇是一款80后.90后比较熟悉的经典游戏,下面通过简单的JS代码来实现低仿版贪吃蛇效果:随着鼠标的移动,在页面中呈现所有Div块跟随鼠标依次移动,效果如下图所示. <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>习题-仿select下拉框</title> <style> div {

使用前端原生 js,贪吃蛇小游戏

好久好久,真的是好久好久没来写过了,因为最近有点小忙.不过即使是忙,也也还是写了两个小游戏,其中一个就是这个,贪吃蛇啦. 算是一个小练手了,这个是在有点太简单了,只是第一次写这种小游戏,还是零零星星花了三五天时间,下面就是这个小游戏的gif小动画,比较简单,对比过网上其他用来写出来练手的贪吃蛇作品,这个在颜值还是功能上,都还是不错的,霍霍. 这里讲解一下功能: 空格控制开始和暂停. 方向键控制移动方向. Q 键加速,再按一次恢复常规速度(在加速状态时,按下或者方向键,或者吃到了白色小食物,速度自

JS编写贪吃蛇(面向对象思想)

效果图:(抱歉,由于本人能力有限,只能暂时放静态图.后期会把动态图更新上去) <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8"> <title></title> <style> #map { width: 500px; height:500px; position:relative; background: #cc

13行js写贪吃蛇游戏

先上源码,版本是ES6 13行常规(700bytes) shortest snake game.html 压缩后的500bytes(当然两处document还是可以用eval压缩的) index.500bytes.html 之前很火的20行代码地址(有BUG)(900bytes) hj7jay/article/details/51011269 一维数组700char (0,0)位置的蛇身用0表示,(0,1)用1,(1,0)用10表示,以此类推 因为就13行js, 第4行 是声明 第5行 比较难理

原生JS实现贪吃蛇项目,附源码下载!

运行于谷歌浏览器.主要是利用了函数的封装思想,把每一个小功能分别封装在一个函数中,大大提高了代码的可扩展性!!提高了代码的可维护性!!!提高了代码的可阅读性!!!项目要求:1:有边界,碰到边界就game over.2:猎物没3秒增加一个,而且位置随机产生.3:吃一个猎物自身就增加一个元素.4:按上下左右控制移动方向,按空格决定暂停和前进. 实现思路:主要是一开始就把实现的功能封装在了一个先函数中去了,所以后续的功能增加就比较容易了.1:先画出了边界,就是实现了设置边界的函数.2:实现判断按键功能

javascript:用原生js模拟贪吃蛇游戏练习

本次练习所有的代码:可以直接复制全部然后运行看效果~ 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>title</title> 6 <style> 7 .map { 8 width: 800px; 9 height: 600px; 10 background-color:

js制作贪吃蛇小游戏

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> #map{ width: 800px; height: 800px; background-color: black; position: relative; } </style> <

OC版贪吃蛇

昨天写了一个js版贪吃蛇,今天突然想写一个OC版的,来对比一下两种语言的区别 oc版功能,适配所有尺寸iphone,可暂停,可设置地图和蛇的比例,可加速 对比一下会发现js版的相对OC版的会简单一些,有想看js版的可以看我上一篇随笔 程序中没用到任何素材,效果图如下: github源码地址:https://github.com/masterChunlinHan/snake_OC 下面开始,跟js版一样,为了方便学习,所有代码都写在一个controller中,所以头文件中什么也不用写 #impor

JS贪吃蛇游戏

<!DOCTYPE html><html> <head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>JS贪吃蛇游戏</title>    <style>    * {        margin: 0;