效果展示(视频加载可能有点慢哦~ )
在点击开始游戏之前的设置
1、需要设置背景的移动,
2、小鸟上下的跳跃
3、开始游戏按钮设置思路
点击开始按钮之后的设置
1、小鸟不需要上下跳跃
2、开始游戏这个按钮需要隐藏
3、背景图片的移动速度要加快
4、小鸟要开始加速下降
5、要动态创建柱子
6、柱子要移动
7、点击屏幕之后小鸟要上升
8、小鸟在飞行的过程中要进行碰撞检测
9、小鸟撞到柱子或者上下屏幕界面就结束游戏
结束游戏之后的设置
1、关闭所有定时器
2、显示分数
3、设置再来一局的实现
开始游戏之前的具体思路
1、对于 背景的移动用 JS 定时器实现,将背景图片往左移动
2、小鸟上下的跳跃与开始游戏按钮的设置用 CSS 的 animate 实现,也可选择用定时器,但后面的设置用到的定时器较多,所以从性能的角度能用 CSS 实现的就用CSS
点击开始按钮之后的具体思路
1、小鸟取消需要上下跳跃、隐藏开始游戏按钮 只需将相应的 CSS 属性设置为 none
2、背景图片移动的速度在加快之前要先清理之前的定时器,防止重复设置定时器使页面出现抖动
小鸟要开始加速下降的具体思路
3、小鸟要开始加速下降设置: 设一个全局变量 dropSpeed,让其自增,小鸟的 offsetTop 值加全局变量就会实现加速下降,
小鸟上升的具体思路
点击屏幕之后小鸟要上升需要将这个全局变量设置一个固定值,但注意这个固定值是负值,并且这个点击上升的前提是在游戏进行当中并且点击的不是开始按钮
动态创建柱子的具体思路,
1、注意每次创建的柱子都是成对出现的,即上下两个柱子,所以设置一个数组去装上下两个柱子,下标为 0 的是上面的柱子,下标为 1 的是下面的柱子,我这里设置中间的空隙都是一样的,
2、每对柱子的高度不一样,所以需要用随机数生成高度
3、 每对柱子距离移动的速度以及每次创建距离左边的距离都是一样的,在这个游戏中, 我总共创建了 10 对柱子,每对柱子之间的距离是固定值200,在这里设置一个全局变量 index,让其每次自增 然后 * 200,这样就是每对柱子距离左边的距离 ,其移动的当 index >= 10 ,index 重新设置为 10,
4、当创建完一对柱子之后,就让这对柱子往左移动,因为背景也是移动的,这样从视觉上就是小鸟移动的,其实小鸟是不动的,
柱子移动的具体思路
1、柱子移动时要获取每对柱子的位置,所以在创建完一对柱子之后,就要将这对柱子抛出,就是传实参,所以移动柱子的函数要有两个形参去接受它,
2、当有一对柱子移出屏幕时,就取消移动的定时器,并删除这对元素,同时再创建一对柱子,这对柱子的位置就是 index 设置为10的值 ,然后 * 200 ,这样柱子离左边的距离是最远的,即它的位置在所有的柱子之后
3、当柱子在移动的过程中,小鸟要进行碰撞检测,小鸟的 offsetTop 值小球上边柱子的高度或者 大于上边高度+中间的空隙时,再判断小鸟离柱子的距离是不是 <= 0 && >= 柱子的宽度,如果都满足则结束游戏, 再判断小鸟是不是超出了屏幕的上下距离,若是超出也结束游戏
4、当柱子完全移动到小鸟的左侧之后,就加分,
结束游戏之后的设置
1、关闭所有定时器 clearInterval() 就可以实现
2、显示分数 innerText 实现
3、设置再来一局的实现就相当于是重新刷新页面,用 location.reload() 实现
同时在页面点击的时候,为了防止点击到文字会出现背景选中的情况,所以设置一个监听事件,禁止选中文字
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>会飞的小鸟</title>
<link rel="stylesheet" href="./css/reset.css">
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<div class="container">
<div class="start-game-font">开始游戏</div>
<div class="bird"></div>
<div class="over">
<div class="finish-word">
<div class="get-score"></div>
<div class="again"> 再来一局 </div>
</div>
</div>
<div class="score"><div>得分</div> <div class="show-score">0</div></div>
</div>
<script src="index.js"></script>
<script>
bird.show();
</script>
</body>
</html>
CSS代码 reset.css是一些公共样式,就不上传了
.container{
position: relative;
width: 100%;
height: 600px;
background-image: url('../images/sky.png');
overflow: hidden;
}
/* 字体样式 */
.start-game-font{
position: absolute;
top: 55%;
left: 50%;
transform: translate(-50%,-50%);
padding: 5px;
animation: font .6s ease-in-out infinite;
font-weight: 700;
letter-spacing: 2px;
border: 1px solid gray;
border-radius: 3px;
background-color: gainsboro;
}
.start-game-font:hover{
cursor: pointer;
}
@keyframes font{
0%{
font-size: 18px;
color: blueviolet
}
50%{
font-size: 20px;
color: blueviolet;
}
75%{
font-size: 24px;
color: blue;
}
100%{
font-size: 26px;
color: blue;
}
}
/* 小鸟样式 */
.bird{
position: absolute;
top: 250px;
left: 50%;
transform: translate(-50%,-50%);
background: url('../images/birds.png') no-repeat center ;
background-position-x: -30px;
width: 30px;
height: 30px;
animation: birdJump .9s ease infinite;
}
@keyframes birdJump{
0%{
top: 40%;
}
25%{
top: 45%;
/* background-position-x: -30px; */
}
50%{
top: 40%;
/* background-position-x: -60px; */
}
75%{
top:35%;
}
100%{
top: 40%;
}
}
.over{
position: absolute;
left: 0;
top:0;
z-index: 666;
width: 100%;
height: 600px;
background-color: rgba(0,0, 0,.3);
text-align: center;
vertical-align: middle;
font-size: 30px;
font-weight: 700;
display: none;
}
.finish-word>div{
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
}
.finish-word>div:first-child{
top: 40%;
color: red;
}
.finish-word>div:last-child{
top: 55%;
padding: 5px;
letter-spacing: 3px;
color: yellow;
font-size: 40px;
animation: over .7s ease-in-out infinite;
border: 1px solid gainsboro;
border-radius: 3px;
}
.finish-word>div:last-child:hover{
cursor: pointer;
}
@keyframes over{
0%{
font-size: 40px;
}
25%{
font-size: 50px;
}
50%{
font-size: 60px;
}
75%{
font-size: 50px;
}
100%{
font-size: 40px;
}
}
/* 创建柱子 */
.ctop,.cbottom{
position: absolute;
width: 50px;
background-color: yellow;
}
.ctop{
top: 0;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
.cbottom{
bottom: 0;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
/* 分数 */
.score{
position: absolute;
left: 50%;
top: 0;
z-index: 666;
transform: translate(-50%,0);
display: none;
width: 200px;
height: 40px;
line-height: 40px;
text-align: center;
}
.score>div{
float: left;
font-size: 30px;
font-weight: 700;
color: red;
}
.score>div:first-child{
font-size: 23px;
font-weight: 400;
color: #fff;
margin-right: 10px;
}
JS代码
var bird = {
// 背景移动的步长
skyStep: 3,
// 小鸟下降的速度
dropSpeed: 0,
// 游戏开始之后设置一个锁
flag: false,
// 小鸟下降距离上边的距离
runTop: 0,
// 创建 的柱子
column:[],
// 柱子离左边的距离
left:0,
// 设置索引值记录要创建的柱子以及每对柱子离左边的距离
index:0,
// 小鸟移动时距离上边的距离
maxTop: 0,
// show函数主要将获取的 DOM 元素, animate动画, 监听函数全部封装起来,
// 这样在调用完之后就会释放,省内存空间
show: function(){
this.getDom(); // 获取 DOM 元素
this.animate(); // 动画
this.handle(); // 监听事件
},
// 获取 DOM 元素
getDom: function(){
// 获取页面中最大的容器
this.obgImg = document.querySelector('.container');
// 获取字体
this.ofont = document.querySelector('.start-game-font');
// 获取小鸟
this.obird = document.querySelector('.bird');
// 获取游戏结束元素
this.over = document.querySelector('.over');
// 再来一局
this.oagain = document.querySelector('.again');
// 获取分数
this.oscore = document.querySelector('.score');
// 结束时设置分数
this.oset = document.querySelector('.get-score ');
},
// 动画
animate: function(){
// 天空背景移动
this.skyMove();
// 小鸟飞
this.birdFly();
// 文字动画
},
// 监听事件
handle: function(){
// 点击开始游戏之后, 小鸟不上下跳,也不飞,字体也不会跳动且会从页面中消失,
// 背景速度加快 , 让小鸟加速下下降
this.fontClick();
this.birdUp(); // 小鸟上升
this.stop() // 禁止选中文字
},
// 动画 -- 天空背景移动
skyMove: function(){
// 设置图片的距离左边的位置
var skyPostionX = 0;
this.skyMoveTimer = setInterval(() => {
skyPostionX -= this.skyStep;
this.obgImg.style.backgroundPositionX = skyPostionX + 'px' ;
}, 50);
},
// 动画 -- 小鸟飞
birdFly:function(){
var birdPositionX = 0;
this.birdFlyTimer = setInterval(() => {
this.obird.style.backgroundPositionX = birdPositionX % 3 * -30 + 'px';
birdPositionX++;
}, 300);
},
// 点击开始游戏之后, 小鸟不上下跳,也不飞,所以清除定时器与css中的animate
// 字体也不会跳动且会从页面中消失
fontClick:function(){
// this --> <div class="start-game-font">开始游戏</div>
// var self = this;
this.ofont.addEventListener('click', () => {
this.addClick();
})
},
// 点击开始游戏之后的所有操作
addClick:function(){
clearInterval(this.birdFlyTimer); // 小鸟不飞
clearInterval( this.skyMoveTimer); // 清除当前的背景定时器,重新设置一个更快的定时器
this.obird.style.animation = 'none'; // 小鸟不跳动
this.obird.style.left = 100+'px'; // 小鸟离左边的距离变小
this.ofont.style.display = 'none'; // 字体消失
this.oscore.style.display='block' ; // 分数显示
this.flag = true;
this.addSpeed(); // 背景速度加快,
this.birdDrop(); // 小鸟下降,小鸟下降屏幕检测,柱子检测
if(this.flag){ // 创建 柱子
for(var i = 0; i < 10; i++){
this.createColumn(); // 创建柱子
}
}
},
// 背景速度加快
addSpeed:function(){
this.skyStep = 6;
this.skyMove();
},
// 小鸟下降屏幕检测
birdDrop:function(){
// 小鸟上下可以移动的最大距离
this.maxTop = this.obgImg.offsetHeight;
// 获
// 获取当前小鸟距离上边的距离
this.birdDropTimer = setInterval(() => {
// 小鸟在下降的时候会点击屏幕上升,这时也要做判断
this.dropSpeed++;
this.runTop = this.obird.offsetTop + this.dropSpeed ;
// 每500毫秒就获取当前小鸟距离上边的距离,如果超过了最大的距离,则结束游戏 否则就下降自增
if(this.runTop >= this.maxTop || this.runTop <= 0 ){
this.gameOver();
}
this.obird.style.top = this.runTop + 'px';
}, 50);
},
// 小鸟上升
birdUp : function(){
document.addEventListener('click', (e) => {
// 游戏未进行,或者当前点击的开始游戏按钮
if(!this.flag || e.target.classList.contains('start-game-font') )
return;
this.dropSpeed = -10;
})
},
// 创建柱子
createColumn:function(){
this.column[0] = document.createElement('div');
this.column[1] = document.createElement('div');
var maxh = 250;
var minh = 50;
var height = Math.floor(Math.random() * (maxh - minh + 1)) + minh;
this.column[0].className = "ctop";
this.column[1].className = "cbottom";
++this.index;
if(this.index >= 10)
this.index = 10; // 页面删除一个柱子后,再添加一个柱子时放的位始终是1000
this.left = this.index * 200 + 'px';
this.column[0].style.left= this.left;
this.column[1].style.left = this.left;
this.column[0].style.height = height + 'px';
this.column[1].style.height = 450 - height + 'px';
this.obgImg.appendChild(this.column[0]);
this.obgImg.appendChild(this.column[1]);
this.columnMove(this.column[0], this.column[1],height); // 移动柱子
},
// 移动柱子
columnMove:function(obj1, obj2,height){
var left
obj1.columnMoveTimer = setInterval(() => {
left = obj1.offsetLeft;
// 当移动屏幕外面时,删除元素和定时器,同时再创建一个柱子,保证页面始终有5个柱子
if(left < -obj1.offsetWidth){
this.obgImg.removeChild(obj1);
this.obgImg.removeChild(obj2);
clearInterval(obj1.columnMoveTimer);
this.createColumn();
}
// 当小鸟碰到上下屏幕时,结束游戏,停止移动柱子
if(!this.flag)
clearInterval(obj1.columnMoveTimer);
// 当小鸟遇到柱子时,结束游戏
let result = left - this.obird.offsetLeft;
if(this.runTop <= height|| this.runTop >= height+150){
if(result <= 0 && result >= -60){
clearInterval(obj1.columnMoveTimer)
this.gameOver();
}
}
left -= 10;
// 显示分数
if(left - this.obird.offsetLeft == -this.obird.offsetWidth){
this.oscore.children[1].innerText =parseInt(this.oscore.children[1].innerText)+ 10;
}
obj1.style.left = left + 'px';
obj2.style.left = left + 'px';
}, 50);
},
// 禁止选中文字
stop:function(){
document.addEventListener('selectstart',(e) =>{
e.preventDefault();
})
},
// 结束游戏
gameOver:function(){
clearInterval(this.skyMoveTimer); // 清空天空移动定时器
clearInterval(this.birdDropTimer); // 清空小鸟下降定时器
this.flag = false; // 游戏结束之后flag 设置为false;
this.oscore.style.display = 'none'; // 分数隐藏
this.over.style.display = 'block'; // 显示游戏界面
this.oset.innerText = "总共得分: " + parseInt(this.oscore.children[1].innerText) ;
this.oagain.addEventListener('click', () =>{
this.over.style.display = 'none';
this.gameAgain();
})
},
// 再来一局
gameAgain:function(){
location.reload();
}
}