-
2,定义onMouseMove函数并且测试它的正确性 我们来定义一下这个onMouseMove函数, /* 参数e传进来,如果可以检测到e.offSetX或者是e.layerX,这个时候呢,获取一下鼠标的 坐标,等于e.offSetX,如果这个值不存在,那么就使用layerX值,否则使用e.offSetX. my等于e.offSetY,如果这个值不存在,就等于layerY,否则使用e.offSetY.好,我们来打印 一下鼠标的坐标,看是不是获取了这个值, */ function onMouseMove(e){ if(e.offSetXe.layerX){ mx = e.offSetX == undefined ? e.layerX : e.offSetX; my = e.offSetY == undefined ? e.layerY : e.offSetY; console.log(mx); } } 哦,大家可以看到,在我鼠标移动的时候,在控制台就打印出了鼠标的x值坐标 提示和注释 提示:只能用 === 运算来测试某个值是否是未定义的,因为 == 运算符认为 undefined 值等价于 null。 注释:null 表示无值,而 undefined 表示一个未声明的变量,或已声明但没有赋值的变量,或一个并不存在的对象属性。查看全部
-
1,定义鼠标坐标,给canvas1添加鼠标移动事件 首先在main.js中定义一个有关鼠标的变量:mx和my //定义鼠标的变量 var mx; var my; 并且在main.js中的init方法中初始化mx和my: //初始化鼠标的坐标: mx=canWidth*0.5; my=canHeight*0.5; 好,要捕捉到鼠标的动作呢,首先要canvas添加监测鼠标的事件(在main.js中的init方法中)。我们把这个事件放在canvas1上面,因为canvas1上面画的是大鱼只需要获得鼠标在移动时的坐标值就可以了 can1.addEventListener('mousemove',onMouseMove,false); 这样的话,鼠标在移动的时候,它就可以进行监测了。 addEventListener的语法和参数意思: 语法 element.addEventListener(event, function, useCapture) 参数值 参数 描述 event 必须。字符串,指定事件名。 注意: 不要使用 "on" 前缀。 例如,使用 "click" ,而不是使用 "onclick"。 提示: 所有 HTML DOM 事件,可以查看我们完整的 HTML DOM Event 对象参考手册。 function 必须。指定要事件触发时执行的函数。 当事件对象会作为第一个参数传入函数。 事件对象的类型取决于特定的事件。例如, "click" 事件属于 MouseEvent(鼠标事件) 对象。 useCapture 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。 可能值: true - 事件句柄在捕获阶段执行 false- false- 默认。事件句柄在冒泡阶段执行查看全部
-
视频里面beta最后突然就冒出来一个Math.PI,老师也没有讲解,没注意的话会出现尾部跟着鼠标移动的问题。原因应该是一开始鱼头就在180度位置查看全部
-
仔细想了下:“为何ratio的参数越小,大鱼跟着鼠标跑的越快(有点类似鼠标灵敏度的感觉)”。在自封装的lerpDistance()这个方法内,ratio越大,每一帧(requestAnimationFrame())内大鱼走的距离就越短,所以相同的距离下,ratio越大,需要的帧数就越多(一般都是100/60ms),时间就越长。查看全部
-
关于ratio越大速度越慢,之前也想了半天,结果突然看到lerpDistance(aim, cur, ratio)返回值是aim+距离差*ratio...查看全部
-
4问:因为canvas1覆盖在canvas2上,所以就要清空,这是为什么?canvas2跟canvas1本身就不是同一个画布,那是怎么影响的呢? 答:清空的原因不是因为【canvas1覆盖在canvas2上】,教程中从来没这么说。教程中说的是:因为动画一直在循环执行,前一次的图像如果不清除,就会跟后面的图像叠加在一起,使得大鱼小鱼的边线看起来特别粗,所以才要清。打个简单的比方:写满字的黑板如果不擦,继续写上去的字就会跟之前的叠加在一起看不清楚。 5问:请问为什么ctx2每次刷新都不需要ctx2.clearRect(0,0,canWidth, canHeight);? 答:因为它再一次绘制背景的时候,之前画的已经被新的背景覆盖了。。。按照原理来说,肯定要清空ctx2的,加上ctx2.clearRect(0,0,canWidth, canHeight);页面也是正确的,不信你可以注释掉绘制背景图片那个方法,海葵绘制就出问题了。查看全部
-
7,慕课网课后问答摘抄: 1问:translate()就单独使用这个属性来说是什么意思? 答:context.translate(x,y)函数可以使画布的原点坐标变为(x,y),即画笔从这个点开始画。因为我们画完一部分内容之后希望重新定义画笔的属性,所以用context.save()和context.restore()包裹例如context.translate(),context.fillStyle等属性设定。希望能帮助你理解 2问:鱼的坐标问题 ctx1.translate(this.x,this.y); ctx1.drawImage(this.bigBody,-this.bigBody.width*0.5,-this.bigBody.height*0.5); 为什么会是-this.bigBody.width*0.5和-this.bigBody.height*0.5,这个距离是怎么算的 答:如果drawImage方法,没有后面的两个参数,鱼的图片的左上角,就是整个大背景图片的中心位置(即,在translate之后)。加上两个参数的作用可以理解为,使鱼向x轴负方向移动身体的一半,向y轴方向移动身体的一般,把鱼图片的中心点放在当前坐标轴的中心点位置。当然也可以不这么做。 3问:为什么需要清空?没听懂 就是在mom.draw()前那为什么需要? 答:因为动画效果是靠gameloop一次一次地循环载入canvas形成的,如果不清除的话,多次载入的画布会重叠在一起,就形成了重影,也就是看上去线条变宽了一样。而cxt2之所以不用清除,是因为canvas2每次重新载入时都是先载入背景图片,直接就把前一次画布上的东西全覆盖了,所以不用清除。这就是两种清除画布的方法,一种直接调用清除方法,一种用背景覆盖。查看全部
-
6,解释一下translate在画大鱼时的作用: 首先ctx1.translate(this.x,this.y);将canvas1的中心设置为画布的 坐标系原点,即零点(0,0) 因为drawImage方法是从图片本身的左上角开始绘制本图片的,所以要想让大鱼的各部件 的中心都重叠在原点上,那么必须让大鱼各部件图片向西北方向移动到原点,从坐标系上看就是各图片的x坐标向 左(负方向)移动它本身宽度的一半,各图片的y坐标向上(负方向)移动它本身高度的一半。这样子大鱼各部件图片 的中心都在原点上了。 因为老师制作的大鱼的各个部件的图片都是类似圆形的图片,也就是说移动的时候只需要移动图片本身长宽的一半, 如果大鱼身子是长条状的,那么把大鱼眼睛放在大鱼脑袋上,而不是大鱼身子的中心(若大鱼是长条的,大鱼的 眼睛肯定不在大鱼身子的中心位置)这时,大鱼身子往原点移动的距离就是大鱼眼睛向原点移动的距离,因为大鱼眼睛 始终是圆形的。查看全部
-
5,利用translate重新定位大鱼各部件坐标 那么这里的坐标都需要全部改一下了: this.bigEye它的位置画在,离原点(this.x,this.y),大鱼的x坐标往左移this.bigEye.width*0.5这个距离, 同样的,y坐标往上移this.bigEye.height*0.5这个距离:那么眼睛的中心就在零点处了。 ctx1.drawImage(this.bigEye,-this.bigEye.width*0.5,-this.bigEye.height*0.5); 所以,所有的图片都要绘制在中心点,这里替换一下: momObj.prototype.draw=function(){ 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,-this.bigTail.height*0.5); ctx1.restore(); } 好,我们再刷新一下:好,现在三张图片的中心位置都在这个地方,只是尾巴要往后移一点,我们先把尾巴移出来, 因为眼睛看不到了:绘制尾巴的横坐标再向右移10个px, ctx1.drawImage(this.bigTail,-this.bigTail.width*0.5+10,-this.bigTail.height*0.5); 好,太少了,好,加30, ctx1.drawImage(this.bigTail,-this.bigTail.width*0.5+30,-this.bigTail.height*0.5); 好,差不多,大鱼眼睛这个位置看起来挺好的,那眼睛就不改了,好,大鱼就已经绘制好了 接下来,大鱼要动,对不对,它要随着鼠标来动,这个时候我们就需要获取一下鼠标的位置, 然后大鱼的坐标要跟随着鼠标的位置去移动查看全部
-
4,利用translate()方法将大鱼的坐标设置为画布的原点 但是,大鱼的坐标并不是很对,那么这个大鱼的坐标,我们一是为了方便调节这三张图片之间的相对距离, 同时也有利于我们做大鱼的旋转动作,大鱼需要一直跟着我的鼠标,一直指向我的鼠标。也是为了方便做旋转计算 我们使用前面给大家介绍的translate()这个方法(translate方法的作用:重新映射画布上的(0,0)位置), 来给它指定一个相对的原点值,好,这个方法仅适用于大鱼,所以这里需要加一个使用的范围: momObj.prototype.draw=function(){ ctx1.save(); ctx1.drawImage(this.bigEye,this.x,this.y); ctx1.drawImage(this.bigBody,this.x,this.y); ctx1.drawImage(this.bigTail,this.x,this.y); ctx1.restore(); } 使我们中间定义的属性仅适用于大鱼, translate到大鱼的坐标位置, ctx1.translate(this.x,this.y); 好,translate到这个位置之后呢, 这个地方就是原点了。查看全部
-
3,初画大鱼非常粗,加上命令显苗条 那么大鱼应该画在哪一个canvas上面呢?是在第一个canvas下面: 我们先不做调整,先把它都画上去,然后再慢慢调整它的位置: momObj.prototype.draw=function(){ ctx1.drawImage(this.bigEye,this.x,this.y); ctx1.drawImage(this.bigBody,this.x,this.y); ctx1.drawImage(this.bigTail,this.x,this,y); } 我们来刷新看一下,大鱼已经画出来了。但是它并不像我们的图片那个样子, 原图的线条(src下的大鱼的body的线条是很细的)是很细的,在这里却变得非常的粗 为什么?我们再来看一下,这个canvas1,它是一个透明的,部分透明的,只绘制需要绘制的东西在上面 然后其他地方都是透明的,然后它覆盖在canvas2上,所以我们每一次绘制的时候,都需要把前面一帧的 内容clear一下。把它清空掉,然后再绘制新的,我们需要在gameloop循环里加上这样一个功能: ctx1.clearRect(0,0,canWidth,canHeight); 从0,0点到canvas的对角线点整个清除掉,然后在干净的画布上面去绘制, 好,这样子绘制出来的东西就是正常的了查看全部
-
2,将大鱼相关的图片作为属性添加到类中,并初始化时加载这些图片 我们再来看一下大鱼的资源都有哪些?大鱼的是big,大鱼会有眼睛,眼睛会有一个动画,同时身体也会有 一个变化的过程,随着吃到果实的数量不同它的颜色会变,同时它的尾巴还会有一个动画,这就是所有有关 大鱼的资源,那么在第一阶段的课程中呢,我们不做大鱼的动画,仅把大鱼的基本东西描绘出来就行了。 我们先不做动画,所有我们把这些图片资源放在类里面吧。我们定义几个图像属性: var momObj=function(){ this.x; this.y; this.bigEye=new Image(); this.bigBody=new Image(); this.bigTail=new Image(); } 那么在初始化的时候,加载一下图片的资源: momObj.prototype.init=function(){ this.x=0; this.y=0; this.bigEye.src="./src/bigEye0.png"; this.bigBody.src="./src/bigSwim0.png"; this.bigTail.src="./src/bigTail0.png"; } 这样初始化的时候,图片就加载进来了。我们先来刷新一下, 现在我们首先来绘制一下大鱼,看这些资源有没有加载进去, 我们把大鱼的坐标放在canvas的中间: momObj.prototype.init=function(){ this.x=canWidth*0.5; this.y=canHeight*0.5; this.bigEye.src="./src/bigEye0.png"; this.bigBody.src="./src/bigSwim0.png"; this.bigTail.src="./src/bigTail0.png"; }查看全部
-
1,绘制大鱼所用API,定义鱼妈妈类,同时在main.js中定义mom对象并初始化 我们将会用到一些API:translate(); rotate();这两个API是html5 canvas的API。还有一个API是Math.atan2(y,x);反正切,这个 API是JavaScript的API。那我们来分别看一下这几个API的含义: 我们先来看一下反正切这个函数:这个函数是计算里面两个参数的反正切值,这两个参数呢 y在前,x在后,同时要注意一点,它的返回值,是一个数字,它的区间是PI到-PI之间,这点要牢记, 因为等会我们要用到这个知识,我们如何来绘制大鱼,我们还是从最基本的开始:首先我们新建一个文件 ,Ctrl+N,Ctrl+S,然后保存在js文件夹下mom.js ,首先把这个js文件包含在html里面: <script type="text/javascript" src="js/mom.js"></script> 我们把鱼妈妈也定义为一个类。因为鱼妈妈也会有各种各样的属性,首先,它会有一个坐标值,同时我们 肯定也要初始化一下,初始化它的位置,初始化完了之后,我们要在画布上画一条大鱼,要用到 drawImage,这个结构就有了, var momObj=function(){ this.x; this.y; } momObj.prototype.init=function(){ this.x=0; this.y=0; } momObj.prototype.draw=function(){ } 我们把相应的大鱼的对象定义一下: //大鱼的对象 var mom; 同时在main.js的init方法中把它定义为momObj类型,同时进行初始化,并且把draw方法放到gameloop方法中 //new一个大鱼对象并且初始化 mom=new momObj(); mom.init();查看全部
-
8,在born方法中降低蓝色果实生成几率 好,我们这时候看到有蓝色的果实出来了,而且蓝色的果实非常多,我们来调整一下数值, 不让它那么多,否则在写score的时候会非常的大: fruitObj.prototype.born=function(i){ var aneId=Math.floor(Math.random()*ane.num); this.x[i]=ane.x[aneId]; this.y[i]=canHeight-ane.len[aneId]; this.l[i]=0; this.alive[i]=true; var ran=Math.random(); if(ran<0.2){ this.fruitType[i]="blue"; //orange,blue }else{ this.fruitType[i]="orange"; } } 这个部分,至于数值(分数)是多少,我们程序其实不用管,这个是策划做的事情, 好,这样子蓝色果实和黄色果实就有了。 那我们再回来看一下,绘制果实,黄色果实和蓝色果实这一部分我们就完成了。查看全部
-
7,修改draw方法:根据fruitType的值来绘制不同颜色的果实: 好,相应的在绘制它的图片的时候,我们需要根据它的果实类型来绘制相应的图片, 我们在外面定义一下: fruitObj.prototype.draw=function(){ for(var i=0;i<this.num;i++){ if(this.alive[i]){ if(this.fruitType[i]=="blue"){ var pic=this.blue; }else{ var pic=this.orange; } if(this.l[i]<=14){ //果实生长时果实长度的变化情况 this.l[i] += this.spd[i]*deltaTime; }else{ //果实往上漂的速度的变化情况 this.y[i] -= this.spd[i]*7*deltaTime; } ctx2.drawImage(pic,this.x[i]-this.l[i]*0.5, this.y[i]-this.l[i]*0.5,this.l[i],this.l[i]); if(this.y[i]<10){ this.alive[i]=false; } } } }查看全部
举报
0/150
提交
取消