![](http://img.e-com-net.com/image/info10/5134d13381bb4fc7bf2a470bf48b286a.jpg)
下一阶段,让大小鱼动起来,眼睛,尾巴。小鱼会饿死的判断,大鱼吃果实的变化。海葵摇动,game over 生命值判断。大鱼喂小鱼的动作。
1、小鱼动画
尾巴摆动、眨眼睛、得不得果实会身体变白。
小鱼的尾巴图片是babyTail0 - babyTail7 八张图片。
要做的就是八张图片组成的序列帧在游戏里轮播,就成了动画。
2、鱼尾摇动
babyTail0 - babyTail7 八张图片组成的序列帧在游戏里轮播,如何在游戏里实现,很简单,就是每隔一个固定的时间,执行下一张图片。然后连续起来就是一个动画。首先一个图片数组,放八张图片,一个计时器,每隔一张图片,绘制下一张图片。在main.js中定义一个鱼尾数组,var babyTail = [ ] ; 这个数组在init中初始化:
![](http://img.e-com-net.com/image/info10/0114821463db4689998cbcfb9aceb650.jpg)
下面设置计时器,就是每隔一段时间,提醒我们执行下一个动画图片。首先定义两个变量:一个变量是计时器,另一个是记录当前图片序号的变量,就是现在执行到哪一帧了。
![](http://img.e-com-net.com/image/info10/0a1b0fcfc0ab445982c2ac75e2fc5c04.jpg)
10、11行。
draw在gameloop里面每一帧都是要执行的,所以在draw循环中,每一帧计时器都会工作,
![](http://img.e-com-net.com/image/info10/e7dea836f1d44e38aeedc702da05f752.jpg)
36-42行,如果两帧时间间隔大于50,尾巴数加一,%8是因为只有七张,第8张的时候,自动到第一张。同理时间间隔也是,大于50就取余。
![](http://img.e-com-net.com/image/info10/d8da0f77433647de9f9e31ba06ef7703.jpg)
50,51行,绘制鱼尾巴的时候,不再是this.babyTail,而是图片数组。告诉它执行到第几帧了。这里就定义一个临时变量babyTailCount。这样的话,小鱼的尾巴应该就能摆动起来了。
3、小鱼眨眼睛
小鱼眼睛有两个状态,一个是眯起来,一个是睁开,就表示小鱼眨眼睛的动作。
小鱼眨眼睛不是像尾巴那样,眨眼睛时间更随机,不是固定时间,这样更生动。比如上次隔离2秒,下一次3秒。但是小鱼眯起眼的状态是固定的,比如200ms。先定义一个小鱼眼睛的数组,图片放进去。同理在main.js中定义一个var babyEye = [ ] 变量。在init中初始化一下。在init中初始化一下:
![](http://img.e-com-net.com/image/info10/61ddb1645b8542409aaae587966220cc.jpg)
同样在baby.js跟尾巴一样,定义一个计数器,时间控制器。
![](http://img.e-com-net.com/image/info10/10e28fb437b646feb776b1fcc19d2b50.jpg)
14行表示当前图片持续多长时间。比如圆睁的图片需要持续2秒,眯眼睛200毫秒,圆睁的图片需要持续3秒,眯眼睛200毫秒,这样一直循环。
![](http://img.e-com-net.com/image/info10/ca7aa993c0d447cab903124586ab7fad.jpg)
首先对Timer计数,如果计时器超过时间间隔,提醒执行下一帧。让它自身加一,但是不超过2,因为总共两张图片。对2取模。同时计时器归零。对当前时间间隔取模。恢复起始状态。如果是第一帧,眯起眼睛来的,下一帧就是睁开眼睛,我们希望持续时间比较长,如果这次的鱼眼睛是1,那么时间间隔2-3.5秒。0状态是眯着眼睛,是200毫秒。
把这个时间技术反映在眼睛图片上面,首先把babyEye换成数组。同时告诉它执行到哪一帧了。
![](http://img.e-com-net.com/image/info10/cc36f275657d47a48f9222db9af6ebe1.jpg)
4、小鱼身体变白
大鱼不能及时把能量传给小鱼就会变白。
小鱼身体变白通过一个序列帧来表现,这个序列帧跟小鱼尾巴这个序列帧是一样的,间隔相同时间,执行一张图片。但是跟小鱼尾巴稍有不同的是,小鱼尾巴是循环播放的。小鱼身体变白是一个有去无回的动作。因为是一个gameover的判断,当小鱼身体完全变白。就表示挂了。这里先把动画表现出来。
在main.js中定义一个babyBoby = [ ] ,来放小鱼身体的图片资源。同样在init函数中初始化一下,
![](http://img.e-com-net.com/image/info10/efa10437683d4180959e186672ce5272.jpg)
动画的序列帧放在babyBoby这个数组里。
回到baby类下面,定义一个babyBody的定时器,来控制时间,定义一个变量来存储当前执行到哪一帧。
![](http://img.e-com-net.com/image/info10/f8c32e70729c44d48e45efc68d5dd25e.jpg)
16.17行。
回到draw这个函数里面做一个时间的监控:
先让计时器来存储时间,如果时间大于300毫秒,这时候提醒我们执行下一个序列帧。让序列帧计数器自动加一。当大于19的时候,停在这一帧,并提示gameover。
![](http://img.e-com-net.com/image/info10/44789315c3af428386619daf02e92c7a.jpg)
接下来这个计数器反应在小鱼身体的绘制当中,首先来定义一个临时变量。
![](http://img.e-com-net.com/image/info10/f703c84913144605adc8f8337ec1c415.jpg)
85,86小鱼身体绘制。将之前的this.babyBody替换成图片数组。把后面的引用也替换一下。完成小鱼变白的动画。
gameover判断,后面再做。
2-1 大鱼喂小鱼的逻辑判断
跟我们之前大鱼吃果实的逻辑判断是一样的。打开之前碰撞的实现:
![](http://img.e-com-net.com/image/info10/7026d1d5aa2d403b9aba67f7e955a761.jpg)
如法炮制一下:判断鱼妈妈和小鱼的距离:
当大鱼和小鱼的距离小鱼900,小鱼会复原到初始状态。也就是计数器复原到0帧,满血复活。
![](http://img.e-com-net.com/image/info10/987f0da1c9054888b19737a4ba5c0a8d.jpg)
把这个函数放在循环当中。
![](http://img.e-com-net.com/image/info10/cb9988c9e4e44ded907f97c0eacde2ac.jpg)
102行。
大鱼小鱼碰撞检测就写好了。
这里有一个问题,就是大鱼如果没有吃到果实,碰小鱼,小鱼应该不是复原的。这里暂时先不写,先来做一下大鱼的动画。
2-2、大鱼动画
大鱼动画跟小鱼类似,也分成三个部分。摇尾巴、眨眼睛、身体升级。稍有不同,身体升级有所不同。大鱼身体变化有两种情况,一种是吃到黄色果实,一种是吃到蓝色果实。蓝色果实有特殊威力,当前分值加倍。吃到黄色果实,身体变成黄色,吃到蓝色果实,由蓝色逐渐升级。另外大鱼尾巴序列帧一直循环播放。
小鱼摇尾巴,是一连串序列帧循环播放,通过时间计数器和帧计数器就可以实现。让时间逐渐增加,帧的计数器反应到小鱼的绘制里面。同样在main.js做一个大鱼尾巴存储器,把图片放在数组里。var momTail = [ ] 。init初始化的时候,如下:
![](http://img.e-com-net.com/image/info10/759af6d0c93b4e56866bd9f205919007.jpg)
大鱼mom.js里面定义两个控制器。
![](http://img.e-com-net.com/image/info10/64e0cd4402dd4bf5a1fe7089d74a32a3.jpg)
10,11行。
在draw循环里面,对这两个计数器计算。
![](http://img.e-com-net.com/image/info10/e6f4ec1d938246e18e296758062dd33c.jpg)
需要让它反应在图画的绘制中:
![](http://img.e-com-net.com/image/info10/998442f5980243d1a4bfca325dfbc632.jpg)
画大鱼的时候,不再是只画一个图片了,而是根据时间绘制序列帧。49行所示。现在就可以让大鱼摆动尾巴了。
2-3 大鱼眨眼睛
小鱼眨眼睛怎么实现?
![](http://img.e-com-net.com/image/info10/657955e099e84c59ab6c2aad12c18c5d.jpg)
类似写一下大鱼的眼睛动画:
main.js定义一个var momEye = [ ] 数组变量。init中初始化一下、
![](http://img.e-com-net.com/image/info10/be2b0cf55fa14b8cb576280fa467c7ac.jpg)
回到mom类中,定义三个变量:
![](http://img.e-com-net.com/image/info10/c05d4d4baf644d7eb6d41a13ec7f67e4.jpg)
同样在draw循环里做变量的计算:
![](http://img.e-com-net.com/image/info10/4d5209a053b44e73a7004cef63445373.jpg)
把计数器反应在大鱼眼睛绘制的过程中:
![](http://img.e-com-net.com/image/info10/c5ed0b5f72234fe79cc5261c271bdaa3.jpg)
删除this.bigEye变量
2-4 大鱼身体升级准备
由于大鱼身体升级动画会牵扯到游戏分值计算。所以我们在身体动画之前,先把分值计算先做一部分。新建一个文件,保存为data.js 。打开html文件,加载data.js。在data.js中定义一个dataObj类。在main.js中定义一个data变量。init 初始化的时候让这个变量成为一个dataObj类型。var data = new dataObj();
在data.js中,添加对应的属性如下:
![](http://img.e-com-net.com/image/info10/dc22c0d481ca4f529a14ed04897ef56e.jpg)
定义果实数量和double,这个是蓝色果实数量翻倍,就是2。初始状态下为1 。只要两个相乘,就是得到的分数。跟着两个数值有关系的,一个是大鱼和果实碰撞的时候。
![](http://img.e-com-net.com/image/info10/777152bb70af4a8a9340c7b3e16bda70.jpg)
15行,蓝色果实时候,分数就会加倍。
如何获得蓝色果实这个信息?
在fruit.js文件中,有一个fruitType。之前已经定义了。任何一个果实是orange还是blue。这里有一个区别。
![](http://img.e-com-net.com/image/info10/6d568ca16dce4f86baa65cea8a92b976.jpg)
在这里检测一下:
![](http://img.e-com-net.com/image/info10/63335a7580ec4968a7a99b537b8fd0fa.jpg)
说一下游戏的机制,大鱼吃果实,累积,回来给小鱼吃。大鱼把果实转化成能量给小鱼之后,大鱼的能量状态应该回归初始状态。这关系到在两个碰撞检测中出现的一些行为。当大鱼跟小鱼碰撞的时候,当前果实数量归零,恢复到初始状态。data.js中定义归零的方法:
![](http://img.e-com-net.com/image/info10/af2ff0535bf44e62b216e1e22d601f09.jpg)
在碰撞检测中调用归零函数
![](http://img.e-com-net.com/image/info10/2d30676ff77a4ca0abc2172c87d2ba5d.jpg)
把吃到的果实数字和double写在页面上:第一个画布上画UI:
![](http://img.e-com-net.com/image/info10/e74691508b724559a796ab3a7c6768ce.jpg)
data.draw()放在主循环里面。
![](http://img.e-com-net.com/image/info10/bdd7b334bbc1469fb302e29f542b7b7f.jpg)
2-5 身体升级
跟绘制小鱼动画类似,先把图片导入进来。定义大鱼的两个序列的动画帧,一个是蓝色,一个是橙黄色。在main.js中定义两个数组,在init中初始化一下:
![](http://img.e-com-net.com/image/info10/45c4f3199e7a4fa9b09af50d6f722e7b.jpg)
![](http://img.e-com-net.com/image/info10/bc72c316fdea4cb6aab33c3414055b03.jpg)
回到mom类,增加一个变量,记住当前大鱼身体是哪一个帧:
![](http://img.e-com-net.com/image/info10/161e11917b1844048006b145fee6229a.jpg)
这个变量在哪里发生变化?跟果实碰撞的时候,mom.momBodyCount ++;但是有一个问题,序列帧0-7,最大到第8帧。如果大于7,就一直停留在7帧。下图15-17行:
![](http://img.e-com-net.com/image/info10/c8993fa46067412eade1c3da1edbe8fb.jpg)
这时候计数器就做好了。需要把计数器反应在大鱼身体的绘制上面。同样定义一个临时变量。先判断是吃的黄色还是蓝色果实,分别绘制不同颜色的身体:
![](http://img.e-com-net.com/image/info10/a189df3172dc44799c3f5f526a546323.jpg)
之前定义的this.body变量就不需要了。
大鱼碰撞小鱼的时候,序列帧恢复:36行:
![](http://img.e-com-net.com/image/info10/71eb0cdd06af4296bf067ea81fa16f7d.jpg)
让大鱼变成无色的。
2-6 游戏分值计算1
在data类中,进行调整一下,定义字体,字体居中(默认left),需要绘制的是得分,所以在dataObj中加一个变量score,初始化是0,如何计算呢?大鱼跟小鱼碰撞,当前分值加到score上。
![](http://img.e-com-net.com/image/info10/cb0933f2234741f99fb272a201c7cff5.jpg)
在collision.js中,果实数量已经做了记录。在这个时候,在打小鱼碰撞中,要做一个更新数值:
![](http://img.e-com-net.com/image/info10/6aa4da1da5e941a48e2731b8283cfee5.jpg)
在data.js中增加一个方法。
![](http://img.e-com-net.com/image/info10/7245c5f3ad08470fabbbcec385c9f875.jpg)
需要做的事情:计算得分,当前果实数量归零。double状态恢复到原始状态。
因为在大鱼碰小鱼时候做这些事情:
![](http://img.e-com-net.com/image/info10/26be295f62724ff9a9243ceb6c100bb7.jpg)
在data.js中绘制一下score的值:22行
![](http://img.e-com-net.com/image/info10/6de13ce9862a47c0b939e8ba62783e15.jpg)
上面个的17-19行,不需要每次画图都初始化一下,直接放到main.js中init中好了。定义一次就好了。
上面两个值,不需要,删掉吧。结果开始报错,分数不能显示。在大小鱼碰撞检测的时候,有一个reset()
![](http://img.e-com-net.com/image/info10/fa7521a17e39408d9cf33b4c1bcb3d1c.jpg)
我们不需要reset这个函数了,直接在addScore中改变了fruitNum和double。删掉34,35行。
现在就可以正常显示了:
![](http://img.e-com-net.com/image/info10/6b6b8753e41643a99b7333dca082d797.jpg)
2-7 游戏分值计算2
其他边角的东西完成掉:大鱼没有吃果实,去碰小鱼,小鱼也会被点亮,这里是不合适的。大鱼没有果实,是救不了小鱼的。需要检查一下大鱼吃到的果实数量。看一下检测在哪。大鱼跟果实碰撞时候,fruitNum会加加。只有这个值大于0的时候, 大鱼才能跟小鱼产生有效的碰撞。所以加一个检测的条件,如果data.fruitNum大于0
![](http://img.e-com-net.com/image/info10/5b387c0709654b3ead35df8761c986d1.jpg)
没有吃到果实碰小鱼,小鱼是不会被点亮的。
小鱼颜色白色之后,应该gameover了。需要对这个状态做一个检测。就是小鱼变白,显示游戏结束。在小鱼身体动画这一块应该也有这个判断。在data.js的dataObj中添加一个变量,来记录当前游戏状态。this.gameOver = false。小鱼颜色变白之后,游戏检测,gameOver变成true。
![](http://img.e-com-net.com/image/info10/6d2ede398204417abebef3b0d87e909f.jpg)
gameOver之后,鼠标不能控制大鱼,大鱼不能吃果实,显示gameOver字样。下面一个一个接着做:
大鱼不能吃果实:增加一个条件检测,只有gameOver为false之后,才能进行大鱼和果实距离判断:
![](http://img.e-com-net.com/image/info10/3d720f76934c40ce84c2682e57b0ffc2.jpg)
同样,只有!gameOver为true时候,才能进行大小鱼碰撞检测。
![](http://img.e-com-net.com/image/info10/a843ccd837ae4a7184b859936cbe64b2.jpg)
下面开始gameOver状态下,鼠标不能控制大鱼。鼠标检测是在main.js通过onMouseMove控制的。同样添加监控条件:
![](http://img.e-com-net.com/image/info10/829487e6f331497e99f812ba4e60df03.jpg)
小鱼死了之后,鼠标移动就不能控制大鱼了。
gameOver之后,需要显示给玩家,gameOver了。在data类里面处理:在dataObj里面,如果gameOver,它是true状态,小鱼变白,就是true。在画布上绘制字样:
![](http://img.e-com-net.com/image/info10/3215a3389f7849cfb17958e0f6bf364f.jpg)
![](http://img.e-com-net.com/image/info10/38f16432e3ca444baa0718308aac414b.jpg)
优化gameover显示,渐渐出现,有一定的过渡。开始字是完全透明,后来增加到完全白色。通过使用RGBA。data.js中,alpha初始化为0.然后随着时间增加而增加:
![](http://img.e-com-net.com/image/info10/517c73dc8f36480da1fcb2c0152130c4.jpg)
7行和20-23行。上面个0.0001改成0.0005
给gameover和score添加白色阴影:
![](http://img.e-com-net.com/image/info10/053a4f78351d47a8b29edf41daca8113.jpg)
![](http://img.e-com-net.com/image/info10/d605d0732d444d90bbc08e659f0436f1.jpg)
再增加一点点东西:在样式首尾添加save 和restore
![](http://img.e-com-net.com/image/info10/bfa28ca15e9a45428bbede50b9811819.jpg)
避免这里面的样式会作用于其他地方。
3-1 大鱼吃果实特效1
大鱼吃果实,会有白色圈圈,涟漪。喂小鱼,小鱼产生涟漪。本质上一样,只是颜色,大小,快慢不一样。
![](http://img.e-com-net.com/image/info10/51fd3d0d9fbc4aab87424c6cb72302e2.jpg)
大鱼吃果实特效:大鱼每碰到一个果实产生一个圈。就像有一个篮子,里面有很多球,我不管什么时候找你要一个球,你都能从篮子里面拿一个给我。并且拿了你的球之后,隔一段时间还给你,你再放回篮子。这样就保证,不管我什么时候找你要一个球,你都能够拿一个给我。写一下这个特效实现过程,首先需要一个物体池,放很多相同物体。检测是否有闲置的物体,有,就拿出来执行任务。半径增大,颜色减弱。这两个数字是反比关系。还有绘图API.
在main.js函数里定义一个变量叫wave。就是白色圈。新建一个wave类,就是白色圈。在main.js的init()中新创建一个waveObj实例。waveObj定义如下:首先圆圈的位置,当前物体是否可以执行任务。死活的状态,半径值,颜色因为跟半径成反比,就省略一个变量。先定义有10个物体。给每个物体初始化,每个都是死的,都是可以用的。
![](http://img.e-com-net.com/image/info10/7c74d10303cf44d0bb4a1f6fda0d3ae6.jpg)
在main.js中初始化一下:
![](http://img.e-com-net.com/image/info10/fc0df5b602af48e2af761c508c911a47.jpg)
初始化好了之后,需要绘制。只有活着的,执行任务的才能被绘制。
![](http://img.e-com-net.com/image/info10/76a4245ef8ac4f1ab2e32768d9d4520d.jpg)
这个draw需要每一帧都执行,所以放在gameloop中:
![](http://img.e-com-net.com/image/info10/b18dc0ff8fde4921b19872df85daf06e.jpg)
再解释一下,如何实现圆圈特效。首先定义一个很多物体的池。每个物体有一个状态。首先判断一下每个物体的状态是不是满足条件。是不是闲着,闲着的话,就拿出来执行任务。说道是否闲着,就需要一个判断。做一个循环,来一个一个判断是否满足条件:
![](http://img.e-com-net.com/image/info10/bb6a0140f00c4ce19d2e4a04669bd71e.jpg)
每次只需要一个物体,所以找到一个之后,就马上跳出循环,使用return。否则全部画出来。
思考,什么时候使用born?当大鱼跟果实碰撞的时候,出现一个白色全。所以在碰撞函数里面,执行出现白色圈。24行
![](http://img.e-com-net.com/image/info10/c34e026ccd99488d91cd3cf1cfd6be59.jpg)
3-2 大鱼吃果实特效2
把wave.js添加到html文件。
下面要做:在born里面,把这个alive的状态改成true。然后在draw里面当alive状态为true时候,就会被绘制出来的。另外有一个半径值。初始化为0
![](http://img.e-com-net.com/image/info10/7613bc8b05c044b0ac9661c166eb9acf.jpg)
出生的时候,半径重新初始化为20、
![](http://img.e-com-net.com/image/info10/49e969bdda034fc4b7e99ae3b4fd59a4.jpg)
在draw中绘制圆圈:绘制圆圈的API。context.arc()绘制圆圈的方法。相应的方法自己查吧。另外一个api,strokeStyle,描边样式,它的值,是一个颜色值。还一个lineWidth,线条宽度。是一个像素值。如下绘制圆圈,绘制在第一个canvas上。在大鱼碰撞果实的时候,果实的位置,作为参数传递进去:
![](http://img.e-com-net.com/image/info10/bdbfca567ef345a0b88ed037b7bdf0a3.jpg)
在wave.js中做连接:
![](http://img.e-com-net.com/image/info10/4927a7d509344c62b55bbf9c0402051f.jpg)
出生的圆圈就获得了位置。下面开始绘制圆周的函数:
![](http://img.e-com-net.com/image/info10/7576cf152b974bab906633e7e60fb0ee.jpg)
想一下这个问题:这个圆圈是要慢慢消失的。所以半径变大,颜色逐渐消失23行时间间隔,进行控制,27-30行进行控制:
![](http://img.e-com-net.com/image/info10/8f36de2cab0743ff8f1b5c4ceda03052.jpg)
注意alpha的值,当alpha为0的时候,完全透明,看不见了。检测一下r[i] ,大于100,就消失,25行。
![](http://img.e-com-net.com/image/info10/bcda12c52b714721af48bdf6a58557ac.jpg)
3-3 大鱼吃果实特效3
这里有一个错误,21行改成this.alive[i] 。33行添加ctx1.stroke(); 32行拼写错误rgba。
调整相关参数:速度和大小。初始圈圈大小10,其他参数如下:
![](http://img.e-com-net.com/image/info10/6ea31751ab7742719875aa90363d3bb9.jpg)
19,38行,保存状态,避免样式会污染别的地方。
下面定义线宽,阴影大小,阴影颜色
![](http://img.e-com-net.com/image/info10/c71daf543c1d4af39c5a62796c9fabee.jpg)
![](http://img.e-com-net.com/image/info10/3cec3ed1ec8a4c4fb8cb52a01c25eda8.jpg)
3-4 大鱼喂小鱼果实特效1
main.js中跟定义wave一样,定义一个halo。新建一个halo.js、在html文件中加载这个halo.js、halo.js中定义一个haloObj。定义一系列参数。一系列数组。状态是否为活着。相关初始化如下
位置和状态,半径:
![](http://img.e-com-net.com/image/info10/f9b88895937a42fea1083977707cf8f2.jpg)
希望这个draw每一帧都会被绘制,添加到gameloop中:halo.draw()
触发机制,就是出生方法。见下一节
3-5 大鱼喂小鱼果实特效2
当大鱼跟小鱼碰撞的时候,绘制圆圈。也就是在碰撞检测里面绘制
,44行
![](http://img.e-com-net.com/image/info10/34674f1cb3a64107b044d66ba767fb79.jpg)
其中传入参数,是baby的位置。在halo.js中定义出生函数:
![](http://img.e-com-net.com/image/info10/0ec88c96894e475c80a4d6a1a2ad79b7.jpg)
检测程序是不是有问题,结果报错,main.js中draw未定义。在main.js中,init 中 halo = mew haloObj() ;halo.init() ,这时候就没有报错了。
看某个函数是不是执行了,可以在里面console.log 一下。下面开始绘制圆圈:半径随着时间增大,半径大于100时,任务执行完了,更改alive状态,跳出本次循环。同时颜色alpha值,跟半径成反比关系。参数有了,就开始绘制了。开始一个路径,画圆。圆的半径,弧度,等等。画好之后,定义描边样式,开始描边。
在22-24行定义圆圈样式。
36行错误,改成alpha = this.r[i] / 100. 30行改成0.05,半径增大比较快一点。改一下圆圈颜色为橙黄色: 203,91,0
3-6 海葵摆动动画
下面海葵一直左右摆动,使用序列帧实现,也是可以的。但是要是比较平滑的话,要求序列帧可能比较高。现在用实时绘制的方法。
绘制二次贝塞尔曲线。在三维建模等用的也比较多。
![](http://img.e-com-net.com/image/info10/380431363abf42e69f10224e83642dd3.jpg)
![](http://img.e-com-net.com/image/info10/1e504dfa032046a5a816a681ce9ca0d4.jpg)
![](http://img.e-com-net.com/image/info10/e1c995e319894ddab9308a82f1b0bc2c.jpg)
让起始点和控制点不动,结束点运动,做一个摆动。形成一个曲线摆动。那么怎么做结束点摆动?使用一个正弦或者余弦函数。
之前画海葵定义x值,和高度。都是一条直线,一个直线从某个点到另外一个点。描边。线的顶端是圆的。改造:
![](http://img.e-com-net.com/image/info10/3c31e99bbd46422b99b02a32de0aa448.jpg)
start point是最底边上,不用定义,control point是start point往上移动,也不需要定义。end point就需要定义了。初始化这些坐标:
![](http://img.e-com-net.com/image/info10/1be3f633dd25427b80064b91b496fb7d.jpg)
moveTo起始点是root,控制点是
![](http://img.e-com-net.com/image/info10/8325db0e9c7f40e08f07bca107bc02e6.jpg)
这时候报错:main.js 80行和fruit.js 63行。因为之前把x的变量替换成了rootx,所以修改fruit.js中修改63,64行。就是果实的成长位置。
![](http://img.e-com-net.com/image/info10/d6de69f816a04a7fa061721646a7b3f7.jpg)
现在木有问题了。
![](http://img.e-com-net.com/image/info10/9f9579ee97b34945b66871166fc08f83.jpg)
海葵有点矮,调整一下头部数值。长高一点。希望让海葵摆动起来,这时候要对headx改造。希望x的值是来回摆动的。使用正弦函数alpha。定义一个角度alpha,是正弦函数的角度。在draw中,角度一直变化的。7行
![](http://img.e-com-net.com/image/info10/123f3ff8856f4b148f3fa10c2791235b.jpg)
在draw中角度一直变化:
![](http://img.e-com-net.com/image/info10/051f8343e63e4672bd316fdc67399188.jpg)
定义一组海葵振幅。7行。18行初始化一下。
![](http://img.e-com-net.com/image/info10/3f161861e0e74f1ba9069a68dc36b870.jpg)
![](http://img.e-com-net.com/image/info10/fe2493e11edc49ad827d8cd425435415.jpg)
曲线函数的结束点的x坐标,给她一个l*振幅。这样就会在一定范围摆动。只是摆动幅度比较大。调整数值。控制点位置降低一点。基本就可以了。
有一个问题,果实应该长在海葵顶部的。而不是凭空出现。
3-7 水藻长在海葵上
调整海葵头部跟果实同步问题。果实出生确实在海葵顶部,但是海葵摆动起来了,位置对不上去了。果实应该随着海葵摆动。如果让果实跟着海葵头部运动,要让果实知道果实对应哪个海葵。 绘制过程中,海葵的坐标一直在变化的。需要的就是把海葵头部坐标告诉果实。
![](http://img.e-com-net.com/image/info10/492ef2faec7e4a59b3cd410594b24415.jpg)
需要的就是把headx,heady告诉果实。保存一下。出生的时候,不需要告诉它坐标值。
绘制果实图片的时候,绘制的是海葵顶部。(改懵逼了。不知所谓)
3-8 漂浮物制作
用的是三角函数sin( ) 。漂浮物随着波浪左右摇摆。海葵、漂浮物的摇动都是一致的。
定义一个全局变量,dust。有一系列图片作为dust。定义一个数组dustPic,存放图片。好了。在游戏初始化函数中,dust这个变量指向dust类。除了这个类以外,还会使用一些图片dustPic。
![](http://img.e-com-net.com/image/info10/ec0df2eeeef14417b55f8baff24d92a0.jpg)
新建一个dust.js。在html中加载进来。定义一个dustObj类,坐标位置,振幅,number,角度alpha。总数为num。初始化:
![](http://img.e-com-net.com/image/info10/599ddbef59dc45ddbdc784e1bcbb8a1e.jpg)
18行,是任意一张图片的意思。
main.js中初始化一下
![](http://img.e-com-net.com/image/info10/dbe8563241344834b3d2273eb65cebd2.jpg)
绘制函数:
![](http://img.e-com-net.com/image/info10/444ce50af15a4517af5d2c6819eba820.jpg)
这里面相关初始值跟海葵保持一致,保持摇摆节奏一致。
3-9 总结
通过两个阶段完成任务的,第一个阶段,搭建基本框架,第二阶段让游戏更加丰富。首先分析游戏,怎么设计,游戏首先有游戏的角色,有大鱼小鱼。大鱼一直吃果实,喂小鱼,让小鱼保持有生命。故事背景在海洋中。海葵提供果实,是大鱼小鱼能量来源。
分析一下学到什么东西:
大鱼小鱼动画。动画原理,轮播序列帧实现。比如小鱼:尾巴动画实现,经过一段时间,检查babyTailTimer,符合判断标准时候,执行下一帧。这些动画,眼睛动画比较 特殊,眨眼睛规律不一样,增加了interval,时间跨度。通过定义两个不同的时间跨度,让两个时间跨度来回变,让眨眼睛时间比较短,睁开眼睛时间比较长。核心东西,碰撞接触,大鱼喂小鱼,大鱼吃果实。碰撞检测,通过两者之间的距离。符合一定条件就认为撞在一起了。分值计算,学了一些api,比如shadowColor。shadowBlur,font,textAlign。还有特效,就是大鱼吃果实白色圈圈,大鱼喂小鱼黄色圈圈。有一个很重要概念,物体池。我们是怎么样让它一个个产生,好像无穷无尽。物体池中的物体是有数的,我们规定有多少个,估计够用就好了。原理,拿一个物体,检测,有没有闲置的物体,有的话,拿出来执行任务,完毕了再放回去。还有小的技巧,比如通过两个变量关系,少定义一个变量。还有绘图的api。海葵摆动,是一个技术核心一部分,用了两个部分的结合。二次贝塞尔曲线和正弦曲线,产生摇摆的结果。通过开始点,结束点,控制点,产生摇摆。