標籤:重繪 ret etc 位置 公式 png tco 調試 內容
昨天寫到構造炮彈,有點小bug不知道大家發現沒有,今天繼續昨天的步驟
7》構造炮彈 思路和前面都是一樣一樣的 注意建構函式中需要考慮的屬性 和 建構函式的原型上面的方法
<script src="js/resource.js"></script> <script src="js/com.js"></script> <script src="js/fish.js"></script> <script src="js/cannon.js"></script> <script> //開始構造炮彈 //炮彈具體尺寸 var BULLET_SIZE=[ null, {x: 86, y: 0, w: 24, h: 26}, {x: 62, y: 0, w: 25, h: 29}, {x: 30, y: 0, w: 31, h: 35}, {x: 32, y: 35, w: 27, h: 31}, {x: 30, y: 82, w: 29, h: 33}, {x: 0, y: 82, w: 30, h: 34}, {x: 0, y: 0, w: 30, h: 44} ]; //炮彈的建構函式,同樣先在resource.js中載入炮彈的資源, 炮彈的屬性有 type 位置x y rotate iSpeed move function Bullet(type){ this.type=type; this.x=0; this.y=0; this.rotate=0; this.iSpeed=1; this.move(); } //暫時想到的炮彈原型上的方法有draw move ,先寫,後面出現其他的再補充 Bullet.prototype.draw=function(gd){ //同樣的炮彈的尺寸資料表中已經量好並且給出 var w=BULLET_SIZE[this.type].w; var h=BULLET_SIZE[this.type].h; //這裡與前面不同的是需要定義不同尺寸炮彈的起始位置,資料表中已經給出,直接擷取 var x=BULLET_SIZE[this.type].x; var y=BULLET_SIZE[this.type].y; //開始畫炮彈, gd.save(); gd.translate(this.x,this.y); gd.rotate(this.rotate); gd.drawImage(JSON[‘bullet‘], x,y,w,h, -w/2,-h/2,w,h ); gd.restore(); }; //添加炮彈move的方法,和fish運動的思路相同 Bullet.prototype.move=function(){ //開啟定時器不停的改變炮彈的位置並且重繪,同樣,注意事件中的定時器裡的this有問題,需要提前存正確的this的指向 var _this=this; setInterval(function(){ //和魚的move有些不同的是炮彈的y軸的方向不同炮彈都是是向上射出的 _this.x+=Math.sin(d2a(_this.rotate))*_this.iSpeed; _this.y-=Math.cos(d2a(_this.rotate))*_this.iSpeed; },30); }; document.addEventListener(‘DOMContentLoaded‘,function(){ var oC=document.getElementById(‘c1‘); var gd=oC.getContext(‘2d‘); //開始畫炮台 畫炮台需要先載入資源,然後再畫,這裡沒有使用物件導向的概念 loadImage(resource,function(){ //設定炮的初始位置,初始位置在資源檔中已經寫明 var c=new Cannon(4); c.x=431; c.y=570; //存放炮彈的數組 var arrBullet=[]; setInterval(function(){ //炮是在炮台上的,可以在畫炮台的時候一起畫出來,畫之前為了避免重繪,需要先清除畫布 /* gd.save();*/ gd.clearRect(0,0,oC.width,oC.height); gd.drawImage(JSON[‘bottom‘], 0,0,765,70, 0,532,765,70 ); //調用炮的方法draw來畫炮 和魚的轉動相同,當點擊畫布的時候,炮需要跟隨滑鼠的指向來轉動,這裡在轉動的時候我們改改變炮的轉動角度,然後重新不停的刪除,再畫炮 這個效果思路和畫魚相同,需要配合定時器來實現 c.draw(gd); //將當次點擊所產生的炮彈畫出來 for(var i=0;i<arrBullet.length;i++){ arrBullet[i].draw(gd); } /*gd.restore();*/ },30); //當點擊畫布的時候炮的角度對著滑鼠點擊的位置,並進行重繪 oC.onclick=function(ev){ //這裡需要梳理滑鼠點擊的位置和炮旋轉角度之間的關係(附圖說明--炮的旋轉角度.png) var x=ev.clientX-oC.offsetLeft- c.x; var y= c.y-(ev.clientY-oC.offsetTop); //計算角度,注意角度的公式tan是臨邊比對邊,和數學公式的有所不同 Math.atan2(y,x);並且這裡是弧度轉角度,需要在com.js中添加a2d的函數 var d=90-a2d(Math.atan2(y,x)); c.rotate=d; //當點擊的時候產生炮彈,所以在點擊事件中添加炮彈 var bullet=new Bullet(c.type); //炮彈的位置和旋轉角度和炮的位置和旋轉角度相同, bullet.x= c.x; bullet.y= c.y; bullet.rotate = c.rotate; //注意炮彈不能畫在這裡,如果畫在這裡會被畫炮和炮台時所清空,當然潘丹並不是只畫一個,可以用一個數組來儲存所畫出來的炮彈,然後在炮旋轉重繪的時候同時添加炮彈,為了讓點擊事件和定時器都能用到這個數組,這個數組應該寫到事件和定時器的父級的變數空間中 /*bullet.draw(gd);*/ //講當次點擊畫布所建立的炮彈存入arrBullet中 arrBullet.push(bullet); }; }); /* //調用物件導向方法中創造的魚,並在畫布上畫出魚 loadImage(resource,function(){ var f1=new Fish(1); //給出新建立出魚的出事位置 f1.x=300; f1.y=300; //在畫魚的時候需要先清除一次畫布 同樣畫之前需要先儲存,結束以後再儲存 //使魚動起來需要不停的在畫布上擦除上衣畫的魚並且不停的建立新的魚,需要配合定時器來實現 setInterval(function(){ gd.clearRect(0,0,oC.width,oC.height); gd.save(); //畫魚的方法在物件導向中都已經建立,在這直接使用就可以 f1.draw(gd); gd.restore(); },30); });*/ },false); </script></head><body> <canvas id="c1" width="800" height="600"></canvas></body>
8》設定炮彈的顯示範圍 在炮彈跑出螢幕的時候,將畫出的炮彈在炮彈的數組中刪除
loadImage(resource,function(){ //設定炮的初始位置,初始位置在資源檔中已經寫明 var c=new Cannon(4); c.x=431; c.y=570; //存放炮彈的數組 var arrBullet=[]; setInterval(function(){ //炮是在炮台上的,可以在畫炮台的時候一起畫出來,畫之前為了避免重繪,需要先清除畫布 /* gd.save();*/ gd.clearRect(0,0,oC.width,oC.height); gd.drawImage(JSON[‘bottom‘], 0,0,765,70, 0,532,765,70 ); //調用炮的方法draw來畫炮 和魚的轉動相同,當點擊畫布的時候,炮需要跟隨滑鼠的指向來轉動,這裡在轉動的時候我們改改變炮的轉動角度,然後重新不停的刪除,再畫炮 這個效果思路和畫魚相同,需要配合定時器來實現 c.draw(gd); //將當次點擊所產生的炮彈畫出來 for(var i=0;i<arrBullet.length;i++){ arrBullet[i].draw(gd); } //這裡由於炮彈不停的被創造,數組中也變得越來越大,當炮彈到達一定位置(移出螢幕)的時候,應該清除前面沒用的炮彈,避免效能的浪費。注意,我們需要檢測每個炮彈的位置,有我就是整個數組所有參數身上的x y for(var i=0;i<arrBullet.length;i++){ if(arrBullet[i].x<0 || arrBullet[i].x>oC.width || arrBullet[i].y>oC.height || arrBullet[i].y<0){ arrBullet.splice(i,1); i--; } } /*gd.restore();*/ },30);
昨天的小bug,旋轉的時候角度的調試不對,是在寫炮彈屬性rotate的時候沒有將角度轉為弧度
//暫時想到的炮彈原型上的方法有draw move ,先寫,後面出現其他的再補充Bullet.prototype.draw=function(gd){ //同樣的炮彈的尺寸資料表中已經量好並且給出 var w=BULLET_SIZE[this.type].w; var h=BULLET_SIZE[this.type].h; //這裡與前面不同的是需要定義不同尺寸炮彈的起始位置,資料表中已經給出,直接擷取 var x=BULLET_SIZE[this.type].x; var y=BULLET_SIZE[this.type].y; //開始畫炮彈, gd.save(); gd.translate(this.x,this.y);//這裡沒有將角度轉為弧度 gd.rotate(d2a(this.rotate)); gd.drawImage(JSON[‘bullet‘], x,y,w,h, -w/2,-h/2,w,h ); gd.restore();};
9》加入魚
下面的代碼只加入魚從左面出來的情況
loadImage(resource,function(){ //設定炮的初始位置,初始位置在資源檔中已經寫明 var c=new Cannon(4); c.x=431; c.y=570; //存放炮彈的數組 var arrBullet=[]; //存放魚的數組 var arrFish=[]; setInterval(function(){ //炮是在炮台上的,可以在畫炮台的時候一起畫出來,畫之前為了避免重繪,需要先清除畫布 /* gd.save();*/ gd.clearRect(0,0,oC.width,oC.height); //創造魚並規定魚產生的位置,這裡唯寫了魚只能從左面出來 //畫魚 var f1=new Fish(rnd(1,6)); f1.x=-50; f1.y=rnd(0,oC.height); // f1.rotate=rnd(-90,90); arrFish.push(f1); for(var i=0;i<arrFish.length;i++){ arrFish[i].draw(gd); } gd.drawImage(JSON[‘bottom‘], 0,0,765,70, 0,532,765,70 ); //調用炮的方法draw來畫炮 和魚的轉動相同,當點擊畫布的時候,炮需要跟隨滑鼠的指向來轉動,這裡在轉動的時候我們改改變炮的轉動角度,然後重新不停的刪除,再畫炮 這個效果思路和畫魚相同,需要配合定時器來實現 c.draw(gd); //將當次點擊所產生的炮彈畫出來 for(var i=0;i<arrBullet.length;i++){ arrBullet[i].draw(gd); } //這裡由於炮彈不停的被創造,數組中也變得越來越大,當炮彈到達一定位置(移出螢幕)的時候,應該清除前面沒用的炮彈,避免效能的浪費。注意,我們需要檢測每個炮彈的位置,有我就是整個數組所有參數身上的x y for(var i=0;i<arrBullet.length;i++){ if(arrBullet[i].x<0 || arrBullet[i].x>oC.width || arrBullet[i].y>oC.height || arrBullet[i].y<0){ arrBullet.splice(i,1); i--; } } /*gd.restore();*/ },30); //當點擊畫布的時候炮的角度對著滑鼠點擊的位置,並進行重繪 oC.onclick=function(ev){ //這裡需要梳理滑鼠點擊的位置和炮旋轉角度之間的關係(附圖說明--炮的旋轉角度.png) var x=ev.clientX-oC.offsetLeft- c.x; var y= c.y-(ev.clientY-oC.offsetTop); //計算角度,注意角度的公式tan是臨邊比對邊,和數學公式的有所不同 Math.atan2(y,x);並且這裡是弧度轉角度,需要在com.js中添加a2d的函數 var d=90-a2d(Math.atan2(y,x)); c.rotate=d; //當點擊的時候產生炮彈,所以在點擊事件中添加炮彈 var bullet=new Bullet(c.type); //炮彈的位置和旋轉角度和炮的位置和旋轉角度相同, bullet.x= c.x; bullet.y= c.y; bullet.rotate = c.rotate; //注意炮彈不能畫在這裡,如果畫在這裡會被畫炮和炮台時所清空,當然潘丹並不是只畫一個,可以用一個數組來儲存所畫出來的炮彈,然後在炮旋轉重繪的時候同時添加炮彈,為了讓點擊事件和定時器都能用到這個數組,這個數組應該寫到事件和定時器的父級的變數空間中 /*bullet.draw(gd);*/ //講當次點擊畫布所建立的炮彈存入arrBullet中 arrBullet.push(bullet); };});
相同的,魚只從右面出來的情況值是改變了魚初始位置的x 和rotate
//畫魚 魚從右面出來的情況var f1=new Fish(rnd(1,6));f1.x=oC.width+50;f1.y=rnd(0,oC.height);//f1.rotate=rnd(90,270);arrFish.push(f1);for(var i=0;i<arrFish.length;i++){ arrFish[i].draw(gd);}
魚隨機從兩邊出來,com.js檔案中添加隨機數的公用函數
function rnd(m,n){ return parseInt(Math.random()*(n-m)+m);}
index.html中的內容
document.addEventListener(‘DOMContentLoaded‘,function(){ var oC=document.getElementById(‘c1‘); var gd=oC.getContext(‘2d‘); var rule=0.5; //開始畫炮台 畫炮台需要先載入資源,然後再畫,這裡沒有使用物件導向的概念 loadImage(resource,function(){ //設定炮的初始位置,初始位置在資源檔中已經寫明 var c=new Cannon(4); c.x=431; c.y=570; //存放炮彈的數組 var arrBullet=[]; //存放魚的數組 var arrFish=[]; setInterval(function(){ //炮是在炮台上的,可以在畫炮台的時候一起畫出來,畫之前為了避免重繪,需要先清除畫布 /* gd.save();*/ gd.clearRect(0,0,oC.width,oC.height); //創造魚並規定魚產生的位置,這裡唯寫了魚只能從左面出來 //畫魚 魚從左右兩邊同時隨機出現 實現這個的原理是Math.random()是0-1的數,這裡設定一個規則,rule=0.5,所以兩邊幾率各為50%; if(Math.random()<rule){ var f1=new Fish(rnd(1,6)); f1.x=oC.width+50; f1.y=rnd(0,oC.height); // f1.rotate=rnd(90,270); }else{ var f1=new Fish(rnd(1,6)); f1.x=-50; f1.y=rnd(0,oC.height); // f1.rotate=rnd(-90,90); } arrFish.push(f1); for(var i=0;i<arrFish.length;i++){ arrFish[i].draw(gd); } gd.drawImage(JSON[‘bottom‘], 0,0,765,70, 0,532,765,70 ); //調用炮的方法draw來畫炮 和魚的轉動相同,當點擊畫布的時候,炮需要跟隨滑鼠的指向來轉動,這裡在轉動的時候我們改改變炮的轉動角度,然後重新不停的刪除,再畫炮 這個效果思路和畫魚相同,需要配合定時器來實現 c.draw(gd); //將當次點擊所產生的炮彈畫出來 for(var i=0;i<arrBullet.length;i++){ arrBullet[i].draw(gd); } //這裡由於炮彈不停的被創造,數組中也變得越來越大,當炮彈到達一定位置(移出螢幕)的時候,應該清除前面沒用的炮彈,避免效能的浪費。注意,我們需要檢測每個炮彈的位置,有我就是整個數組所有參數身上的x y for(var i=0;i<arrBullet.length;i++){ if(arrBullet[i].x<0 || arrBullet[i].x>oC.width || arrBullet[i].y>oC.height || arrBullet[i].y<0){ arrBullet.splice(i,1); i--; } } /*gd.restore();*/ },30); //當點擊畫布的時候炮的角度對著滑鼠點擊的位置,並進行重繪 oC.onclick=function(ev){ //這裡需要梳理滑鼠點擊的位置和炮旋轉角度之間的關係(附圖說明--炮的旋轉角度.png) var x=ev.clientX-oC.offsetLeft- c.x; var y= c.y-(ev.clientY-oC.offsetTop); //計算角度,注意角度的公式tan是臨邊比對邊,和數學公式的有所不同 Math.atan2(y,x);並且這裡是弧度轉角度,需要在com.js中添加a2d的函數 var d=90-a2d(Math.atan2(y,x)); c.rotate=d; //當點擊的時候產生炮彈,所以在點擊事件中添加炮彈 var bullet=new Bullet(c.type); //炮彈的位置和旋轉角度和炮的位置和旋轉角度相同, bullet.x= c.x; bullet.y= c.y; bullet.rotate = c.rotate; //注意炮彈不能畫在這裡,如果畫在這裡會被畫炮和炮台時所清空,當然潘丹並不是只畫一個,可以用一個數組來儲存所畫出來的炮彈,然後在炮旋轉重繪的時候同時添加炮彈,為了讓點擊事件和定時器都能用到這個數組,這個數組應該寫到事件和定時器的父級的變數空間中 /*bullet.draw(gd);*/ //講當次點擊畫布所建立的炮彈存入arrBullet中 arrBullet.push(bullet); }; });
降低魚出現的機率這裡改rule=0.05;
//畫魚 魚從左右兩邊同時隨機出現 實現這個的原理是Math.random()是0-1的數,定時器的觸發時間是30ms一秒鐘30多條魚的誕生有些多,所以在這裡我們需要修改規則rule來降低魚出現的機率,當rule=0.05(機率為原來的20%),再加入一個參數decoration,然後用Math.random()-0.5得出的這個值的範圍時0.5到-0.5,這樣正負的機率分別為50%,這樣我們就能繼續進行魚誕生的方向了;var decoration=Math.random()-0.5;if(Math.random()<rule){ if(decoration<0){ var f1=new Fish(rnd(1,6)); f1.x=oC.width+50; f1.y=rnd(0,oC.height); // f1.rotate=rnd(91,269); }else{ var f1=new Fish(rnd(1,6)); f1.x=-50; f1.y=rnd(0,oC.height); // f1.rotate=rnd(-89,89); } arrFish.push(f1);}for(var i=0;i<arrFish.length;i++){ arrFish[i].draw(gd);}
和炮彈相同的,對魚進行了最佳化
for(var i=0;i<arrFish.length;i++){ arrFish[i].draw(gd);}//和炮彈一樣,對魚進行效能最佳化,再魚遊出螢幕一定範圍之後,便將魚從魚的數組中清除for(var i=0;i<arrFish.length;i++){ if(arrFish[i].x<-50 || arrFish[i].x>(oC.width+50) || arrFish[i].y<0 || arrFish[i].y>(oC.height+50)){ arrFish.splice(i,1); i--; }}
10》檢測是否打到魚
for(var i=0;i<arrBullet.length;i++){ if(arrBullet[i].x<0 || arrBullet[i].x>oC.width || arrBullet[i].y>oC.height || arrBullet[i].y<0){ arrBullet.splice(i,1); i--; }}//進行碰撞檢測,這裡只做了簡單的碰撞檢測,我們把每個模型(魚和子彈)都考慮成了原型,當兩個物體的距離小於兩個物體的半徑之和的時候表明兩個物體碰撞,注意,需要迴圈檢測存在的所有的魚,我們可以提前做一個函數來判斷這個距離,當得到碰撞距離的時候函數返回true,當得到沒有碰撞的距離的時候,函數返回的是false,這個函數是每條魚身上的一個方法,每條魚在遊動的時候都在不停的計算這個值,並不停的返回真或者假來供我們判斷是否和子彈碰撞for(var i=0;i<arrFish.length;i++){ for(var j=0;j<arrBullet.length;j++){ if(arrFish[i].isIn(arrBullet[j].x, arrBullet[j].y)){ alert(‘碰到了‘); } }}
在魚的fish.js檔案中給魚添加檢測碰撞的方法 , 大家可以更改子彈的速度this.iSpeed=this.type*2; 這樣子彈的型號越大,子彈的速度也就越快
//傳入的兩個參數x y是子彈的即時位置Fish.prototype.isIn=function(x,y){ var a=this.x-x; var b=this.y-y; var c=Math.sqrt(a*a+b*b); //這裡需要提前在魚的建構函式中添加this.collR的屬性this.collR=FISH_SIZE[this.type].collR; if(c<=this.collR){ return true; }else{ return false; }};
碰撞之後刪除魚和子彈
//進行碰撞檢測,這裡只做了簡單的碰撞檢測,我們把每個模型(魚和子彈)都考慮成了原型,當兩個物體的距離小於兩個物體的半徑之和的時候表明兩個物體碰撞,注意,需要迴圈檢測存在的所有的魚,我們可以提前做一個函數來判斷這個距離,當得到碰撞距離的時候函數返回true,當得到沒有碰撞的距離的時候,函數返回的是false,這個函數是每條魚身上的一個方法,每條魚在遊動的時候都在不停的計算這個值,並不停的返回真或者假來供我們判斷是否和子彈碰撞for(var i=0;i<arrFish.length;i++){ for(var j=0;j<arrBullet.length;j++){ if(arrFish[i].isIn(arrBullet[j].x, arrBullet[j].y)){ /*alert(‘碰到了‘);*/ //在魚碰到了之後,我們需要做的是讓相互碰撞的魚和子彈都消失,也就是從魚和子彈的數組中刪除 arrFish.splice(i,1); i--; arrBullet.splice(j,1); j--; } }}
今天先寫到這裡,明天繼續
轉載請註明‘轉載於Jason齊齊的部落格http://www.cnblogs.com/jasonwang2y60/’
js原生捕魚達人(二)