-
2,定義onMouseMove函數(shù)并且測試它的正確性 我們來定義一下這個onMouseMove函數(shù), /* 參數(shù)e傳進(jìn)來,如果可以檢測到e.offSetX或者是e.layerX,這個時候呢,獲取一下鼠標(biāo)的 坐標(biāo),等于e.offSetX,如果這個值不存在,那么就使用layerX值,否則使用e.offSetX. my等于e.offSetY,如果這個值不存在,就等于layerY,否則使用e.offSetY.好,我們來打印 一下鼠標(biāo)的坐標(biāo),看是不是獲取了這個值, */ 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); } } 哦,大家可以看到,在我鼠標(biāo)移動的時候,在控制臺就打印出了鼠標(biāo)的x值坐標(biāo) 提示和注釋 提示:只能用 === 運(yùn)算來測試某個值是否是未定義的,因?yàn)?== 運(yùn)算符認(rèn)為 undefined 值等價于 null。 注釋:null 表示無值,而 undefined 表示一個未聲明的變量,或已聲明但沒有賦值的變量,或一個并不存在的對象屬性。查看全部
-
1,定義鼠標(biāo)坐標(biāo),給canvas1添加鼠標(biāo)移動事件 首先在main.js中定義一個有關(guān)鼠標(biāo)的變量:mx和my //定義鼠標(biāo)的變量 var mx; var my; 并且在main.js中的init方法中初始化mx和my: //初始化鼠標(biāo)的坐標(biāo): mx=canWidth*0.5; my=canHeight*0.5; 好,要捕捉到鼠標(biāo)的動作呢,首先要canvas添加監(jiān)測鼠標(biāo)的事件(在main.js中的init方法中)。我們把這個事件放在canvas1上面,因?yàn)閏anvas1上面畫的是大魚只需要獲得鼠標(biāo)在移動時的坐標(biāo)值就可以了 can1.addEventListener('mousemove',onMouseMove,false); 這樣的話,鼠標(biāo)在移動的時候,它就可以進(jìn)行監(jiān)測了。 addEventListener的語法和參數(shù)意思: 語法 element.addEventListener(event, function, useCapture) 參數(shù)值 參數(shù) 描述 event 必須。字符串,指定事件名。 注意: 不要使用 "on" 前綴。 例如,使用 "click" ,而不是使用 "onclick"。 提示: 所有 HTML DOM 事件,可以查看我們完整的 HTML DOM Event 對象參考手冊。 function 必須。指定要事件觸發(fā)時執(zhí)行的函數(shù)。 當(dāng)事件對象會作為第一個參數(shù)傳入函數(shù)。 事件對象的類型取決于特定的事件。例如, "click" 事件屬于 MouseEvent(鼠標(biāo)事件) 對象。 useCapture 可選。布爾值,指定事件是否在捕獲或冒泡階段執(zhí)行。 可能值: true - 事件句柄在捕獲階段執(zhí)行 false- false- 默認(rèn)。事件句柄在冒泡階段執(zhí)行查看全部
-
視頻里面beta最后突然就冒出來一個Math.PI,老師也沒有講解,沒注意的話會出現(xiàn)尾部跟著鼠標(biāo)移動的問題。原因應(yīng)該是一開始魚頭就在180度位置查看全部
-
仔細(xì)想了下:“為何ratio的參數(shù)越小,大魚跟著鼠標(biāo)跑的越快(有點(diǎn)類似鼠標(biāo)靈敏度的感覺)”。在自封裝的lerpDistance()這個方法內(nèi),ratio越大,每一幀(requestAnimationFrame())內(nèi)大魚走的距離就越短,所以相同的距離下,ratio越大,需要的幀數(shù)就越多(一般都是100/60ms),時間就越長。查看全部
-
關(guān)于ratio越大速度越慢,之前也想了半天,結(jié)果突然看到lerpDistance(aim, cur, ratio)返回值是aim+距離差*ratio...查看全部
-
4問:因?yàn)閏anvas1覆蓋在canvas2上,所以就要清空,這是為什么?canvas2跟canvas1本身就不是同一個畫布,那是怎么影響的呢? 答:清空的原因不是因?yàn)椤綾anvas1覆蓋在canvas2上】,教程中從來沒這么說。教程中說的是:因?yàn)閯赢嬕恢痹谘h(huán)執(zhí)行,前一次的圖像如果不清除,就會跟后面的圖像疊加在一起,使得大魚小魚的邊線看起來特別粗,所以才要清。打個簡單的比方:寫滿字的黑板如果不擦,繼續(xù)寫上去的字就會跟之前的疊加在一起看不清楚。 5問:請問為什么ctx2每次刷新都不需要ctx2.clearRect(0,0,canWidth, canHeight);? 答:因?yàn)樗僖淮卫L制背景的時候,之前畫的已經(jīng)被新的背景覆蓋了。。。按照原理來說,肯定要清空ctx2的,加上ctx2.clearRect(0,0,canWidth, canHeight);頁面也是正確的,不信你可以注釋掉繪制背景圖片那個方法,??L制就出問題了。查看全部
-
7,慕課網(wǎng)課后問答摘抄: 1問:translate()就單獨(dú)使用這個屬性來說是什么意思? 答:context.translate(x,y)函數(shù)可以使畫布的原點(diǎn)坐標(biāo)變?yōu)?x,y),即畫筆從這個點(diǎn)開始畫。因?yàn)槲覀儺嬐暌徊糠謨?nèi)容之后希望重新定義畫筆的屬性,所以用context.save()和context.restore()包裹例如context.translate(),context.fillStyle等屬性設(shè)定。希望能幫助你理解 2問:魚的坐標(biāo)問題 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方法,沒有后面的兩個參數(shù),魚的圖片的左上角,就是整個大背景圖片的中心位置(即,在translate之后)。加上兩個參數(shù)的作用可以理解為,使魚向x軸負(fù)方向移動身體的一半,向y軸方向移動身體的一般,把魚圖片的中心點(diǎn)放在當(dāng)前坐標(biāo)軸的中心點(diǎn)位置。當(dāng)然也可以不這么做。 3問:為什么需要清空?沒聽懂 就是在mom.draw()前那為什么需要? 答:因?yàn)閯赢嬓Ч强縢ameloop一次一次地循環(huán)載入canvas形成的,如果不清除的話,多次載入的畫布會重疊在一起,就形成了重影,也就是看上去線條變寬了一樣。而cxt2之所以不用清除,是因?yàn)閏anvas2每次重新載入時都是先載入背景圖片,直接就把前一次畫布上的東西全覆蓋了,所以不用清除。這就是兩種清除畫布的方法,一種直接調(diào)用清除方法,一種用背景覆蓋。查看全部
-
6,解釋一下translate在畫大魚時的作用: 首先ctx1.translate(this.x,this.y);將canvas1的中心設(shè)置為畫布的 坐標(biāo)系原點(diǎn),即零點(diǎn)(0,0) 因?yàn)閐rawImage方法是從圖片本身的左上角開始繪制本圖片的,所以要想讓大魚的各部件 的中心都重疊在原點(diǎn)上,那么必須讓大魚各部件圖片向西北方向移動到原點(diǎn),從坐標(biāo)系上看就是各圖片的x坐標(biāo)向 左(負(fù)方向)移動它本身寬度的一半,各圖片的y坐標(biāo)向上(負(fù)方向)移動它本身高度的一半。這樣子大魚各部件圖片 的中心都在原點(diǎn)上了。 因?yàn)槔蠋熤谱鞯拇篝~的各個部件的圖片都是類似圓形的圖片,也就是說移動的時候只需要移動圖片本身長寬的一半, 如果大魚身子是長條狀的,那么把大魚眼睛放在大魚腦袋上,而不是大魚身子的中心(若大魚是長條的,大魚的 眼睛肯定不在大魚身子的中心位置)這時,大魚身子往原點(diǎn)移動的距離就是大魚眼睛向原點(diǎn)移動的距離,因?yàn)榇篝~眼睛 始終是圓形的。查看全部
-
5,利用translate重新定位大魚各部件坐標(biāo) 那么這里的坐標(biāo)都需要全部改一下了: this.bigEye它的位置畫在,離原點(diǎn)(this.x,this.y),大魚的x坐標(biāo)往左移this.bigEye.width*0.5這個距離, 同樣的,y坐標(biāo)往上移this.bigEye.height*0.5這個距離:那么眼睛的中心就在零點(diǎn)處了。 ctx1.drawImage(this.bigEye,-this.bigEye.width*0.5,-this.bigEye.height*0.5); 所以,所有的圖片都要繪制在中心點(diǎn),這里替換一下: 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(); } 好,我們再刷新一下:好,現(xiàn)在三張圖片的中心位置都在這個地方,只是尾巴要往后移一點(diǎn),我們先把尾巴移出來, 因?yàn)檠劬床坏搅耍豪L制尾巴的橫坐標(biāo)再向右移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); 好,差不多,大魚眼睛這個位置看起來挺好的,那眼睛就不改了,好,大魚就已經(jīng)繪制好了 接下來,大魚要動,對不對,它要隨著鼠標(biāo)來動,這個時候我們就需要獲取一下鼠標(biāo)的位置, 然后大魚的坐標(biāo)要跟隨著鼠標(biāo)的位置去移動查看全部
-
4,利用translate()方法將大魚的坐標(biāo)設(shè)置為畫布的原點(diǎn) 但是,大魚的坐標(biāo)并不是很對,那么這個大魚的坐標(biāo),我們一是為了方便調(diào)節(jié)這三張圖片之間的相對距離, 同時也有利于我們做大魚的旋轉(zhuǎn)動作,大魚需要一直跟著我的鼠標(biāo),一直指向我的鼠標(biāo)。也是為了方便做旋轉(zhuǎn)計(jì)算 我們使用前面給大家介紹的translate()這個方法(translate方法的作用:重新映射畫布上的(0,0)位置), 來給它指定一個相對的原點(diǎn)值,好,這個方法僅適用于大魚,所以這里需要加一個使用的范圍: 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到大魚的坐標(biāo)位置, ctx1.translate(this.x,this.y); 好,translate到這個位置之后呢, 這個地方就是原點(diǎn)了。查看全部
-
3,初畫大魚非常粗,加上命令顯苗條 那么大魚應(yīng)該畫在哪一個canvas上面呢?是在第一個canvas下面: 我們先不做調(diào)整,先把它都畫上去,然后再慢慢調(diào)整它的位置: 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); } 我們來刷新看一下,大魚已經(jīng)畫出來了。但是它并不像我們的圖片那個樣子, 原圖的線條(src下的大魚的body的線條是很細(xì)的)是很細(xì)的,在這里卻變得非常的粗 為什么?我們再來看一下,這個canvas1,它是一個透明的,部分透明的,只繪制需要繪制的東西在上面 然后其他地方都是透明的,然后它覆蓋在canvas2上,所以我們每一次繪制的時候,都需要把前面一幀的 內(nèi)容clear一下。把它清空掉,然后再繪制新的,我們需要在gameloop循環(huán)里加上這樣一個功能: ctx1.clearRect(0,0,canWidth,canHeight); 從0,0點(diǎn)到canvas的對角線點(diǎn)整個清除掉,然后在干凈的畫布上面去繪制, 好,這樣子繪制出來的東西就是正常的了查看全部
-
2,將大魚相關(guān)的圖片作為屬性添加到類中,并初始化時加載這些圖片 我們再來看一下大魚的資源都有哪些?大魚的是big,大魚會有眼睛,眼睛會有一個動畫,同時身體也會有 一個變化的過程,隨著吃到果實(shí)的數(shù)量不同它的顏色會變,同時它的尾巴還會有一個動畫,這就是所有有關(guān) 大魚的資源,那么在第一階段的課程中呢,我們不做大魚的動畫,僅把大魚的基本東西描繪出來就行了。 我們先不做動畫,所有我們把這些圖片資源放在類里面吧。我們定義幾個圖像屬性: 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"; } 這樣初始化的時候,圖片就加載進(jìn)來了。我們先來刷新一下, 現(xiàn)在我們首先來繪制一下大魚,看這些資源有沒有加載進(jìn)去, 我們把大魚的坐標(biāo)放在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的含義: 我們先來看一下反正切這個函數(shù):這個函數(shù)是計(jì)算里面兩個參數(shù)的反正切值,這兩個參數(shù)呢 y在前,x在后,同時要注意一點(diǎn),它的返回值,是一個數(shù)字,它的區(qū)間是PI到-PI之間,這點(diǎn)要牢記, 因?yàn)榈葧覀円玫竭@個知識,我們?nèi)绾蝸砝L制大魚,我們還是從最基本的開始:首先我們新建一個文件 ,Ctrl+N,Ctrl+S,然后保存在js文件夾下mom.js ,首先把這個js文件包含在html里面: <script type="text/javascript" src="js/mom.js"></script> 我們把魚媽媽也定義為一個類。因?yàn)轸~媽媽也會有各種各樣的屬性,首先,它會有一個坐標(biāo)值,同時我們 肯定也要初始化一下,初始化它的位置,初始化完了之后,我們要在畫布上畫一條大魚,要用到 drawImage,這個結(jié)構(gòu)就有了, var momObj=function(){ this.x; this.y; } momObj.prototype.init=function(){ this.x=0; this.y=0; } momObj.prototype.draw=function(){ } 我們把相應(yīng)的大魚的對象定義一下: //大魚的對象 var mom; 同時在main.js的init方法中把它定義為momObj類型,同時進(jìn)行初始化,并且把draw方法放到gameloop方法中 //new一個大魚對象并且初始化 mom=new momObj(); mom.init();查看全部
-
8,在born方法中降低藍(lán)色果實(shí)生成幾率 好,我們這時候看到有藍(lán)色的果實(shí)出來了,而且藍(lán)色的果實(shí)非常多,我們來調(diào)整一下數(shù)值, 不讓它那么多,否則在寫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"; } } 這個部分,至于數(shù)值(分?jǐn)?shù))是多少,我們程序其實(shí)不用管,這個是策劃做的事情, 好,這樣子藍(lán)色果實(shí)和黃色果實(shí)就有了。 那我們再回來看一下,繪制果實(shí),黃色果實(shí)和藍(lán)色果實(shí)這一部分我們就完成了。查看全部
-
7,修改draw方法:根據(jù)fruitType的值來繪制不同顏色的果實(shí): 好,相應(yīng)的在繪制它的圖片的時候,我們需要根據(jù)它的果實(shí)類型來繪制相應(yīng)的圖片, 我們在外面定義一下: 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){ //果實(shí)生長時果實(shí)長度的變化情況 this.l[i] += this.spd[i]*deltaTime; }else{ //果實(shí)往上漂的速度的變化情況 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
提交
取消