放假闲来无事,一群小屁孩想玩我的电脑。
字都不会打,还玩电脑。
用 js 写一个打字游戏,打不到 100 分,就不要玩我的电脑~~~!!!
整体界面如下所示,一切从简~
HTML 结构
-
<div id="box" class="box">
-
<div class="tips">
-
击中数量:
<span id="scoreSpan" style="margin-right: 20px;">0
</span>
-
失误:
<span id="missSpan">0
</span>
-
</div>
-
<div class="container" id="container">
-
-
</div>
-
<!-- 游戏结束标签 -->
-
<div class="gameover">
-
<h1>游戏结束
</h1>
-
<div class="overBtn">
-
<button type="button" id="btn">重新开始
</button>
-
</div>
-
</div>
-
</div>
div.container 是字母出现的区域,相对定位。
字母是 JS 动态生成的 span 标签,全部绝对定位。
div.gameover 是游戏结束时的画面,默认是隐藏的。当游戏结束的时候,给 div.box 添加一个类 over,才让 div.gameover 显示出来。
具体样式见下 CSS 样式部分。
CSS 样式
-
*{
-
margin:
0;
-
padding:
0;
-
}
-
div
.box{
-
width:
100vw;
-
height:
100vh;
-
position: relative;
-
background:center center
url(
"../images/mm.jpg") no-repeat;
-
background-size: cover;
-
}
-
.tips{
-
position: absolute;
-
left:
20px;
-
top:
20px;
-
font-size:
20px;
-
line-height:
40px;
-
z-index:
2;
-
}
-
.tips
span{
-
font-size:
30px;
-
color:
#ff6600;
-
vertical-align: middle;
-
}
-
.container{
-
width:
100%;
-
height:
100vh;
-
position: relative;
-
overflow: hidden;
-
background:
rgba(
255,
255,
255,
0.5);
-
}
-
.container
span
.zm{
-
font-size:
40px;
-
display: inline-block;
-
padding:
5px
10px;
-
height:
80px;
-
line-height:
80px;
-
overflow: hidden;
-
position: absolute;
-
}
-
span
.zm
.shoot{
-
animation: shootAni
0.2s;
-
}
-
@keyframes shootAni {
-
0%{
-
opacity:
1;
-
transform:
scale(
1);
-
}
-
100%{
-
opacity:
0;
-
transform:
scale(
1.5);
-
}
-
}
-
.gameover{
-
position: absolute;
-
left:
0;
-
top:
0;
-
background:
rgba(
0,
0,
0,
0.5);
-
bottom:
0;
-
right:
0;
-
text-align: center;
-
display: none;
-
}
-
.over
.gameover{
-
display: block;
-
}
-
.over
.gameover
h1{
-
padding-top:
40vh;
-
margin-bottom:
40px;
-
}
-
.over
.gameover
button{
-
cursor: pointer;
-
width:
100px;
-
height:
50px;
-
}
-
-
</style>
JavaScript 部分
字母是 26 个字母随机出现,因此利用一个字符串存储字母。
let zmStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
字母是随机生成的 span,span的内容就是随机字母。但是,字母不能跟已有的字母重复,因此要做一个重复性的判断。
判断的方式:先把已有的字母收集起来,形成一个字符串。随机字母的时候,就判断是否已经存在。如果存在,就重新随机选取字母。如果不存在,ok,就把这个字母放入span 中。
-
// 随机生成字母
-
let zmInStr =
"";
// 已有的字母
-
for(
let i=
0; i<=container.
children.
length-
1; i++){
-
zmInStr += container.
children[i].
innerText ;
-
}
-
let zmNow = zmStr[
Math.
floor(
Math.
random()*zmStr.
length) ];
-
// 防止字母重复
-
while( zmInStr.
indexOf(zmNow) >=
0){
-
zmNow = zmStr[
Math.
floor(
Math.
random()*zmStr.
length) ]
-
}
-
span.
innerText = zmNow;
每个生成的字母,也就是 span,它的位置,速度都是随机的。
-
span.
style.
fontSize = (
Math.
random()*
50+
30)+
"px";
-
span.
style.
color = fontColorArr[
Math.
floor(fontColorArr.
length*
Math.
random())];
-
// 字母出现的位置
-
span.
style.
left = (
80+
Math.
random()*(container.
offsetWidth-
160)) +
"px";
-
span.
style.
top =
`${60}px` ;
-
// 每个字母设置下落速度
-
span.
speed = spDi+
Math.
random()*spCtr;
-
// 每个字母的下落距离
-
span.
dis =
0;
当字母被击中,会执行一个 animation 动画。动画结束后,该字母span标签要被删除。所以,字母的span标签需要监听 animationend 事件。
-
// 添加动画事件
-
span.
addEventListener(
"animationend",
function (
) {
-
// 当 animation 动画结束后,移除该字母
-
container.
removeChild(span);
-
});
下坠动画部分。
利用的是 requestAnimationFrame ,每次执行动画先遍历所有字母 span。
获取每个 span 的速度 speed 和 移动的距离 dis。在当前 dis 上添加 speed 值,实现位置变化。
-
// 获取每个span的速度和位置
-
let speed =
Number(span.
speed);
-
let dis =
Number(span.
dis);
-
span.
style.
top =
`${dis+speed}px`;
-
span.
dis =
`${dis+speed}`;
还要判断字母是否移动到了屏幕之外,这个时候说明字母没有被击中。要添加失误分。
-
// 判断字母是否在外面。
-
if(
Number(span.
dis) >
Number(container.
offsetHeight)+
10){
-
container.
removeChild(span);
-
createSpan();
-
missScore++;
-
missSpan.
innerText = missScore;
-
}
当失误分超过10分的时候,游戏结束。
-
// 判断游戏是否结束:失误超过10次
-
if(missScore>=
10){
-
cancelAnimationFrame(req);
-
box.
classList.
add(
"over");
-
return ;
-
}
当用户击打键盘的时候,要判断按下的键是否在已有的字母中。
因此,要遍历字母 span 标签,判断按键是否跟其中的一个一致。
有,则这个字母被击中,添加击中动画 shoot,速度归零,再创建一个新的字母补位。得分+1 。
-
// 添加事件
-
document.
addEventListener(
"keyup",
function (
e) {
-
console.
info( e.
code );
-
let spans = container.
getElementsByTagName(
"span");
-
// 判断按键
-
for(
let i=
0; i<spans.
length ; i++){
-
// 击中了字母:按下了正确的字母键
-
if(
"Key"+spans[i].
innerText == e.
code ){
-
spans[i].
classList.
add(
"shoot");
// 击中字母
-
spans[i].
speed =
0;
// 被击中的字母不再移动
-
createSpan();
// 再生成一个字母
-
// 得分
-
score++;
-
scoreSpan.
innerText = score ;
-
break;
-
}
-
}
-
});
完整 JavaScript 代码如下:
-
let box =
document.
getElementById(
"box");
-
let container =
document.
getElementById(
"container");
-
let missSpan =
document.
getElementById(
"missSpan");
-
let scoreSpan =
document.
getElementById(
"scoreSpan");
-
let btn =
document.
getElementById(
"btn");
-
let numZM =
5;
-
let score =
0 ;
// 得分
-
let missScore =
0;
// 失误
-
let zmStr =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
let spCtr =
1;
// 速度控制变量
-
let spDi =
0.5;
-
let req ;
// 动画id
-
let fontColorArr = [
"#ba300c",
"#057a7d",
"#b724c7",
"#8cc111"];
-
// 创造一个字母
-
function
createSpan(
){
-
let span =
document.
createElement(
"span");
-
span.
className =
"zm";
-
// 随机生成字母
-
let zmInStr =
"";
// 已有的字母
-
for(
let i=
0; i<=container.
children.
length-
1; i++){
-
zmInStr += container.
children[i].
innerText ;
-
}
-
let zmNow = zmStr[
Math.
floor(
Math.
random()*zmStr.
length) ];
-
// 防止字母重复
-
while( zmInStr.
indexOf(zmNow) >=
0){
-
zmNow = zmStr[
Math.
floor(
Math.
random()*zmStr.
length) ]
-
}
-
span.
innerText = zmNow;
-
container.
appendChild(span);
-
span.
style.
fontSize = (
Math.
random()*
50+
30)+
"px";
-
span.
style.
color = fontColorArr[
Math.
floor(fontColorArr.
length*
Math.
random())];
-
// 字母出现的位置
-
span.
style.
left = (
80+
Math.
random()*(container.
offsetWidth-
160)) +
"px";
-
span.
style.
top =
`${60}px` ;
-
// 每个字母设置下落速度
-
span.
speed = spDi+
Math.
random()*spCtr;
-
// 每个字母的下落距离
-
span.
dis =
0;
-
// 添加动画事件
-
span.
addEventListener(
"animationend",
function (
) {
-
// 当 animation 动画结束后,移除该字母
-
container.
removeChild(span);
-
});
-
}
-
// 移动函数
-
function
move(
){
-
let spans = container.
children;
-
for(
let i=
0; i<spans.
length; i++){
-
let span = spans[i];
-
// 获取每个span的速度和位置
-
let speed =
Number(span.
speed);
-
let dis =
Number(span.
dis);
-
span.
style.
top =
`${dis+speed}px`;
-
span.
dis =
`${dis+speed}`;
-
// 判断字母是否在外面。
-
if(
Number(span.
dis) >
Number(container.
offsetHeight)+
10){
-
container.
removeChild(span);
-
createSpan();
-
missScore++;
-
missSpan.
innerText = missScore;
-
}
-
}
-
// 判断游戏是否结束:失误超过10次
-
if(missScore>=
10){
-
cancelAnimationFrame(req);
-
box.
classList.
add(
"over");
-
return ;
-
}
-
// 动画循环
-
req =
requestAnimationFrame(move);
-
}
-
-
// 初始化
-
function
initGame(
){
-
container.
innerHTML =
"";
-
score =
0;
-
scoreSpan.
innerText = score ;
-
missScore =
0;
-
missSpan.
innerText = missScore;
-
box.
classList.
remove(
"over");
-
// 初始生成字母
-
for(
let i=
0; i<numZM; i++){
-
createSpan()
-
}
-
move();
-
}
-
-
// 添加事件
-
document.
addEventListener(
"keyup",
function (
e) {
-
console.
info( e.
code );
-
let spans = container.
getElementsByTagName(
"span");
-
// 判断按键
-
for(
let i=
0; i<spans.
length ; i++){
-
// 击中了字母:按下了正确的字母键
-
if(
"Key"+spans[i].
innerText == e.
code ){
-
spans[i].
classList.
add(
"shoot");
// 击中字母
-
spans[i].
speed =
0;
// 被击中的字母不再移动
-
createSpan();
// 再生成一个字母
-
// 得分
-
score++;
-
scoreSpan.
innerText = score ;
-
break;
-
}
-
}
-
});
-
// 重新开始游戏:
-
btn.
addEventListener(
"click",
function(
){
-
initGame()
-
});
-
// 启动游戏
-
initGame();
转载:https://blog.csdn.net/weixin_42703239/article/details/128777424