点击领取专属小蛇~JS贪吃蛇来咯

        贪吃蛇可以说是一款非常经典的小游戏了。相信大家都有玩过这款游戏。今天动动小手就可以让大家拥有一条自己的专属蛇蛇!

一、面向对象和面向过程

        面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;

        面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

   在本案例中我们使用面向对象来完成,之前写的基本上都是面向过程,所以写面向对象逻辑上会有一定的问题,请见谅哦~

二、封装对象

        在本案例中我们主要使用的是构造函数创建对象,可以看下图简单复习一下构造函数的使用方法。

         本篇大量运用到了prototype对象,是面向对象的一个重要机制哦。

        每个函数就是一个对象(Function),函数对象都有一个子对象 prototype对象,类是以函数的形式来定义的。prototype表示该函数的原型,也表示一个类的成员的集合。

三.功能分析 

        1.点击开始按钮开始游戏,蛇默认的方向是向右走。

        2.点击地图会暂停游戏,点击暂停按钮会继续游戏,并隐藏按钮。

        3.用户通过方向键控制蛇,当蛇头碰到食物时则表示贪吃蛇吃到此食物,界面上会在任意位置出现下一个食物,用户再次控制蛇去吃这一食物。

        4.死亡判断:4.1撞到墙了 4.2撞到自己了

四、代码演示

        在本案例中我们选择的方法是使用js动态生成项目中的所有节点(蛇头、蛇身体、食物),所以HTML的结构就很简单了,用一个大容器装地图、开始按钮和暂停按钮。再在CSS中书写对应的样式。注意:在CSS中我们不用给需要动态生成的节点设置大小。

        完整代码见链接:https://blog.csdn.net/weixin_45990864/article/details/121294587

        设置完HTML和CSS后,我们就需要开始书写js代码。在写之前,我们可以将这个地图看成一个一个的像素格子,每一个动态生成的结点的宽高都为20px,一个600*600的地图正好可以划分为30行30列。我们将宽高行列都设为全局变量供我们使用。

        首先我们需要创建一个Square函数,在这个函数里面传入元素的位置和类名,我们传进去的x和y值是按一份一份计算的,例如蛇头的位置是[2,0],身体的位置是[1,0],蛇尾的位置是[0,0]。

         通过计算后的this.x和this.y是实际的位置。在后面的计算中我们会经常进行转换。

        接着我们需要给Square函数添加一些共享属性,主要有create、remove,让生成好的节点可以在dom中进行添加或者删除操作。

         这个函数是为了构造项目中所有需要生成的节点,并赋予它们一些基本的属性和方法,我们还需要写两个不同的函数来生成特定的元素。

Snake函数

        这个函数的作用是书写蛇中的所有作用和方法。

        在写之前我们需要知道这个对象里面需要包含蛇头、蛇尾、蛇每一个元素的位置以及蛇运动的方向。例如蛇头想要往右运动,坐标就会从原来的[2,0]变成[3,0],即x+1,其他方向同理。另外我们在控着蛇移动时,蛇头的方向也会发生改变,我们可以在这一步写上改变的参数值,供后面使用。

         同样的,当我们设置创建好蛇对象以后,需要进行初始化、并且添加一些方法。在初始化中使用构造函数构造蛇头、蛇身体1和蛇身体2(蛇尾)。并且将它们的坐标存下来,方便后面判断食物是否生成在蛇身体上。另外当蛇进行移动的时候,可以将蛇看作一个整体,当蛇头移动时,整体会一起移动,这需要蛇与蛇之间有一定的关系。

初始化代码:

         当我们把蛇中的元素都进行初始以后,我们在全局声明一个snake变量并使用 snake = new Snake()。当我们完成以上操作时,我们就可以在页面中看到创建好的蛇了。

        接着我们再来创建食物。

CreateFood函数

        这个函数对象里面包含了食物的的坐标,创建食物,以及需要将食物的坐标存入一个数组,以便后面判断是否吃到食物。

        在这里需要注意的是,食物的的坐标是使用随机函数生成的,我们需要使用一个参数来判断食物是否生成在蛇的身上,若在蛇身上则需要重新生成新的坐标点。另外当我们在蛇吃到食物时,我们需要将该点删除并生成一个新的食物,如果每一次都重新生成新节点并且删除旧节点就会很麻烦,这时候可以使用一个if…else判断,当页面中能查找到食物的类('.food')就改变食物的坐标点,若查询不到就生成食物。

代码如下:       

         到现在就已经把蛇和食物都创建好啦,接下来的工作就是让蛇动起来,实现我们预期的功能。让蛇动起来的第一步就是需要知道蛇头的下一个坐标点。根据下一个坐标点我们来判断当前蛇需要做的事情,大致如下:

  1. 下一个坐标点是自己,即碰到自己的身体 ——游戏结束
  2. 下一个坐标是墙,即撞到墙上 ——游戏结束
  3. 下一个坐标是食物,即吃到食物,身体变长,重新生成新的食物
  4. 下一个坐标啥也不是,继续往前走。

        所以我们需要给Snake对象添加一个新的属性-getNextPos,用于获取蛇头的下一个坐标点并且进行判断。

        先将下一个点的坐标获取过来并且以数组的形式存储,再一一判断情况。

情况一:下一个点是自己

        在前面我们不是将蛇的坐标存入snake.pos这个数组中么,将蛇运动中的下一个点的坐标与蛇的坐标进行对比,若有相等的值即为撞上自己,游戏结束。

 情况二:下一个点是墙

        在这个情况我们只需要判断蛇头的下一个点坐标是否超过容器的范围,即小于0或者大于30(我们将容器化成30份)

 情况三:下一个点是食物

        在这个情况下也是需要读取食物的坐标,若下一个点和食物的坐标相等,就调用吃的那个方法。

情况四:下一个点什么也不是

        下个点啥也不是,就继续往前走,调用走的那个方法。

         在上面提到了一些方法,这些方法是添加到strategies里的,主要对应了游戏的几个情况——即游戏结束、吃到食物、蛇移动。

蛇移动 

        当蛇移动的时候,不需要去计算蛇中的每一个点的坐标,而是使用动态生成和删除来完成蛇的移动。本质上是改变蛇头和蛇尾的位置。蛇的移动可以见下动图帮助理解。

  1. 先创建一个新的身体,这个身体的x,y和原来的蛇头的x,y一样。让这个点代替原来蛇头的位置。因为蛇的身体结构发生改变,所以线性关系也要跟着一起修改,在更改完所有的关系后再删除原来的蛇头节点。
  2. 再创建一个新的蛇头,这个蛇头的x,y就是原来蛇头的下一个点。同样的需要更新蛇中的对应关系。
  3. 另外需要判断当前是否需要删点最末的节点,若贪吃蛇碰到了食物,即身体会变成一节,就不需要删除最末尾的节点,否则就需要删除节点。这里需要添加以一个参数来判断。

 吃到食物

        在这个方法中,只需要创建食物、计算得分以及给上面的函数传递参数过去。

  游戏结束

        游戏结束也可以定义一个Game对象,并且调用里面的over方法。

        其实写到这里,我们只差一个功能就能将贪吃蛇的基本功能实现完毕了,这个差的功能就是需要用户通过方向键控着蛇移动的方向。这里需要使用键盘事件document.onkeydown = function (e){},这个事件添加到哪里合适呢?上面我们不是创建了一个Game函数嘛,当这个对象初始化的时候,我们需要生成蛇的相关信息和食物,同时也可以把键盘事件添加在初始化中。

         剩下的就是给Game对象添加一些属性和方法,例如start、over、pause等,其本质是开启定时器、清除定时器。另外需要给最初设定的按钮添加点击事件。

       如果觉得每一把的贪吃蛇速度都一样太easy了,也可以给贪吃蛇添加不同的难度,调难度就是在开始前设置几个按钮,每个按钮对应不同的速度,点击后把速度传给定时器,毕竟开始游戏的本质就是开启定时器啦!相信对聪明的大家来讲就是洒洒水啦!

         那么贪吃蛇这个项目基本上就完成啦,这个由自己亲手完成的贪吃蛇肯定是独一无二的贪吃蛇,可以动动手做起来哦!若有不完整的地方欢迎大家友好交流~

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>