问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

有类似Flappy Bird的HTML5游戏么

发布网友 发布时间:2022-04-23 06:22

我来回答

3个回答

懂视网 时间:2022-04-23 10:44

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

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

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

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

2.画不会扇翅膀的小鸟

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

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

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

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

三.开始编写:

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

game.html类:

用HTML5编写,需要加<!DOCTYPE HTML>,并且我习惯把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()方法,<body>里面就写<canvas>标签和<audio>用来调入音频文件

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类了,也是比较麻烦的一个类,需要用<canvas>来画:

首先,最重要的,我建议每次写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);
}

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

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


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

//点击鼠标事件
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;
}

接下来是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('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;
			}
		}
	}
}
四.总结:

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

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

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

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

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

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

热心网友 时间:2022-04-23 07:52

只用HTML5和JS,CSS写的游戏(2048,围住神经猫,flappy bird),之前火过一段时间,现在还好,有发展前景,但是只适合轻中度游戏,不能做大型重度游戏

热心网友 时间:2022-04-23 09:10

您可以去H5e学习网看看,里面有很多html5游戏
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
心理咨询师培训怎么收费标准是多少 2024心理咨询师培训费用是多少钱 心理咨询师培训费用大概是多少 心理咨询师培训课程收费标准 新蒙迪欧空调怎么用? 福特蒙迪欧16款2.0T冷车启动怠速会一抖一抖的是什么情况 牛油果冻了还能吃不 牛油果冻过了能吃吗 泰兴人很有钱吗? 江苏有多少百万人口以上的城市 中国移动的话费能不能在官网买东西啊?全球通的。 男士带南红手链是什么好处? 突然被永久注销了? 被盗,且被注销? 请问被盗并被恶意永久注销怎么找回? 被注销怎么找回来? 被别人注销该怎么办? 开发一个 Flappy Bird 需要多少行代码,多少时间 被别人注销该怎么办? 微信零钱被盗了,也被注销了怎么办 微信被盗,手机号码也被解绑了我的被盗了,然后用短信也不可以说是已经被注销了_百度问一问 我的已经被盗了 并且似乎已经被注销了 那我有没有办法重新找回我的? 被骗子注销了怎么办? 突然被注销了怎么回事 垃圾池子垃圾清运的预算怎样做 学校毕业季垃圾清理计划书? 关于扔垃圾怎么罚,怎么办的计划丫 生姜发出来的嫩芽能吃吗?有没有营养 开发一个Flappy Bird需要多少行代码? 每种花的开放时间是什么?求回答。 怎么优雅的夸别人做的饭好吃 夸你做饭好吃,怎么回? 谈一谈如何优雅地夸奖朋友做的饭好吃? 姑爷做饭挺好吃怎样夸? 怎么夸女同事老公做饭好吃 如果有人夸你第一次第一次做饭好吃,怎么回答? 华为p40pro和苹果11pro和一加7pro那个值得买? 一加手机7游戏载入速度,对比iPhone11Pro Max 使用visual studio写一个Flappy Bird游戏(看问题补充) 全部 欠条 借条 一个手机能上几个? 你不喜欢什么样的人怎么回复 如何回复对你好而你不喜欢的人,尽量不伤害到他? 怎样在同一部手机上用两个微信!怎么才能下载另一个! 肚子好疼啊,还拉稀,想吐也吐不出来,想吐的时候有呕吐的味道,大半夜的,没药,我该怎么办?求救。 半夜肚子疼醒了,拉稀,很疼,疼得都没劲了…… 什么最有营养 为什么 Flappy Bird 游戏这么难玩? 笔记本电脑键盘上面洒上水了,然后用吹风机吹过了,再开机的过程中出现很大的嘟嘟的声音是怎么回事? 笔记本进水后,开机有很大的嘟声