1. 思路

  • 漏点判断:当div元素下有6个行元素时,对最后一行的元素进行判断,如果仍有元素具有target属性,则判断有漏点,游戏结束,显示最终成绩,终止动画定时函数,终止提速定时函数。
  • 点击判断:点击的元素若没有target属性,则游戏结束;有则成绩+1
  • 动画实现:使用定时函数,来修改位置参数。

在线观看

2. 代码

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<head>
<meta http-equiv="Content-Type"content="text/html; charset=utf-8">
<link rel="stylesheet" href="style.css" type="text/css">
</head>
<body>
<div class="score"></div>
<div class="wrapper">
<div class="title">Game Start</div>
<div class="author">作者:沈世磊</div>
<div class="main"></div>
</div>
</body>
<script src="jquery.js"></script>
<script src="doNotStepOnWhiteBlocks.js"></script>
</html>

CSS

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
.wrapper {
width: 400px;
height: 600px;
margin: 200px auto;
border-style: solid;
border-width: 2px;
position: relative;
overflow: hidden;
}

.main {
width: 400px;
height: 600px;
position: absolute;
top: -150px;
display: none;
}

.title {
font-family: Arial;
font-size: 50px;
font-weight: bold;
color: lightseagreen;
border-bottom-style: dashed;
border-bottom-width: 4px;
border-color: lightblue;
padding: 20px;
text-align: center;
cursor: pointer;
}

.author {
text-align: center;
font-size: 30px;
font-weight: bold;
padding-top: 200px;
}

.row {
border-bottom-width: 1px;
border-bottom-style: solid;
border-bottom-color: black;
height: 149px;
}

.col, .target {
border-right-width: 1px;
border-right-style: solid;
border-right-color: black;
height: 149px;
width: 99px;
float: left;
}

.score {
font-size: 30px;
color: darkorange;
position: absolute;
left: 1000px;
top: 400px;
display: none;
font-family: SimSum, "宋体";
}

JQuery

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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
function Step() {
this.score = 0;
this.lastScore = 0;
this.speed = 2;
// 是否重新开始
this.start = false;
// Dom元素
this.dom = {
title: $(".title"),
author: $(".author"),
main: $(".main"),
score: $(".score")
};
// 整个别踩白块动作交互
this.bindEvent();
// 动画定时函数
this.timer1 = {};
// 加速定时函数
this.timer2 = {};
// 显示分数
this.timer3 = {};
}

/**
* bindEvent() 绑定事件
* @function name: bindEvent
* @param none
* @return none
*/
Step.prototype.bindEvent = function () {
var self = this;
var topValue = -150;
self.dom.title.on("click", function () {
// 隐藏标题和作者信息
self.dom.title.css("display", "none");
self.dom.author.css("display", "none");
// 显示分数信息
self.dom.score.css("display", "block");
// 创建第一行钢琴块
self.createBlock(0);
// 创建动画定时函数
self.timer1 = setInterval(function () {
// 检验是否有漏点
var main = self.dom.main;
if (main.children().length == 6) {
for (var i = 0; i < 4; i++) {
if (main.children().eq(5).children().eq(i).attr("class") == "target") {
self.start = confirm("最终得分:" + self.score + "\n是否重新开始?");
clearInterval(self.timer1);
clearInterval(self.timer2);
clearInterval(self.timer3);
self.startOrNot();
return;
}
}
main.children().eq(5).remove();
}
// 通过修改main的位置实现动画效果
var main = self.dom.main;
topValue += self.speed;
if (parseInt(main.css("top")) > 0) {
topValue = -150;
self.createBlock(1);
}
main.css("top", topValue+"px");
}, 10);
// 创建速度定时函数 得分是10的倍数,速度增加
self.timer2 = setInterval(function () {
var diffScore = self.score - self.lastScore;
if (10 == diffScore) {
self.speed++;
self.lastScore = self.score;
}
}, 100);
// 显示分数
self.timer3 = setInterval(function () {
self.dom.score.text("");
self.dom.score.append("当前分数:" + self.score);
}, 10);
});
}

/**
* createBlock() 创建钢琴块
* @function name: createBlock()
* @param flag flag=0 说明创建第一行钢琴块;flag=1 说明在后面添加钢琴块
* @return none
*/
Step.prototype.createBlock = function (flag) {
var self = this;
var main = self.dom.main;
var row = $('<div class="row"></div>');
if (0 == flag) {
main.append(row);
main.css("display", "block");
}
if (1 == flag) {
main.prepend(row);
}
// 生成四个钢琴块
for (var i = 0; i < 4; i++) {
var col = $('<div class="col"></div>');
row.append(col);
// 对钢琴块进行点击判定
col.on("click", function () {
if ($(this).attr("class") == "target") {
// 点击了正确的钢琴块
$(this).css("background-color", "lightgray").attr("class", "col");
self.score++;
return;
}
// 未点击正确的钢琴块
self.start = confirm("最终得分:" + self.score + "\n是否重新开始?");
clearInterval(self.timer1);
clearInterval(self.timer2);
clearInterval(self.timer3);
self.startOrNot();
});
}
// 生成随机数字标记钢琴块
var index = parseInt(Math.random() * 4);
row.children().eq(index).css("background-color", "black").attr("class", "target");
}

Step.prototype.startOrNot = function () {
if (this.start) {
window.location.reload();
// 刷新结束置为false
this.start = false;
}
}

new Step();

3. 遇到的问题

  • 将鼠标移到Game Start上,鼠标指针变为手型,提醒用户点击,需要将元素对应的CSS格式中添加cursor: pointer;
  • 这里设置的wrapper标签高度为600px,宽度为400px,但每个钢琴块的长度和宽度需要设置为149px和99px,若是150px和100px。则一行将填不下四个钢琴块。(因为边框也有宽度😺)
  • 使用浮动float生成并列的钢琴块
  • var col = $('<div class="col"></div>');不能定义在循环外,否则只添加一个钢琴块。
  • 对每个钢琴块进行点击判断时,this是当前点击的对象,$(this)将其转换为jquery对象,获得其属性。
  • 使用overflow: hidden对超出范围的元素进行隐藏,由于钢琴块的CSS格式中有position: absolute;,导致其定位的position变成了整个视窗,内容将不会被裁剪,这时需要在wrapper中添加position: relative;
  • 相对定位元素经常被用来作为绝对定位元素的容器块,养成这种习惯避免遇到上个问题👀

4. 参考