上一篇文章我們和大家分享了JS和H5編寫推箱子遊戲,本文主要和大家分享用js和H55ba626b379994d53f7acf72a64f9b697標籤編寫經典遊戲:Flappy Bird 簡易版,希望能幫助大家。
聲明:本人初學JS和H5,本文涉及編寫方式以及演算法如有更好地改進,請各位大佬提出建議~
1.設計遊戲(包括小鳥、柱子等,我們必須遵循一條清晰的邏輯:鳥是在做豎直上拋和自由落體運動,柱子不斷創建並向左移動,將鳥和柱子隔離開,各自動各自的)
2.畫不會扇翅膀的小鳥
3.讓鳥飛起來(自由落體,點擊滑鼠垂直上拋)
4.邏輯部分(柱子向左移動,小鳥碰到柱子遊戲結束等)
#5.分數計算(每透過一個柱子分數加1)
6.加背景(圖片,音樂,音效等)
##首先我們需要創建4個類別:game.html(用來運行遊戲),game.js(用來寫邏輯部分),paint.js(用來畫物體),pojo.js(用來創建對象,進行封裝)
game.html類別:
用HTML5寫,需要加fef50554eca1a427827adaa329da8122,而且我習慣把margin設定為0 :
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> <title>flappy bird</title> <style> /*设置边距为0*/ body{ margin:0px; overflow:hidden; } /*加背景*/ #can1{ background-image: url(背景.jpg); background-size:100%100%; } </style> <script type="text/javascript" src="pojo.js"></script> <script type="text/javascript" src="game.js"></script> <script type="text/javascript" src="paint.js"></script> <!--调用run()--> <script> window.onload = function (){ run(); }; </script> </head> <body> <!--画布标签,设置长宽像素--> <canvas id="can1" width="1536" height="733"></canvas> <!--加入背景音乐--> <audio src="bgm.mp3" autoplay loop></audio> <!--加入点击鼠标触发的音效--> <audio id="audio1" autoplay></audio> </body> </html>
其實在html檔案裡就呼叫run()方法,6c04bd5ca3fcae76e30b72ad730ca86d裡面就寫5ba626b379994d53f7acf72a64f9b697標籤和b97864c2e0ef2353a16c4d64c7734e92用來調入音訊檔案
pojo.js類別:用來存放類別,我們需要兩個類別:小鳥的柱子。在這裡,我們做的是簡易版的,所以小鳥用圓近似代替,這樣的話之後的碰撞檢測好寫一些。其中,確定的值直接寫出來,可變的值不賦值。
書寫格式如下:
//鸟类(圆代替) function Bird(color){ //鸟的颜色 this.color = color; //鸟巩膜的颜色 this.eyeColor = 'white'; //鸟巩膜的半径 this.eyeRadius = 10; //鸟瞳孔的颜色 this.eyeInsideColor = 'black'; //鸟瞳孔的半径 this.eyeInsideRadius = '2.5'; //鸟初始位置 this.left = 100; this.top = 300; //鸟身体半径 this.size = 25; //鸟的速度 this.v = 0; //向下为+ 向上为- //分数计算 this.score = 0; //是否存活 this.isLive = true; }
#注意:我們一定要把鳥的所有屬性要考慮到,封裝好在game.js中使用
然後我們還需要寫柱子(pillar)類別:
//柱子类 //上面下面各一个,在一个竖直线上; //上下柱子的间隔固定; //左右两列柱子间隔固定; //柱子的粗细固定; //柱子相对鸟的速度 function Pillar(position, length){ //柱子颜色 this.color = 'lime'; //柱子向左移动速度 this.v = 8; //柱子宽度 this.width = 80; //柱子位置,是每个柱子左上角的位置 this.position = position; //柱子长度 this.length = length; //柱子是否存在,意思一会解释 this.isLive = true; //鸟是否通过当前柱子 this.isPass = false; }
#接下來我們要寫paint.js類別了,也是比較麻煩的一個類,需要用5ba626b379994d53f7acf72a64f9b697來畫:
#首先,最重要的,我建議每次寫paint.js都放到最前面:清屏(如果不清的話,上一次的畫的還會留下,就成「運動軌跡」了):
//清屏 function clearScreen(ctx){ ctx.clearRect(0, 0, 1536, 750); }
然後,我們畫小鳥,畫鳥之前,我建議用畫圖工具畫出鳥的大致形狀,以便之後用代碼畫,這是我設計的鳥的圖案(翅膀有點複雜,還不知道怎麼畫好,所以在程序裡沒有畫,見諒)
設計出來以後,我們就可以開始在paint.js裡面畫了(我把獲取畫布和創建畫筆寫在了game.js裡面而不是paint.js):
//画鸟,同样,所有的变量属性都要考虑到,并且在画巩膜,瞳孔,嘴唇时候都要以变量作为基准!里面的参数需要耐下心来调整。 function paintBird(ctx, left, top, size, color){ ctx.beginPath(); ctx.fillStyle = color; ctx.arc(left, top, size, 0, 2*Math.PI);//left:100 top:300 size:25 ctx.fill(); //画巩膜 ctx.beginPath(); ctx.fillStyle = bird.eyeColor; ctx.arc(left+13,top-8,bird.eyeRadius,0,2*Math.PI); ctx.fill(); //画瞳孔 ctx.beginPath(); ctx.fillStyle = bird.eyeInsideColor; ctx.arc(left+18,top-8,bird.eyeInsideRadius,0,2*Math.PI); ctx.fill(); //画嘴唇 ctx.beginPath(); ctx.strokeStyle = 'black'; ctx.fillStyle = '#FC6747'; ctx.moveTo(left+4, top+3); ctx.lineTo(left+29, top+3); ctx.lineTo(left+33, top+6); ctx.lineTo(left+29, top+9); ctx.lineTo(left+32, top+12); ctx.lineTo(left+29, top+15); ctx.lineTo(left+4, top+15); ctx.lineTo(left+1, top+9); ctx.closePath(); ctx.stroke(); ctx.fill(); ctx.beginPath(); ctx.strokeStyle = 'black'; ctx.moveTo(left+1,top+9); ctx.lineTo(left+29,top+9); ctx.stroke(); //画翅膀,简易版先不画 }
畫出來就是這樣( 我看著都想笑:) )
//画柱子,我用了渐变色,虽然调整的并不是很好,但是还能看
function paintPillar(ctx, left, top, width, height){
ctx.beginPath();
var grd=ctx.createLinearGradient(left,top,left+height,top);
grd.addColorStop(0,"green");
grd.addColorStop(0.45,"white");
grd.addColorStop(1,"green");
ctx.fillStyle = grd;
ctx.fillRect(left, top, width, height);
}
//计分
function paintScore(ctx, score){
ctx.fillStyle = 'red';
ctx.font = '40px 黑体';
ctx.fillText('分数:'+score, 1320, 40);
}
首先介紹如何設計小鳥的自由落體:
//点击鼠标事件
document.onmousedown = function (ev){
//每点击一下出来音效
var oAudio = document.getElementById('audio1');
oAudio.src = '扇翅膀emm.wav';
//每点击一下做一次竖直上抛
jump(bird);
}
//鸟自由落体
function drop(bird){
bird.top = bird.top+bird.v;
bird.v++;
}
//设置竖直上抛,直接将速度修改为负数即可
function jump(bird){
bird.v = -13;
}
//游戏逻辑中枢
//创建鸟的对象
var bird = new Bird('#FBEE30');
//创建柱子对象,把20个柱子放到数组中
var pillar = new Array(20);
var count = 0;
function run(){
//获取画布
var oCan = document.getElementById('can1');
//创建画笔,2d
var ctx = oCan.getContext('2d');
//这timer1是游戏页面显示的东西的线程,每25毫秒刷新一次
var timer1 = setInterval(function (){
//每次画之前先清屏
clearScreen(ctx);
//判断鸟是否碰上柱子(是否死亡),死亡则弹框,结束线程
if(!bird.isLive){
alert('游戏结束!你的分数是'+bird.score+'!你好菜啊!')
clearInterval(timer1);
clearInterval(timer2);
}
//降落一下
drop(bird);
//判断鸟是否通过柱子
for(var i = 0; i < pillar.length; i++){
if(pillar[i] != null && pillar[i].isLive){
//移动柱子
movePillar(pillar[i]);
//画柱子
paintPillar(ctx, pillar[i].position.x, pillar[i].position.y, pillar[i].width, pillar[i].length);
//计分,如果每个鸟的身体(圆)的左边通过一个柱子的最右边时,加一分
if(pillar[i].position.x+pillar[i].width <= bird.left-bird.size && !pillar[i].isPass){
//这里是因为每次通过上下两个柱子,如果是++的话就会每次加2,所以用+=0.5
bird.score += 0.5;
//通过的柱子将isPass设置为true,否则程序将默认鸟通过了所有柱子,就会加每次21
pillar[i].isPass = true;
}
}
}
//检验鸟碰到柱子
for(var i = 0; i < pillar.length; i++){
if(pillar[i] != null && pillar[i].isLive){
judgeImpact(bird, pillar[i]);
}
}
//死亡后执行
//画鸟
paintBird(ctx, bird.left, bird.top, bird.size, bird.color);
paintScore(ctx, bird.score);
}, 25);
//这个timer2是创建柱子的线程
var timer2 = setInterval(function (){
//上面的柱子的长度
var l = Math.random()*330+100;
//上面柱子,用json传变量
pillar[count++] = new Pillar({x:1536, y:0}, l);
//下面柱子
pillar[count++] = new Pillar({x:1536, y:l+200}, 733-l-200);
//如果柱子达到20个,自动将第20个设置为第0个,节省了内存,属于算法优化
if(count == 20){
count = 0;
}
}, 1100);
}
//点击鼠标事件
document.onmousedown = function (ev){
//每点击一下出来音效
var oAudio = document.getElementById('audio1');
oAudio.src = '扇翅膀emm.wav';
//每点击一下做一次竖直上抛
jump(bird);
}
//鸟自由落体
function drop(bird){
bird.top = bird.top+bird.v;
bird.v++;
}
//设置竖直上抛,直接将速度修改为负数即可
function jump(bird){
bird.v = -13;
}
//移动柱子
function movePillar(pillar){
pillar.position.x -= pillar.v;
//如果柱子移动出画布,将isLive设置为false
if(pillar.position.x < -80){
pillar.isLive = false;
}
}
//检测鸟和柱子碰撞
function judgeImpact(bird, pillar){
//碰到上边框,死亡
if(bird.top < bird.size){
bird.isLive = false;
bird.top = bird.size;
}
//碰到下边框,死亡
else if(bird.top > 733-bird.size){
bird.isLive = false;
bird.top = 733-bird.size;
}
//当小鸟嵌入上下柱子的左边时(检验鸟是否碰到柱子的左边)
if(Math.abs(bird.left-pillar.position.x) <= bird.size){
//碰到上面柱子的左边
if(pillar.position.y == 0){
if(bird.top < pillar.length){
bird.isLive = false;
bird.left = pillar.position.x-bird.size;
}
}
//碰到下面柱子的左边
else{
if(bird.top > pillar.position.y){
bird.isLive = false;
bird.left = pillar.position.x-bird.size;
}
}
}
//如果是上面柱子
if(pillar.position.y == 0){
//如果小鸟高度小于上面柱子
if(Math.abs(bird.top-pillar.length) <= bird.size){
//并且小鸟在两个柱子之间,死亡
if(bird.left+bird.size > pillar.position.x && bird.left+bird.size < pillar.position.x+pillar.width+30){
bird.isLive = false;
bird.top = pillar.length+bird.size;
}
}
}
//如果是下面柱子
else{
//如果小鸟高度大于 下面柱子上方距离顶部的高度
if(Math.abs(bird.top-pillar.position.y) <= bird.size){
//并且小鸟在两个柱子之间,死亡
if(bird.left+bird.size > pillar.position.x && bird.left+bird.size < pillar.position.x+pillar.width+30){
bird.isLive = false;
bird.top = pillar.position.y-bird.size;
}
}
}
}
四.總結:
# 2.关于柱子,我们必须符合这一条逻辑:先创建柱子数组(array),然后创建每个柱子,再画柱子,再移动,四个步骤缺一不可。 3.其中有对于算法的优化:在创建柱子的数组中,我们没有设置很多个柱子(比如说10000,虽然也不可能达到那么高的分),因为这样每25毫秒就要创建那么多柱子,再画和移动,内存占用很高,我们只用建立一个能存放20个柱子的数组,出屏幕的清掉,位置由新的代替,这样就极大程度减少了对内存的需要。 4.关于调试参数(比如说画鸟),要耐心调整,直到满意为止。 5.在检测鸟和柱子的碰幢时候,需要在逻辑上下功夫,建议先在稿纸上画出碰撞条件,再编写程序。paintPillar(ctx, pillar[i].position.x, pillar[i].position.y, pillar[i].width, pillar[i].length);
以上是JavaScript與HTML5編寫遊戲Flappy Bird簡易版的詳細內容。更多資訊請關注PHP中文網其他相關文章!