当前位置:Gxlcms > JavaScript > JS实现的贪吃蛇游戏案例详解

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

时间:2021-07-01 10:21:17 帮助过:44人阅读

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

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

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

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

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

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

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

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

然后随机生成蛇的位置:

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

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

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

到此,initData()完成。

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

  1. this.draw = function () {
  2. /**
  3. * 清空画布
  4. */
  5. this.clear();
  6. /**
  7. * 画画布
  8. */
  9. this.drawBG();
  10. /**
  11. * 画蛇体
  12. */
  13. this.drawBody();
  14. /**
  15. *画果实
  16. */
  17. this.drawFood();
  18. };

1.清空画布

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

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

2.画背景

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

  1. var _this = this;
  2. var x = 0, y = 0, size = _this.size / _this.columns;
  3. _this.ctx.strokeStyle = "rgba(124,124,124,0.1)";
  4. //一行一行画画布
  5. for (var i = 0; i < _this.columns; i++) {
  6. y = i * size;
  7. for (var j = 0; j < _this.columns; j++) {
  8. x = j * size;
  9. _this.ctx.strokeRect(x, y, size, size);
  10. }
  11. }

3.画蛇

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

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

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

的一个随机生成的元素。

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

4.画果实

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

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

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

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

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

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

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

①方向控制directionContoller

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

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

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

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

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

②timerController

时间控制,

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

  1. this.timerController = function () {
  2. var _this = this;
  3. if (_this.timer) {
  4. clearInterval(_this.timer);
  5. }
  6. _this.timer = setInterval(function () {
  7. _this.move();
  8. }, 6000 / _this.speed);
  9. $('#speed').text(_this.speed);
  10. };

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

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

  1. this.Utils = {
  2. contains: function (arr, o) {
  3. var _this = this;
  4. if (!arr || !o) return false;
  5. var flag = false;
  6. $.each(arr, function () {
  7. if (!this) return true;
  8. if (_this.equals(this, o)) {
  9. flag = true;
  10. return false;
  11. }
  12. });
  13. return flag;
  14. },
  15. equals: function (o1, o2) {
  16. if (o1 == o2) return true;
  17. if (!o1 || !o2) return false;
  18. return o1.x == o2.x && o1.y == o2.y;
  19. }
  20. };

更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《JavaScript数学运算用法总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript数组操作技巧总结》、《JavaScript排序算法总结》、《JavaScript遍历算法与技巧总结》、《JavaScript查找算法技巧总结》及《JavaScript错误与调试技巧总结》

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

人气教程排行