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 相关文章推荐
Js+Dhtml:WEB程序员简易开发工具包(预先体验版)
Nov 07 Javascript
js unicode 编码解析关于数据转换为中文的两种方法
Apr 21 Javascript
js用Date对象的setDate()函数对日期进行加减操作
Sep 18 Javascript
Javascript中Array.prototype.map()详解
Oct 22 Javascript
基于javascript实现九宫格大转盘效果
May 28 Javascript
微信小程序  action-sheet详解及实例代码
Nov 09 Javascript
文件上传,iframe跨域数据提交的实现
Nov 18 Javascript
什么是Vue.js框架 为什么选择它?
Oct 17 Javascript
vue2.0学习之axios的封装与vuex介绍
May 28 Javascript
如何用webpack4带你实现一个vue的打包的项目
Jun 20 Javascript
angularJs自定义过滤器实现手机号信息隐藏的方法
Oct 08 Javascript
ajax请求前端跨域问题原因及解决方案
Oct 16 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
JavaScript 变量命名规则
2009/09/23 Javascript
window.open不被拦截的实现代码
2012/08/22 Javascript
纯js分页代码(简洁实用)
2013/11/05 Javascript
使用jQuery动态加载js脚本文件的方法
2014/04/03 Javascript
jquery 显示*天*时*分*秒实现时间计时器
2014/05/07 Javascript
JQuery实现鼠标移动图片显示描述层的方法
2015/06/25 Javascript
jQuery拖动布局其结果保存到数据库
2015/10/09 Javascript
JavaScript代码实现图片循环滚动效果
2020/03/19 Javascript
JS图片左右无缝隙滚动的实现(兼容IE,Firefox 遵循W3C标准)
2016/09/23 Javascript
JavaScript用JSONP跨域请求数据实例详解
2017/01/06 Javascript
js实现tab切换效果
2017/02/16 Javascript
基于Vue2.0+ElementUI实现表格翻页功能
2017/10/23 Javascript
Angular4实现鼠标悬停3d倾斜效果
2017/10/25 Javascript
windows系统下更新nodejs版本的方案
2017/11/24 NodeJs
Node中使用ES6语法的基础教程
2018/01/05 Javascript
详解JS实现系统登录页的登录和验证
2019/04/29 Javascript
jQuery实现图片随机切换、抽奖功能(实例代码)
2019/10/23 jQuery
小程序中使用css var变量(使js可以动态设置css样式属性)
2020/03/31 Javascript
微信小程序中使用 async/await的方法实例分析
2020/05/06 Javascript
国内常用的js类库大全(CDN公共库)
2020/06/24 Javascript
Python实现对PPT文件进行截图操作的方法
2015/04/28 Python
TensorFlow模型保存和提取的方法
2018/03/08 Python
使用numpy和PIL进行简单的图像处理方法
2018/07/02 Python
[原创]Python入门教程2. 字符串基本操作【运算、格式化输出、常用函数】
2018/10/29 Python
在Pycharm中将pyinstaller加入External Tools的方法
2019/01/16 Python
Python实现剪刀石头布小游戏(与电脑对战)
2019/12/31 Python
如何快速一次性卸载所有python包(第三方库)呢
2020/10/20 Python
很酷的小工具和电子产品商城:GearBest
2016/11/19 全球购物
Vinatis德国:法国领先的葡萄酒邮购公司
2020/09/07 全球购物
介绍一下mysql的日期和时间函数
2013/03/28 面试题
后勤采购员岗位职责
2013/12/19 职场文书
合伙开公司协议书范本
2014/10/28 职场文书
2014年城市管理工作总结
2014/12/02 职场文书
python 爬取豆瓣网页的示例
2021/04/13 Python
postgres之jsonb属性的使用操作
2021/06/23 PostgreSQL
Redis特殊数据类型HyperLogLog基数统计算法讲解
2022/06/01 Redis