用Html做一个快乐鸟小游戏

入门学习前端的时候做了这么一个简单的小游戏,为了将自己所学到的知识运用起来。

img

做这个小游戏用到了:

  • html
  • css
  • jQuery

然后这个小游戏的图片素材用到了:

img

其实用原生的js也是可以完成的,但是为什么要用jQuery?因为我直接跳过了原生JS的学习…只有等空余的时候,好好的找本书研究一下原生的js。

一、 大致流程

下面是这个小游戏的大致流程:

img

其中鸟和管道应该用面向对象来做,但是我原生JS只学习了最基础的部分,而且JS在ES5的时候还没有类的概念,只能使用构造函数来模拟一个类,在ES6的时候才加入了class这个关键字,但是我知道ES6的时候,已经是在完成这个小游戏之后了。

从上面的素材图片只有4张可以看得出来,html和CSS的搭建是没有太大难度的。所以本文着重讲解JS的部分。

这里值得一说的是,我CSS上面是用的子绝父相的定律,来摆放鸟和管道,其中管道的代码如下所示:

/* 上边的管道 */
.tubeTop { 
 width: 90px;
 height: 420px;
 background: url(/images/bird/ColumnSprite.png) no-repeat 0 0;
 background-size: cover;
 transform: rotate(180deg);
}
/* 下边的管道 */
.tubebotton {
 width: 90px;
 height: 420px;
 background: url(/images/bird/ColumnSprite.png) no-repeat 0 0;
 background-size: cover;
 margin-top: 100px;
}

.tube {
 position: absolute;
 top: 0;
}

可以看得出来,其实上下管道用的是一张图片,只是将它旋转了180度,然后包含在一个div中,这样只要设置父盒子的位置,上下的两根管道的位置就不需要再去设置。

二、 游戏逻辑

模型控制:

其实整个游戏,鸟是没有动的,我是让背景向前移动,这里有一点需要注意背景我并不是拼接了很多张图,而是仅仅用了两张图,一张在可视范围内,一张在可视范围外,当前面的那张移出可视范围的时候,再用JS将它放置到后面那张背景的后面,这样反复,就可以变成一个无限背景。

img

当管道移除可视范围外的时候,我并没有将它进行销毁,而是用JS重新设置它的位置,因为产生和销毁一个物体的时候,是非常的耗费性能的,如果一个物件能够复用,就需要想办法进行复用。

控制管道和背景的代码,管道的位置控制都是通过css设置它们position:

//控制管道
function tubeControl() {
	var tube = $(".tube");
	//背景1
	var bgImg1 = $(".bgImage")
		.css("left")
		.split("p")[0];
	bgImg1 = bgImg1 - 1 + "px";
	$(".bgImage").css("left", bgImg1);
	if (parseInt(bgImg1) < -1490) {
		bgImg1 = 1500 + "px";
		$(".bgImage").css("left", bgImg1);
	}
	//背景2
	var bgImg2 = $(".bgImage2")
		.css("left")
		.split("p")[0];
	bgImg2 = bgImg2 - 1 + "px";
	$(".bgImage2").css("left", bgImg2);
	if (parseInt(bgImg2) < -1490) {
		bgImg2 = 1500 + "px";
		$(".bgImage2").css("left", bgImg2);
	}
	//草
	var Green = $(".bootonGreen")
		.css("left")
		.split("p")[0];
	Green = Green - 1 + "px";
	$(".bootonGreen").css("left", Green);
	if (parseInt(Green) < -1490) {
		Green = 1500 + "px";
		$(".bootonGreen").css("left", Green);
	}
	var Green2 = $(".bootonGreen2")
		.css("left")
		.split("p")[0];
	Green2 = Green2 - 1 + "px";
	$(".bootonGreen2").css("left", Green2);
	if (parseInt(Green2) < -1490) {
		Green2 = 1500 + "px";
		$(".bootonGreen2").css("left", Green2);
	}
	for (var i = 0; i < tube.length; i++) {
		var left = tube
			.eq(i)
			.css("left")
			.split("p")[0];
		if (left < -250) {
			left = 1550 + "px";
			var top = -myRondom(210) + "px";
			tube.eq(i).css("left", left);
			tube.eq(i).css("top", top);
		} else {
			left -= 1;
			tube.eq(i).css("left", left);
		}
	}
}

当管道已经移出可视范围的时候,给它一个随机数重新设置它的位置:

// 随机数
function myRondom(muth) {
	return Math.floor(Math.random() * muth);
}
//Math.random()是随机生成0~1之间的小数
for (var i = 0; i < tube.length; i++) {
	var left = tube
		.eq(i)
		.css("left")
		.split("p")[0];
	if (left < -250) {
		left = 1550 + "px";
		var top = -myRondom(210) + "px";
		tube.eq(i).css("left", left);
		tube.eq(i).css("top", top);
	} else {
		left -= 1;
		tube.eq(i).css("left", left);
	}
}

控制鸟的方式我是一直让它向下走:

function birdDown() {
	var bird = $(".bird")
		.css("top")
		.split("p")[0];
	bird = parseInt(bird) + 1 + "px";
	$(".bird").css("top", bird);
}

然后鸟的动画部分就是让图片来回切换就可以达到动起来的效果,但是开篇的BUG也是在这里产生的,因为这个切换图片设置了延迟,所以在鸟死亡的时候,可能这个图片还没有进行切换:

//让鸟动起来
function birdAnima() {
	var bird = $(".bird");
	setInterval(function() {
		if (window.die) {
			$(".bird").css(
				"background-position",
				"-128px 0px"
			);
			return;
		}
		bird.css("background-position", "-64px 0px");
		setTimeout(function() {
			bird.css(
				"background-position",
				"0px 0px"
			);
		}, 250);
	}, 500);
}

我在怎么判断鸟是否撞到管道然后触发死亡状态的地方卡了一会,最后我是通过鸟的盒子的上下左右的坐标因为他们都是绝对定位,而我给了整个可视窗口相对定位,所以当它们的坐标相同时,它们之间就会重叠,然后和管道的坐标进行一个判断:

//判断鸟的位置
function gameControl() {
	// 地面为bottom 100px
	var birdBottom = $(".bird")
		.css("bottom")
		.split("p")[0];
	if (parseInt(birdBottom) <= 80) {
		death();
	}
	var tube = $(".tube");
	var birdTop = parseInt(
		$(".bird")
			.css("top")
			.split("p")[0]
	);
	var birdLeft = parseInt(
		$(".bird")
			.css("left")
			.split("p")[0]
	);
	for (var i = 0; i < tube.length; i++) {
		var top =
			parseInt(
				tube
					.eq(i)
					.css("top")
					.split("p")[0]
			) + 420;
		var left = parseInt(
			tube
				.eq(i)
				.css("left")
				.split("p")[0]
		);
		if (birdTop < top || birdTop + 34 > top + 100) {
			if (
				birdLeft + 64 > left + 10 &&
				birdLeft < left + 90
			) {
				death();
			}
		}
		if (left < 300) {
			console.log(birdLeft, left + 90);
		}
		if (
			birdLeft > left + 90 &&
			birdLeft < left + 101
		) {
			addScroe();
		}
	}
}

得分的判断也在这个函数中,当小鸟飞过管道的某一位置,就调用addScroe()这个方法

为了保证分数和死亡只有一个,所以我将他们设置为全局变量window.die和window.playScroe,如果撞到地板和管道,就调用death()函数,同时将die设置为true:

//死亡状态
function death() {
	window.die = true;
	$(".gameEnd span").text("您的得分:" + window.playScroe);
	$(".gameEnd").fadeToggle(200);
}

注:声明变量时不加window也是全局变量,但是加上的话更明显,一眼就可以知道它是全局变量。

最后是重新开始函数,将管道背景鸟的位置复位:

//重新开始
function Recovery() {
	window.die = false;
	window.playScroe = 0;
	$("#scroe").text(window.playScroe);
	var tube = $(".tube");
	var wid = 400;
	for (var i = 0; i < tube.length; i++) {
		var left = wid + "px";
		var top = -myRondom(210) + "px";
		tube.eq(i).css("top", top);
		tube.eq(i).css("left", left);
		wid += 300;
	} //背景1
	var bgImg1 = $(".bgImage").css("left", "0px");
	//背景2
	var bgImg2 = $(".bgImage2").css("left", "1500px");
	//草
	var Green = $(".bootonGreen").css("left", "0px");
	var Green2 = $(".bootonGreen2").css("left", "1500px");
	Green2 = Green2 - 1 + "px";
	var bird = $(".bird").css({
		left: "200px",
		top: "400px"
	});
}

整个小游戏大致的思路就是这样了,如果有什么疑问或者有什么错误的地方欢迎在评论指出~


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!