js原生捕鱼达人(一)
捕魚達人的游戲大家都很熟悉吧,接下來的兩三天,我會將整個游戲的原生js寫法詳細的寫出來,整個游戲應用了面向對象的寫法:創建構造函數,在構造函數上面添加對象的屬性,然后在構造函數的原型上添加方法,當然這個程序使用了canvas來繪制,每一步的我都已經分別寫出來,詳細的步驟我在寫代碼的過程中都已經標注了出來。
下面是捕魚達人的素材庫:
1》加載資源
<style>*{padding: 0;margin: 0;}body{background:#000;text-align:center;overflow:hidden;}#c1{background:url(img/game_bg_2_hd.jpg);margin:40px auto;}</style><script>var JSON={};function loadImage(arr,fnSucc){//為了測試是否加載完成,設置count,在加載的時候使count++,判斷count的值來判斷是否加載完成var count=0;for(var i=0;i<arr.length;i++){var oImg=new Image();//加載所有魚的資源(function(index){oImg.οnlοad=function(){//把所有資源加載,并且存到JSON中,注意,循環中有事件,事件里的i值不對,解決用封閉空間JSON[arr[index]]=this;count++;//當count的值和需要加載的資源的數組相同的時候,資源加載完畢if(count==arr.length){fnSucc && fnSucc();}};})(i);oImg.src='img/'+arr[i]+'.png';}}document.addEventListener('DOMContentLoaded',function(){var oC=document.getElementById('c1');var gd=oC.getContext('2d');var oImg=new Image();loadImage(['fish1','fish2','fish3','fish4','fish5'],function(){gd.drawImage(JSON['fish3'],0,0);})},false);</script> </head> <body><canvas id="c1" width="800" height="600"></canvas> </body>2》拆文件 ? com(util.js).js? 工具函數文件 resource -> 資源文件 com.js文件 /** * Created by Jason on 2016/11/2. */ var JSON={}; function loadImage(arr,fnSucc){//為了測試是否加載完成,設置count,在加載的時候使count++,判斷count的值來判斷是否加載完成var count=0;for(var i=0;i<arr.length;i++){var oImg=new Image();//加載所有魚的資源(function(index){oImg.οnlοad=function(){//把所有資源加載,并且存到JSON中,注意,循環中有事件,事件里的i值不對,解決用封閉空間JSON[arr[index]]=this;count++;//當count的值和需要加載的資源的數組相同的時候,資源加載完畢if(count==arr.length){fnSucc && fnSucc();}};})(i);oImg.src='img/'+arr[i]+'.png';} }
?resource.js文件
/** * Created by Jason on 2016/11/2. */ //把所有資源放到一個resource的數組中,方便加載資源的函數loadImage調用 var resource=['fish1','fish2','fish3','fish4','fish5'];index.html
<style>*{padding: 0;margin: 0;}body{background:#000;text-align:center;overflow:hidden;}#c1{background:url(img/game_bg_2_hd.jpg);margin:40px auto;}</style><script src="js/resource.js"></script><script src="js/com.js"></script><script>document.addEventListener('DOMContentLoaded',function(){var oC=document.getElementById('c1');var gd=oC.getContext('2d');var oImg=new Image();loadImage(resource,function(){gd.drawImage(JSON['fish3'],0,0);})},false);</script> </head> <body><canvas id="c1" width="800" height="600"></canvas> </body>3》先畫一條魚(以下步驟js文件中未改變的都沒有提到,大家自己把代碼歸類存放,最后我會給出所有最終版的多有文件的全部代碼)
關于魚游動的角度的計算我也畫了圖
以下尺寸經過ps測量:
//魚
var FISH_SIZE=[
???? null,
???? {w: 55, h: 37, collR: 17},
???? {w: 78, h: 64, collR: 24},
???? {w: 72, h: 56, collR: 20},
???? {w: 77, h: 59, collR: 22},
???? {w: 107, h: 122, collR: 29}
];
--------------------------
炮臺尺寸:
寬度:765, 高度:70
距離畫布上方的距離是:532
--------------------------
炮的位置:
???? x=431;
???? y=570;
--------------------------
炮的尺寸:
//炮
var CANNON_SIZE=[
???? null,
???? {w: 74, h: 74},
???? {w: 74, h: 76},
???? {w: 74, h: 76},
???? {w: 74, h: 83},
???? {w: 74, h: 85},
???? {w: 74, h: 90},
???? {w: 74, h: 94}
];
-----------------------------
//炮彈具體尺寸
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}
];
4》畫炮臺 ?尺寸見3中的位置
document.addEventListener('DOMContentLoaded',function(){var oC=document.getElementById('c1');var gd=oC.getContext('2d');//開始畫炮臺 畫炮臺需要先加載資源,然后再畫,這里沒有使用面向對象的概念loadImage(resource,function(){gd.drawImage(JSON['bottom'],0,0,765,70,0,532,765,70)});5》畫炮,尺寸詳見3中的位置,代碼思路同畫魚
//炮var CANNON_SIZE=[null,{w: 74, h: 74},{w: 74, h: 76},{w: 74, h: 76},{w: 74, h: 83},{w: 74, h: 85},{w: 74, h: 90},{w: 74, h: 94}];//構建炮的構造函數 炮彈的屬性有位置x y type rotate 添加的同時注意在resource.js文件中添加需要加載的資源function Cannon(type){this.type=type;this.x=0;this.y=0;this.rotate=0;}//構建炮的原型,炮的原型上面有draw的方法Cannon.prototype.draw=function(gd){//和魚的原型相同,先要設置炮臺的尺寸w h,同樣的再2中的尺寸表中var w=CANNON_SIZE[this.type].w;var h=CANNON_SIZE[this.type].h;//開始畫炮臺,注意先save最后再restore,炮臺是可以旋轉的gd.save();gd.translate(this.x,this.y);gd.rotate(d2a(this.rotate));gd.drawImage(JSON['cannon'+this.type],0,0,w,h,-w/2,-h/2,w,h);gd.restore();};document.addEventListener('DOMContentLoaded',function(){var oC=document.getElementById('c1');var gd=oC.getContext('2d');//開始畫炮臺 畫炮臺需要先加載資源,然后再畫,這里沒有使用面向對象的概念loadImage(resource,function(){gd.drawImage(JSON['bottom'],0,0,765,70,0,532,765,70)//炮是在炮臺上的,可以在畫炮臺的時候一起畫出來var c=new Cannon(4);//設置炮的初始位置,初始位置在資源文件中已經寫明c.x=431;c.y=570;//調用炮的方法draw來畫炮gd.save();c.draw(gd);c.restore();});/* //調用面向對象方法中創造的魚,并在畫布上畫出魚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>6》創建點擊畫布炮轉向的功能 ? 相同的再這一步完成之后,給炮單獨建立一個js文件存放到js文件夾下(cannon.js文件);并把a2d的函數放到com.js文件中
關于炮的旋轉角度的計算,請看我的圖,其中寫錯了一個,懶得改了大家應該能看懂
<script src="js/resource.js"></script><script src="js/com.js"></script><script src="js/fish.js"></script><script>function a2d(n){return n*180/Math.PI;}//炮var CANNON_SIZE=[null,{w: 74, h: 74},{w: 74, h: 76},{w: 74, h: 76},{w: 74, h: 83},{w: 74, h: 85},{w: 74, h: 90},{w: 74, h: 94}];//構建炮的構造函數 炮彈的屬性有位置x y type rotate 添加的同時注意在resource.js文件中添加需要加載的資源function Cannon(type){this.type=type;this.x=0;this.y=0;this.rotate=0;}//構建炮的原型,炮的原型上面有draw的方法Cannon.prototype.draw=function(gd){//和魚的原型相同,先要設置炮臺的尺寸w h,同樣的再2中的尺寸表中var w=CANNON_SIZE[this.type].w;var h=CANNON_SIZE[this.type].h;//開始畫炮臺,注意先save最后再restore,炮臺是可以旋轉的gd.save();gd.translate(this.x,this.y);gd.rotate(d2a(this.rotate));gd.drawImage(JSON['cannon'+this.type],0,0,w,h,-w/2,-h/2,w,h);gd.restore();};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;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);gd.restore();},30);//當點擊畫布的時候炮的角度對著鼠標點擊的位置,并進行重繪oC.οnclick=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;};});/* //調用面向對象方法中創造的魚,并在畫布上畫出魚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>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 movefunction 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.οnclick=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>
其中炮彈中有個小bug,明天繼續寫
?
?
轉載請注明‘轉載于Jason齊齊的博客http://www.cnblogs.com/jasonwang2y60/’
轉載于:https://www.cnblogs.com/jasonwang2y60/p/6025101.html
總結
以上是生活随笔為你收集整理的js原生捕鱼达人(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 判断pc浏览器和手机浏览器方法
- 下一篇: [转]正确配置Linux系统ulimit