飞鸟-2

JavaScript 是前端核心, 掌握这门语言是步入前端高手行列必经之路,噢,别忘了还有TypeScript, 学习它还需要OOP知识, 底层的浏览器原理、HTTP协议也必不可少, 此系列文章记录使用JavaScript和Canvas进行游戏开发, 有游戏才有趣!!!

飞鸟游戏

  • 技术要点
    • 获取dom元素
    • 获取和设置CSS中可计算样式(变量)
    • ES6 => 函数
    • window.requestAnimationFrame
  • 最终效果如下图

一、上一节中完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小鸟向前冲</title>

<style>
*, *::before, *::after {
box-sizing: border-box;
user-select: none;
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.city {
overflow: hidden;
position: relative;
width: 100vw;
height: 100vh;
}
.score {
position: absolute;
font-size: 3vmin;
right: 1vmin;
top: 1vmin;
z-index: 999;
}

.start-control {
position: absolute;
font-size: 5vmin;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 999;

}
.hide {
display: none;
}
.bg_ground {
--left: 0;
position: absolute;
width: 100%;
height: 100vh;
bottom: 0;
left: calc(var(--left) * 1%);
}

.bird {
--bottom: 10;
position: absolute;
left: 1%;
height: 10%;
bottom: calc(var(--bottom) * 1%);
}

</style>



</head>
<body>
<div class="city" id="city">
<div class="score">得分:<span>0</span></div>
<div class="start-control">按任意键继续</div>
<img src="imgs/full-background.png" class="bg_ground" >
<img src="imgs/full-background.png" class="bg_ground" >
<img src="imgs/frame-1.png" class="bird">
</div>
</body>

<script>


</script>
</html>

二、定义通用函数,用于对CSS中的可变属性进行获取和设置

  • 几个重要的API
    • window.parseFloat 转换为浮点数字
    • window.getComputedStyle 获取计算样式
    • setProperty 设置属性值
    • getPropertyValue 获取属性值
  • 定义设置属性值函数,获取属性值函数,更新属性值函数
    • setProperty(属性名,属性值)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//设置属性函数,定义了三个参数,元素对象elem,属性名称prop和属性值value
function setElementProperty(elemObj, prop, value) {
//使用DOM元素的style的setProperty方法设置属性值
elemObj.style.setProperty(prop, value)
}
//获取元素对应的属性值, 参数为元素对象elem和属性名称prop
function getElementProperty(elemObj, prop) {
//使用getComputedStyle方法获取元素的样式对象,再通过getPropertyValue(属性名)获取值
//如果无法获取值则返回 0
//parseFloat将获取的值转换为浮点数
return parseFloat(getComputedStyle(elemObj).getPropertyValue(prop)) || 0
}

//增加元素的可变样式值, 调用的就是上面定义的两个方法
function incrementElementProperty(elemObj, prop, incVal) {
setElementProperty(elemObj, prop, getElementProperty(elemObj, prop) + incVal)
}

三、初始化背景属性的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小鸟向前冲</title>

<style>
*, *::before, *::after {
box-sizing: border-box;
user-select: none;
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.city {
overflow: hidden;
position: relative;
width: 100vw;
height: 100vh;
}
.score {
position: absolute;
font-size: 3vmin;
right: 1vmin;
top: 1vmin;
z-index: 999;
}

.start-control {
position: absolute;
font-size: 5vmin;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 999;

}
.hide {
display: none;
}
.bg_ground {
--left: 0;
position: absolute;
width: 100%;
height: 100vh;
bottom: 0;
left: calc(var(--left) * 1%);
}

.bird {
--bottom: 10;
position: absolute;
left: 1%;
height: 10%;
bottom: calc(var(--bottom) * 1%);
}

</style>



</head>
<body>
<div class="city" id="city">
<div class="score">得分:<span>0</span></div>
<div class="start-control">按任意键继续</div>
<img src="imgs/full-background.png" class="bg_ground" >
<img src="imgs/full-background.png" class="bg_ground" >
<img src="imgs/frame-1.png" class="bird">
</div>
</body>

<script>
//设置属性函数,定义了三个参数,元素对象elem,属性名称prop和属性值value
function setElementProperty(elemObj, prop, value) {
//使用DOM元素的style的setProperty方法设置属性值
elemObj.style.setProperty(prop, value)
}
//获取元素对应的属性值, 参数为元素对象elem和属性名称prop
function getElementProperty(elemObj, prop) {
//使用getComputedStyle方法获取元素的样式对象,再通过getPropertyValue(属性名)获取值
//如果无法获取值则返回 0
//parseFloat将获取的值转换为浮点数
return parseFloat(getComputedStyle(elemObj).getPropertyValue(prop)) || 0
}
//增加元素的可变样式值, 调用的就是上面定义的两个方法
function incrementElementProperty(elemObj, prop, incVal) {
setElementProperty(elemObj, prop, getElementProperty(elemObj, prop) + incVal)
}

//获取所有背景图片元素
const bgGroundElements = document.querySelectorAll(".bg_ground")
//设置背景图片元素的css变量 --left的值
function setupBgGround() {
//第一张背景图片left位置设置为0
setElementProperty(bgGroundElements[0], "--left", 0)
//第二张背景图片left位置设置为100
setElementProperty(bgGroundElements[1], "--left", 100)
}
</script>
</html>

四、定义游戏场景,同时使用动画帧函数更新背景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//常量,整个div.city的宽高
const CITY_WIDTH = 100
const CITY_HEIGHT = 30

const cityElement = document.querySelector('#city')
//设置图片的位置
setupBgGround()

//上一个动画帧的执行时间
let lastTime

function update(time) {
//第一次执行时lastTime为null
if(lastTime == null) {
lastTime = time
window.requestAnimationFrame(update)
return
}
//两次动画帧之间的时间间隔
const interval = time - lastTime

//调用地面更新, 也就是地面不断向左移动
updateBgGround(interval)

//重新设置lastTime时间为当前时间
lastTime = time
window.requestAnimationFrame(update)
}

window.requestAnimationFrame(update)

五、updateBgGround关键函数实现

  • 传入的是时间间隔
  • 遍历背景图片,不断减少left的值,当left的值小于-100时, 增加图片的left值为200
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//定义一个速度常量,用于控制速度, 值越大,速度越快
const SPEED = 0.03


function updateBgGround(interval) {
//遍历所有背景图片
bgGroundElements.forEach(bgGround => {
incrementElementProperty(bgGround, "--left", interval * SPEED * -1)

if (getElementProperty(bgGround, "--left") <= -100) {
//两张图片,每张100, 需要增加到200
incrementElementProperty(bgGround, "--left", 198)
}
})
}

文章开头的图片为最终效果, 下一节我们来实现键盘事件,让这只鸟能上下移动