JS实现的贪吃蛇游戏案例详解


Posted in Javascript onMay 01, 2019

本文实例讲述了JS实现的贪吃蛇游戏。分享给大家供大家参考,具体如下:

github项目地址:https://github.com/LEERTRT/Snake

在<script></script>中,文档加载完毕后调用:

$(function () {
  var game = new Game("canvas");
  game.init();
});

其中构造函数Game()接收canvas的id作为参数,实例化对象以后,调用init()函数,init()函数里面有三个函数,接下来会一个一个说明。

/**
 * 初始化函数,生成构造函数实例后调用此函数
 */
this.init = function () {
  /**
   * 初始化画布和果实
   */
  this.initData();
  /**
   * 1.清空画布;2.画背景格子;3.画蛇;4.画果实
   */
  this.draw();
  /**
   * 绑定事件:方向和速度控制
   */
  this.bindEvents();
};

第一个,initData():在initData()函数里面,声明画布,果实,画布大小,格子数量,方向,速度,蛇等:

var canvas = document.getElementById(id);
if (canvas && canvas.getContext) {
  this.ctx = canvas.getContext('2d');
}
this.foodNode = null;//果实
this.size = canvas.width || $(canvas).width();//画布大小
this.columns = 50;//画布行列数
this.direction = 0;//方向
this.speed = 10;//速度
this.bodyNodes = [];//蛇体

然后随机生成蛇的位置:

var rdx = Math.round(Math.random() * (this.columns - 1));
var rdy = Math.round(Math.random() * (this.columns - 1));

把随机生成的rdx, rdy放进记录蛇体的数组中:

this.bodyNodes.push({
  x: rdx, y: rdy
});

到此,initData()完成。

第二个,draw():draw()函数包含四步:1.清空画布;2.画背景;3.画蛇;4.画果实:

this.draw = function () {
  /**
   * 清空画布
   */
  this.clear();
  /**
   * 画画布
   */
  this.drawBG();
  /**
   * 画蛇体
   */
  this.drawBody();
  /**
   *画果实
   */
  this.drawFood();
};

1.清空画布

使用clearRect(0,0,size,size)即可:

this.ctx.clearRect(0, 0, this.size, this.size);

2.画背景

每个格子大小 = 画布尺寸/格子数量,然后一行一行画就行了,和画棋盘一样:

var _this = this;
var x = 0, y = 0, size = _this.size / _this.columns;
_this.ctx.strokeStyle = "rgba(124,124,124,0.1)";
//一行一行画画布
for (var i = 0; i < _this.columns; i++) {
  y = i * size;
  for (var j = 0; j < _this.columns; j++) {
    x = j * size;
    _this.ctx.strokeRect(x, y, size, size);
  }
}

3.画蛇

前面在initData()里面,把随机生成的蛇的位置放进了bodyNodes数组里面,

这里把bodyNodes里面的元素用each()取出来画即可。因为后面当蛇吃了果实后,bodyNodes里面的

元素会增加,所以用each取出所有元素绘画,现在是在初始化阶段,bodyNodes里面只有在initData()

的一个随机生成的元素。

var nodes = _this.bodyNodes;
$.each(nodes, function (i, node) {
  _this.ctx.fillRect(node.x * size, node.y * size, size, size);
});

4.画果实

画果实的时候,先判断foodNode是否存在,存在的话就直接画,不存在随机生成位置,

注意,这时候要判断随机生成的果实位置有没有和蛇重合,重合了要重新画:

//如果果实重新出现的位置和蛇体重合,重画果实
if (_this.Utils.contains(_this.bodyNodes, {x: rdx, y: rdy})) {
   _this.drawFood();
} else {
   _this.ctx.strokeRect(rdx * size, rdy * size, size, size);
   _this.foodNode = {x: rdx, y: rdy};
}

到此,初始化画布和果实数据;绘画已经完成,这一块属于静态,接下来是动态的绑定事件。

这里主要描述贪吃蛇动态内容,比如前进,吃果实后变大,越界,速度控制等。

在前面,init()函数已经 完成了initData()和draw(),接下来是最后一个函数,bindEvents()。

在bindEvents()函数里面,有2个函数:①方向控制;②时间控制。

①方向控制directionContoller

document.body.onkeydown捕获按键,对ketCode进行判断,左(37),上(38),右(39),下(40),再将direction根据keyCode置为自己设置的标志即可。这里需要注意一点:如果这时候的方向为x,而按下的方向为-x,那么按键无效。比如现在方向是向左,而按下右是无效转弯的。

case 37: // 左, 1表示右,即当蛇向右行时,按左键不能改变方向,下面同理
  if (_this.direction == 1) return;
  _this.direction = -1;
  break;

设置好方向后,调用move()函数,这里控制蛇的移动,就是说到底就是在蛇体数组里面新增头元素,去掉尾元素,这里还要进行2个判断:1)蛇有没有咬到自己;2)有没有出界。

调用food()方法判断蛇是否吃到果实,在蛇数组里面设置好元素后,draw()重绘,以此完成了蛇的移动和吃果实。

this.food = function () {
  var _this = this;
  var headNode = _this.bodyNodes[0];
  //吃到果实
  if (_this.Utils.equals(headNode, _this.foodNode)) {
    _this.bodyNodes.push(_this.foodNode);//push()方法可向数组的末尾添加一个或多个元素,并返回新的长度。
    _this.foodNode = null;
    var score = _this.bodyNodes.length - 1;
    $('#score').text(score);
    if (score % 10 == 0) {//加速提高难度
      _this.speed += 10;
      _this.timerController();
    }
  }
};

②timerController

时间控制,

利用setInterval()函数定时调用move()方法,时间为6000/speed。

this.timerController = function () {
  var _this = this;
  if (_this.timer) {
    clearInterval(_this.timer);
  }
  _this.timer = setInterval(function () {
    _this.move();
  }, 6000 / _this.speed);
  $('#speed').text(_this.speed);
};

最后是工具类方法contains()和equesl()。contains用来判断新生成随机果实的位置和蛇重合时重新生成随机果实,以及蛇自己碰到自己时算游戏结束。

equals用来判断蛇到果实没有。他们的区别就是,contains要用each比较,因为蛇体数组有多个,所以需要循环一个一个比较。而equals()只比较蛇头和果实重合,所以不用循环。

this.Utils = {
  contains: function (arr, o) {
    var _this = this;
    if (!arr || !o) return false;
    var flag = false;
    $.each(arr, function () {
      if (!this) return true;
      if (_this.equals(this, o)) {
        flag = true;
        return false;
      }
    });
    return flag;
  },
  equals: function (o1, o2) {
    if (o1 == o2) return true;
    if (!o1 || !o2) return false;
    return o1.x == o2.x && o1.y == o2.y;
  }
};

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
怎样在JavaScript里写一个swing把数据插入数据库
Dec 10 Javascript
Bootstrap自动适应PC、平板、手机的Bootstrap栅格系统
May 27 Javascript
每个程序员都需要学习 JavaScript 的7个理由小结
Sep 03 Javascript
微信小程序 form组件详解
Oct 25 Javascript
jQuery下拉菜单的实现代码
Nov 03 Javascript
JAVA Web实时消息后台服务器推送技术---GoEasy
Nov 04 Javascript
AngularJS实现ajax请求的方法
Nov 22 Javascript
bootstrap制作jsp页面(根据值让table显示选中)
Jan 05 Javascript
详解如何让Express支持async/await
Oct 09 Javascript
浅析node.js的模块加载机制
May 25 Javascript
Node.js 使用request模块下载文件的实例
Sep 05 Javascript
vue实现简易图片左右旋转,上一张,下一张组件案例
Jul 31 Javascript
javascript原型链学习记录之继承实现方式分析
May 01 #Javascript
微信小程序实现卡片左右滑动效果的示例代码
May 01 #Javascript
微信小程序常见页面跳转操作简单示例
May 01 #Javascript
浅谈对于react-thunk中间件的简单理解
May 01 #Javascript
vue增加强缓存和版本号的实现方法
May 01 #Javascript
vue组件化中slot的基本使用方法
May 01 #Javascript
Vue基本使用之对象提供的属性功能
Apr 30 #Javascript
You might like
使用PHPMyAdmin修复论坛数据库的图文方法
2012/01/09 PHP
如何使用“PHP” 彩蛋进行敏感信息获取
2013/08/07 PHP
js 覆盖和重载 函数
2009/09/25 Javascript
10款非常有用的 Ajax 插件分享
2012/03/14 Javascript
Javascript 页面模板化很多人没有使用过的方法
2012/06/05 Javascript
AngularJS使用自定义指令替代ng-repeat的方法
2016/09/17 Javascript
node.js+jQuery实现用户登录注册AJAX交互
2017/04/28 jQuery
vue组件 $children,$refs,$parent的使用详解
2017/07/31 Javascript
通俗解释JavaScript正则表达式快速记忆
2017/08/23 Javascript
PHP实现基于Redis的MessageQueue队列封装操作示例
2019/02/02 Javascript
webpack + vue 打包生成公共配置文件(域名) 方便动态修改
2019/08/29 Javascript
微信小程序 select 下拉框组件功能
2019/09/09 Javascript
js抽奖转盘实现方法分析
2020/05/16 Javascript
JavaScript实现简单日历效果
2020/09/11 Javascript
JavaScript 判断浏览器是否是IE
2021/02/19 Javascript
使用Python脚本将Bing的每日图片作为桌面的教程
2015/05/04 Python
Django权限机制实现代码详解
2018/02/05 Python
对numpy和pandas中数组的合并和拆分详解
2018/04/11 Python
Python基础教程之if判断,while循环,循环嵌套
2019/04/25 Python
python模拟键盘输入 切换键盘布局过程解析
2019/08/15 Python
关于Python形参打包与解包小技巧分享
2019/08/24 Python
python创建学生成绩管理系统
2019/11/22 Python
Python字典生成式、集合生成式、生成器用法实例分析
2020/01/07 Python
django下创建多个app并设置urls方法
2020/08/02 Python
canvas 实现 github404动态效果的示例代码
2017/11/15 HTML / CSS
NIHAOMARKET官方海外旗舰店:意大利你好华人超市
2018/01/27 全球购物
菲律宾领先的在线时尚商店:Zalora菲律宾
2018/02/08 全球购物
泰国第一的化妆品网站:Konvy
2018/02/25 全球购物
兰蔻英国官网:Lancome英国
2019/04/30 全球购物
AutoShack.com加拿大:北美主要的汽车零部件零售商
2019/07/24 全球购物
C#笔试题和英文面试题
2013/02/07 面试题
企业元宵节主持词
2014/03/25 职场文书
2014党员学习习主席讲话思想汇报
2014/09/15 职场文书
学院党的群众路线教育实践活动整改方案
2014/10/04 职场文书
财务个人年度总结范文
2015/02/26 职场文书
清明节随笔
2015/08/15 职场文书