为了账号安全,请及时绑定邮箱和手机立即绑定

HTML5小游戏---爱心鱼(上)

难度中级
时长 2小时34分
学习人数
综合评分9.50
139人评价 查看评价
9.6 内容实用
9.5 简洁易懂
9.4 逻辑清晰
  • 5,通过lerpDistance使得小鱼跟着大鱼移动 这时候,我们再让小鱼动起来,小鱼动起来就是对于大鱼当前坐标的lerp, 就是让小鱼的坐标一直趋向于大鱼的坐标,我们再来看一下大鱼lerp坐标的过程,让它的坐标值趋向于目标值,现在绘画小鱼的时候,小鱼lerp的目标坐标就是大鱼的坐标, babyObj.prototype.draw=function(){ //lerp x,y this.x=lerpDistance(mom.x,this.x,0.98); this.y=lerpDistance(mom.y,this.y,0.98); //ctx1 ctx1.save(); //translate() ctx1.translate(this.x,this.y); ctx1.drawImage(this.babyTail,-this.babyTail.width*0.5+23,-this.babyTail.height*0.5); ctx1.drawImage(this.babyBody,-this.babyBody.width*0.5,-this.babyBody.height*0.5); ctx1.drawImage(this.babyEye,-this.babyEye.width*0.5,-this.babyEye.height*0.5); ctx1.restore(); } 好,我们刷新一下,小鱼已经跟着大鱼走起来了
    查看全部
    1 采集 收起 来源:小鱼绘制

    2016-06-24

  • 4,调整小鱼身体部位绘画顺序,使小鱼更逼真 但是尾巴应该在身子的后边,并且眼睛应该在前面,所以这样呢,我们需要先画 尾巴,然后再画body,body画完了再画眼睛,就好像在画布上面一层一层涂一样,那么先画的就在下面,后画的在上面, babyObj.prototype.draw=function(){ //ctx1 ctx1.save(); //translate() ctx1.translate(this.x,this.y); ctx1.drawImage(this.babyTail,-this.babyTail.width*0.5+23,-this.babyTail.height*0.5); ctx1.drawImage(this.babyBody,-this.babyBody.width*0.5,-this.babyBody.height*0.5); ctx1.drawImage(this.babyEye,-this.babyEye.width*0.5,-this.babyEye.height*0.5); ctx1.restore(); } ok,好,小鱼已经画好了,实际上,大鱼也存在顺序的问题,我们来调整一下,先画尾巴,再画body,后画眼睛, 好,再刷新一下,没有问题
    查看全部
    0 采集 收起 来源:小鱼绘制

    2016-06-24

  • 3,绘制静态的小鱼 现在开始绘制,先把这几张图片画上去, babyObj.prototype.draw=function(){ //ctx1 ctx1.drawImage(this.babyEye,this.x,this.y); ctx1.drawImage(this.babyBody,this.x,this.y); ctx1.drawImage(this.babyTail,this.x,this.y); } 并且把draw放到主循环里, 好,看一下,小鱼已经画上去了,接下来做的是,转移原点的相对坐标,转移相对坐标还记得是哪一个API吗?我们希望里面的方法只适用于小鱼,所以加上ctx1.save()和ctx1.restore()。对其他的内容是不产生影响的,所以要用到save和restore这一对API。我们把原点转移到小鱼的坐标位置,这样this.x和this.y就变成了0,0点,它变成0,0点的时候,绘制的坐标就变了,这个时候应该是0,0对吧,可是这个图片资源也是有宽度的,所以为了把这个图片绘制在以这个原点为中心的位置呢,我们需要做一下调整,减去这个图片资源的一半,同样的,它的y坐标也要减去它的图片资源的高度的一半,这样图片资源的中心就是当前的原点, babyObj.prototype.draw=function(){ //ctx1 ctx1.save(); //translate() ctx1.translate(this.x,this.y); ctx1.drawImage(this.babyEye,-this.babyEye.width*0.5,-this.babyEye.height*0.5); ctx1.drawImage(this.babyBody,-this.babyBody.width*0.5,-this.babyBody.height*0.5); ctx1.drawImage(this.babyTail,-this.babyTail.width*0.5,-this.babyTails.height*0.5); ctx1.restore(); } 好,我们来看一下,好,没有问题,这些图片资源的中心原点就在这个位置,我们需要把尾巴往后移动一点,往后移就需要加一个值,加20,奥,太少,23.好,这个位置差不多
    查看全部
    0 采集 收起 来源:小鱼绘制

    2016-06-24

  • 2,添加图片属性完善小鱼类的定义 我们绘制小鱼呢,按照之前绘制鱼妈妈的方法,来一步一步回想,第一步先把小鱼的身体图片资源绘制上去,然后第二步是让小鱼 能够动起来,跟着鼠标动,第三步是让小鱼能够旋转,小鱼跟随的并不是我们的鼠标,所以它的移动也不是跟随鼠标的,它应该是跟随鱼妈妈的,它一直跟着妈妈走,所以它的位置和旋转都跟着鱼妈妈,ok,我们先做这些事情,至于它身体的变化,吃到被大鱼拥抱一下的反应,我们后面再来做,我们先把小鱼的图片资源加载进来,定义三个图片变量, var babyObj=function(){ this.x; this.y; this.babyEye=new Image(); this.babyBody=new Image(); this.babyTail=new Image(); } 那么这三个图片类在初始化的时候,对图片资源进行加载, babyObj.prototype.init=function(){ this.x=canWidth*0.5-50; this.y=canHeight*0.5+50; this.babyEye.src="./src/babyEye0.png"; this.babyBody.src="./src/babyFade0.png"; this.babyTail.src="./src/babyTail0.png"; } 好,这样就加载进来了,我们来刷新看一下,ok,没有问题,
    查看全部
    1 采集 收起 来源:小鱼绘制

    2018-03-22

  • 2-11,小鱼绘制 1,创建小鱼类 接着我们就要来继续下一个任务,绘制小鱼,画小鱼和画大鱼原理是一样的,我们来看一下大鱼跟小鱼,大鱼跟小鱼的图片资源也差不多,都是三张图片,然后小鱼也会有一些动画,除了尾巴的摇动以外呢,身体会变色,如果它一直吃不到果实的话,就是鱼妈妈一直不来救它的话,它就会慢慢的失去颜色,当被大鱼碰到之后呢,它就恢复了颜色,好,我们来看一下小鱼的图片资源,小鱼有一个眼睛眨动的动作,除此以外,它的身体有一个颜色退去的过程,这是一个序列帧,另外,它的尾巴会有一个摇动的动画,也是一个序列帧,画大鱼和画小鱼也能借此复习一下,现在我们先建立一个新的文件,然后保存,叫它baby.js然后把这个js文件包含在html里面,那我们首先先建一个关于小鱼的类,然后定义小鱼的一个变量来继承这个类,babyObj,function,它有坐标位置,另外呢需要初始化,把它初始化在屏幕的中央吧,然后跟大鱼保持一定的距离,注意是在大鱼的下方,让小鱼绘制在第一个canvas上,这样一个基本的类就建立了, var babyObj=function(){ this.x; this.y; } babyObj.prototype.init=function(){ this.x=canWidth*0.5-50; this.y=canHeight*0.5+50; } babyObj.prototype.draw=function(){ //ctx1 } 我们来定义一下小鱼,放在鱼妈妈下面,它继承baby类,并且初始化一下。我们来刷新一下,看有没有问题,没有问题,
    查看全部
    1 采集 收起 来源:小鱼绘制

    2016-06-24

  • 问: 果实成长过程可不可以使用定值? 假如不使用deltaTime,而直接用spd[i]的话,那就不存在果实越变越大的问题了。 还是说不使用deltaTime的话会有其他的问题 答: 个人见解:deltaTime控制了整个游戏中动画的演变节奏(除了大鱼和小鱼的游动),可以统一管理游戏动画效果。而spd[i]目前只用于果实这一个对象,只是为了体现各个果实的不同性。所以我觉得果实的成长不用deltaTime而换用一个定值的话其实也没什么问题的。
    查看全部
    0 采集 收起 来源:优化

    2016-06-24

  • 课后总结:记住chrome浏览器有个特性,切换tab的时候针实际已经停止了,而但前时间没有停止,所以会造成两针之间的间隔越来越大。
    查看全部
    0 采集 收起 来源:优化

    2016-06-24

  • 2-10:优化: 现在我们来解决这个问题:当我把标签切换一下的时候,这个标签下面的东西是不被执行的,所有里面的代码都是不被执行的,所以我在切换过来的时候,所以这个果实就会变得特别大,这是为什么呢?这是因为我们在绘制果实的时候,它的尺寸是和deltaTime成正比的, if(this.l[i]<=14){ //果实生长时果实长度的变化情况 this.l[i] += this.spd[i]*deltaTime; } deltaTime越大,果实的尺寸越大,deltaTime是帧与帧之间的时间间隔,两帧之间的间隔时间越长呢,果实的尺寸的值就越大,所谓在我当前标签切过来之后,它现在执行的帧已经停止了,当我再切过来的时候,这两帧之间的间隔就会变得特别大,所以果实变的特别大,看起来太诡异了。这个给它定义一下。如果deltaTime大于50ms的时候,deltaTime就等于50ms,我们把它约定一下, 50太大了,我们约定为40, if(deltaTime>40) deltaTime=40;加在gameloop里面。 这样子的话呢,它就不会出现这个问题了,我们现在做的是一个硬性的约定了,把它约定在这个值里,虽然不是科学的,但是它不会出现诡异的事情。 那再一个呢,就是Date.now()这个API我们来看一下它的含义,这有利于帮助我们理解帧与帧之间的距离,Date.now()的返回值是什么呢? The Date.now() method returns the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC. 从1970年的这个时间一直到现在的时间消逝,所以它返回的是一个真实的绝对值,好,这是一个小插曲,
    查看全部
    1 采集 收起 来源:优化

    2018-03-22

  • 3,利用calLength2和dead方法完成大鱼吃果实的效果。 //判断大鱼和果实的距离 function momFruitsCollision(){ for(var i=0;i<fruit.num;i++){ if(fruit.alive[i]){ //calculate length var l=calLength2(fruit.x[i],fruit.y[i], mom.x, mom.y); if(l<900){ //fruit eaten fruit.dead(i); } } } } 好,我们再检查一下, 首先做所有fruit的循环,如果当前这个fruit处于活着的状态,那就计算它跟大鱼之间的距离,我们得到的是距离的平方,如果这个距离很小,那么这个果实就被吃掉了,好,我们把这个函数momFruitsCollision放到总循环里面。我们再来打开浏览器, 的确可以看到,果实被大鱼碰到的,就消失了,没有问题,ok,这样子大鱼吃果实的碰撞检测就写好了,我们看下一个任务。 4,课后总结: 为什么是小于900px,就判定大鱼吃到果实了呢? 因为大鱼的坐标指的是,大鱼身体的中心位置,果实的坐标是果实的中心位置,如果大鱼和果实相切(刚好挨着),那么它们中心的距离就是0.5*21+0.5*50,然后再平方,就差不多是900了。
    查看全部
  • 2,在果实类中添加dead方法 function momFruitsCollision(){ for(var i=0;i<fruit.num;i++){ if(fruit.alive[i]){ //calculate length var l=calLength2(fruit.x[i],fruit.y[i], mom.x, mom.y); } } } 如果这个距离l小于某一个值,因为l是一个平方值,30的平方就是900,如果小于900的话,那么这个fruit就被吃掉, 这个果实被吃掉了,需要在果实类里面加一个方法,这个方法的功能就是让当前果实死亡,执行一个死亡的状态,什么叫死亡呢? 就是果实从屏幕上消失了,怎么消失呢?也就是它的alive状态被设置成false,这样子它就消失了, fruitObj.prototype.dead=function(i){ this.alive[i]=false; } 好,就要使用这个dead方法,
    查看全部
  • 1, 老师封装好的函数calLength2来计算大鱼和果实之间距离的平方和 我们再回到ppt来,画大鱼,身子,尾巴,眼睛已经画好了。我们再看一个下面的,我们下一个任务是大鱼吃果实的碰撞检测: 这个原理就是检测大鱼和果实的距离,也就是我们在每一帧的时候去判断一下,大鱼和这个果实距离是不是足够近,足够近的话, 就判定它已经吃到了,然后如果这个距离非常远,然后就判定这个果实没有被吃掉,好,那么我们回到代码中,我们来新建一个文件,Ctrl+N,Ctrl+s,collision.js这个文件里面只存放碰撞检测的功能,首先把这个脚本包含到html里面。我们要做的是判断大鱼和屏幕上每一个果实的距离,如果小于某一个值,我们就认为大鱼把这个果实吃掉了,如果大于这个值,果实仍然继续它的运动 好,现在来写这个功能,因为果实非常的多,我们需要做一个循环,来对比每一个果实,这所有的果实,首先判断它是否在alive状态,如果在alive状态的话,再去判断它跟大鱼之间的距离,判断距离使用它们的坐标差,我们这样得到一个斜边的大小,而实际上我们在计算的时候不需要去开平方,三角里面不需要去开平方,因为开平方或者不开平方对于我们都没有关系,在commonFunctions.js里面有一个封装好的方法: function calLength2(x1, y1, x2, y2) { return Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2); } 距离值的平方,它是这两对坐标(x1,y1),(x2,y2)的差的平方和,pow是乘方的函数,次数是2(pow第二个参数),也就是(x1-x2)的平方加上(y1-y2)的平方,这样呢,在一个三角里面我们得到的就是斜边的平方,也就是大鱼跟果实之间距离的平方。我们把这封装好的函数拿过来用,大家可以经常把这些很普通的函数封装好,然后我们每次就不必去写,否则每次去写要写正确这些API如pow,还有乘方的次数,大家封装好就可以很好的去用了
    查看全部
  • 课后总结: ratio越大,大鱼朝鼠标移动的速度越慢。 仔细想了下:“为何ratio的参数越小,大鱼跟着鼠标跑的越快(有点类似鼠标灵敏度的感觉)”。在自封装的lerpDistance()这个方法内,ratio越大,每一帧(requestAnimationFrame())内大鱼走的距离就越短,所以相同的距离下,ratio越大,需要的帧数就越多(一般都是100/60ms),时间就越长。 视频里面beta最后突然就冒出来一个Math.PI,老师也没有讲解,没注意的话会出现尾部跟着鼠标移动的问题。原因应该是一开始鱼头就在180度位置
    查看全部
  • 5,利用lerpAngle,atan2,rotate等API使大鱼随鼠标旋转。 我们使用lerpAngle,为什么不用lerpDistance呢?因为在lerpAngle里面牵扯到一个数值上的调整,这个数值上的调整为什么 要这么写呢?大家花点时间来研究一下,在这里我们不讲了,我们需要调整一下,为什么呢?这是 因为,我们当前计算出来的值跟计算出来的值有关系,我点一个知识点吧,大家在做的时候,大家在回去研究封装好的函数的 时候可能会用到,这是因为为什么在这里要调整,在这里写-2*PI和+2PI,为什么呢?因为这个API(atan2())的返回值是一个 -PI到+PI之间的范围。ok,大家要注意这一点,那么这个封装好的函数(lerpAngle)直接拿过来用,同样的a是目标值, b是当前值,那么 this.angle=lerpAngle(beta, this.angle, 0.9);我们在获得了这个角度this.angle之后,如何让鱼妈妈旋转起来呢? 这就用到了我们在前面讲到的另外一个API:rotate旋转,旋转画布,旋转画布呢,需要在save和restore之间,使得rotate 只作用于大鱼,并且我们必须在translate后面做这个命令,为什么呢?我们需要先相对的移动原点,然后再去旋转,这样才对。 大家这个逻辑要理清楚, ctx1.rotate(this.angle);那我们去到浏览器中去看一下。可以看到,大鱼已经旋转起来了,可是有点卡,这是因为 录屏软件的问题,它应该是运行非常流畅的,调整一下数值,因为大鱼的反应有点缓慢,我们希望它旋转快一点, 所以,调整如下,this.angle=lerpAngle(beta,this.angle,0.6);它现在反应已经非常快了,同时这个运动有点太快,我们 把它运动的反应调慢一点, this.x=lerpDistance(mx, this.x, 0.99); this.y=lerpDistance(my, this.y, 0.99); 这样大鱼看起来有点慢,我们再来调整一下, this.x=lerpDistance(mx, this.x, 0.98); this.y=lerpDistance(my, this.y, 0.98); 好,可以的,这样大鱼就动起来了,可以在深海里面自由的游来游去了,看起来挺有感觉的。
    查看全部
  • 4,给鱼妈妈类增加角度属性并且引入老师封装好的lerpAngle方法。 现在大鱼虽然可以移动,但是它并没有根据鼠标的位置去旋转,如何来旋转它的身体呢? 我们来分析一下:首先大鱼它自己有一个角度,它现在是朝向左的,它现在 身体的角度是多少呢?根据极坐标的规定,极坐标的正方向是向右,那么它现在朝向左,角度就是PI或者-PI. 不管它是往上转还是往下转,如果是往下转(逆时针角度是正的)呢,角度是PI,往上转(顺时针角度是负的)呢,角度就是-PI。如果大家不清楚极坐标的规定,大家可以去搜索一下坐标的知识,大鱼跟鼠标他俩之间会产生一个坐标差。它俩都有各自 的坐标,那么坐标会产生一个坐标差,坐标差值会形成一个三角形,这个三角形有个夹角,这个夹角就是鼠标相对于大鱼 的角度。所以我们得到了第二个角度,而刚才我们讲的大鱼它自身的角度要去追随,我们刚才说到的坐标差的角度 我们回到代码中来,首先给大鱼增加一个属性:this.angle角度。这个angle初始化为0.怎么来计算坐标差? 坐标差需要在每一帧里面去计算,每一帧都去跟随这个角度delta angle,所以每一帧都去计算角度差,这个角度差 怎么来计算。它是用我们刚才讲到的Math.atan2(y,x),用这个API来计算的,首先计算y值,y值的坐标差: deltaY=my-this.y; x值的坐标差: deltaX=mx-this.x; 我们要求的是angle值,我们用另外一个变量beta,beta这个角度就是鼠标与大鱼之间的角度差,我们用反正切返回这个值 beta=Math.atan2(deltaY,deltaX);这样我们得到了这个角度,大鱼的角度this.angle要不断的趋向于这个beta。 所以不断的趋向,我们用一个lerp,这个我们上面做的坐标的lerp是一样的,上一部分是让大鱼的坐标一直趋向于鼠标的 坐标,而我们现在要做的就是让大鱼的角度一直趋向于鼠标的角度,那么 this.angle=lerp 我们看一下这个封装好的API: function lerpAngle(a, b, t) { var d = b - a; if (d > Math.PI) d = d - 2 * Math.PI; if (d < -Math.PI) d = d + 2 * Math.PI; return a + d * t; }
    查看全部
  • 3,利用老师封装的lerpDistance方法修改draw方法使得大鱼跟鼠标移动 我们如何让鱼妈妈的坐标位置跟随着鼠标呢? 首先我们来看这样一个封装好的函数, function lerpDistance(aim, cur, ratio) { var delta = cur - aim; return aim + delta * ratio; } 它返回的是一个什么样的值,它有三个传入值,一个是aim,一个是cur,aim就是目标值,cur就是当前值,ratio是百分比, return aim + delta * ratio; 它返回的就是按照一定的比率趋向于目标值的这样一个值,所以这个值在帧运行起来之后, 它就会一直不断的追随着这个目标值,好,我们直接把这个封装好的函数拿过来用,这个函数也是经常用到的函数,所以我们 把它封装好 现在需要做的事情是,让this.x去趋向于哪一个呢?aim,这个aim值是mx。它要跟随我们的鼠标,cur值就是this.x 然后 ratio呢,我们来设置一个随便0.9,ratio是一个0到1之间的值,好,这个this.x要等于lerpDistance(mx, this.x, 0.9) this,y也是一样的道理: momObj.prototype.draw=function(){ this.x=lerpDistance(mx, this.x, 0.9); this.y=lerpDistance(my, this.y, 0.9); ctx1.save(); ctx1.translate(this.x,this.y); ctx1.drawImage(this.bigEye,-this.bigEye.width*0.5,-this.bigEye.height*0.5); ctx1.drawImage(this.bigBody,-this.bigBody.width*0.5,-this.bigBody.height*0.5); ctx1.drawImage(this.bigTail,-this.bigTail.width*0.5+30,-this.bigTail.height*0.5); ctx1.restore(); } 好,我们到浏览器中刷新一下,好,现在大鱼就跟随这鼠标动起来了,可以看到:大鱼的中心位置一直是鼠标的位置
    查看全部

举报

0/150
提交
取消
课程须知
1、对html、css基础知识已经掌握。 2、对JavaScript的基础知识掌握,如数组、类、对象。
老师告诉你能学到什么?
1、html5 canvas制作游戏理念 2、html5 canvas 绘图API 3、游戏中的碰撞检测 4、认识几个数学函数 5、物体池概念 6、序列帧动画的控制

微信扫码,参与3人拼团

意见反馈 帮助中心 APP下载
官方微信
友情提示:

您好,此课程属于迁移课程,您已购买该课程,无需重复购买,感谢您对慕课网的支持!