Rumah > hujung hadapan web > tutorial js > JavaScript和HTML5编写游戏Flappy Bird简易版

JavaScript和HTML5编写游戏Flappy Bird简易版

小云云
Lepaskan: 2018-03-17 16:27:49
asal
2583 orang telah melayarinya

上一篇文章我们和大家分享了JS和H5编写推箱子游戏,本文主要和大家分享用js和H5标签编写经典游戏:Flappy Bird 简易版,希望能帮助到大家。

声明:本人初学JS和H5,本文涉及编写方式以及算法如有更好地改进,请各位大佬提出建议~

一.能力要求:
JavaScript相关知识,HTML5,json,面向对象思想等。
二.需要完成以下工作:

1.设计游戏(包括小鸟、柱子等,我们必须遵循一条清晰的逻辑:鸟是在做竖直上抛和自由落体运动,柱子不断创建并向左移动,将鸟和柱子隔离开,各自动各自的)

2.画不会扇翅膀的小鸟

3.让鸟飞起来(自由落体,点击鼠标竖直上抛)

4.逻辑部分(柱子向左移动,小鸟碰到柱子游戏结束等)

5.分数计算(每通过一个柱子分数加1)

6.加背景(图片,音乐,音效等)

三.开始编写:

首先我们需要创建4个类:game.html(用来运行游戏),game.js(用来写逻辑部分),paint.js(用来画物体),pojo.js(用来创建对象,进行封装)

game.html类:

用HTML5编写,需要加,并且我习惯把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>
Salin selepas log masuk

其实在html文件里就调用run()方法,里面就写标签和

pojo.js类:用来存放类,我们需要两个类:小鸟的柱子。在这里,我们做的是简易版的,所以小鸟用圆近似代替,这样的话之后的碰撞检测好写一些。其中,确定的值直接写出来,可变的值不赋值。

书写格式如下:

//鸟类(圆代替)
function Bird(color){
	//鸟的颜色
	this.color = color;
	//鸟巩膜的颜色
	this.eyeColor = &#39;white&#39;;
	//鸟巩膜的半径
	this.eyeRadius = 10;
	//鸟瞳孔的颜色
	this.eyeInsideColor = &#39;black&#39;;
	//鸟瞳孔的半径
	this.eyeInsideRadius = &#39;2.5&#39;;
	//鸟初始位置
	this.left = 100;
	this.top = 300;
	//鸟身体半径
	this.size = 25;
	//鸟的速度
	this.v = 0;		//向下为+	向上为-
	//分数计算
	this.score = 0;
	//是否存活
	this.isLive = true;
}
Salin selepas log masuk

注意:我们一定要把鸟的所有属性要考虑到,封装好在game.js中使用

然后我们还需要写柱子(pillar)类:

//柱子类
//上面下面各一个,在一个竖直线上;
//上下柱子的间隔固定;
//左右两列柱子间隔固定;
//柱子的粗细固定;
//柱子相对鸟的速度
function Pillar(position, length){
	//柱子颜色
	this.color = &#39;lime&#39;;
	//柱子向左移动速度
	this.v = 8;
	//柱子宽度
	this.width = 80;
	//柱子位置,是每个柱子左上角的位置
	this.position = position;
	//柱子长度
	this.length = length;
	//柱子是否存在,意思一会解释
	this.isLive = true;
	//鸟是否通过当前柱子
	this.isPass = false;
}
Salin selepas log masuk

接下来我们要写paint.js类了,也是比较麻烦的一个类,需要用来画:

首先,最重要的,我建议每次写paint.js都放到最前面:清屏(如果不清的话,上一次的画的还会留下,就成“运动轨迹”了):

//清屏
function clearScreen(ctx){
	ctx.clearRect(0, 0, 1536, 750);
}
Salin selepas log masuk

然后,我们画小鸟,画鸟之前,我建议用画图工具画出鸟的大致形状,以便之后用代码画,这是我设计的鸟的图案(翅膀有点复杂,还不知道怎么画好,所以在程序里没有画,见谅)


设计出来以后,我们就可以开始在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 = &#39;black&#39;;
	ctx.fillStyle = &#39;#FC6747&#39;;
	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 = &#39;black&#39;;
	ctx.moveTo(left+1,top+9);
	ctx.lineTo(left+29,top+9);
	ctx.stroke();
	//画翅膀,简易版先不画
}
Salin selepas log masuk

画出来就是这个样子( 我看着都想笑:) )


然后画柱子:

//画柱子,我用了渐变色,虽然调整的并不是很好,但是还能看
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);
}
Salin selepas log masuk

然后我们还要显示计分:

//计分
function paintScore(ctx, score){
	ctx.fillStyle = &#39;red&#39;;
	ctx.font = &#39;40px 黑体&#39;;
	ctx.fillText(&#39;分数:&#39;+score, 1320, 40);
}
Salin selepas log masuk

到这里,我们的工作已经做了一半了,接下来就是最棘手的game.js了,需要考虑逻辑,碰撞,移动,计分等诸多问题。

首先介绍该如何设计小鸟的自由落体:


按照以上方法,编写程序如下:

//点击鼠标事件
document.onmousedown = function (ev){
	//每点击一下出来音效
	var oAudio = document.getElementById(&#39;audio1&#39;);
	oAudio.src = &#39;扇翅膀emm.wav&#39;;
	//每点击一下做一次竖直上抛
	jump(bird);
}

//鸟自由落体
function drop(bird){
	bird.top = bird.top+bird.v;
	bird.v++;
}

//设置竖直上抛,直接将速度修改为负数即可
function jump(bird){
	bird.v = -13;
}
Salin selepas log masuk

接下来是game.js,方便解释,我直接在代码中边编写边解释:

//游戏逻辑中枢
//创建鸟的对象
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(&#39;audio1&#39;);
	oAudio.src = &#39;扇翅膀emm.wav&#39;;
	//每点击一下做一次竖直上抛
	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;
			}
		}
	}
}
Salin selepas log masuk
四.总结:

1.用canvas,js制作时一定需要以上的几个类(当然可以合并,为了辨别每个类的功能我分成了那四个类),需要有面向对象的思想,图画时候用对象里面的参数来画,例如:

paintPillar(ctx, pillar[i].position.x, pillar[i].position.y, pillar[i].width, pillar[i].length);
Salin selepas log masuk

2.关于柱子,我们必须符合这一条逻辑:先创建柱子数组(array),然后创建每个柱子,再画柱子,再移动,四个步骤缺一不可。

3.其中有对于算法的优化:在创建柱子的数组中,我们没有设置很多个柱子(比如说10000,虽然也不可能达到那么高的分),因为这样每25毫秒就要创建那么多柱子,再画和移动,内存占用很高,我们只用建立一个能存放20个柱子的数组,出屏幕的清掉,位置由新的代替,这样就极大程度减少了对内存的需要。

4.关于调试参数(比如说画鸟),要耐心调整,直到满意为止。

5.在检测鸟和柱子的碰幢时候,需要在逻辑上下功夫,建议先在稿纸上画出碰撞条件,再编写程序。

Atas ialah kandungan terperinci JavaScript和HTML5编写游戏Flappy Bird简易版. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan