课程实验要求,迫不得已看了一点javascript,实现这个类似“节奏大师”的小游戏,有计时,计分,对玩家成绩进行排序的小功能,感觉自己审美还是不行,还有感觉自己写的javascript好丑陋,没有数据结构的味道。
遇到卡壳的问题:javascript选择伪元素::after,代码中我用::after表示QWER四个键,js无法选择到伪元素,通过设置如下css代码,然后var crack = document.getElementsByClassName(‘crack’)[0]; 之后crack就是伪元素.crack::after。
.crack {
pointer-events: none;
}
/*伪元素样式*/
.crack::after {
pointer-events: auto;
}
用到javascript知识:Dom,键盘事件,定时器等等=.=
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Gametitle>
<link rel="stylesheet" href="src/css/play.css">
head>
<body>
<div id="game-box">
<div class="game-name">
<span>游戏名: <span style="color: red;">节奏大师简化版span>span>   
<span>游戏时间:<span class="time">span>span>   
<span>积分:<span class="sorce">0span>span>   
<button onclick="gameTime()">开始游戏button>
div>
<div class="crack-box">
<div class="crack">div>
<div class="crack">div>
<div class="crack">div>
<div class="crack">div>
div>
<div class="prefect">prefect~<br>OvO<br>积分+2div>
<div class="good">good~<br>OvO<br>积分+1div>
<div class="miss">miss~<br>OvO<br>积分+0div>
div>
<div id="rank-rule">
<div class="rankbox">
<div class="rank-list">
<table class="rank-table">
<caption>游戏积分表Top5caption>
<tr>
<th>玩家名th>
<th>游戏积分th>
tr>
table>
div>
div>
<div class="rulebox">
<div style="color: red;font-size: 30px;">游戏规则div>
<div style="color: white;font-size: 20px;">玩家通过点击“开始游戏”按钮进行游戏,通过键盘的按键QWER进行操作.<br>当小方块滑落到轨道末尾,点击对应按键,根据按键时机获取不同的分数.<br>
游戏时间20s,在这时间内随机出现小方块.<br>系统会对玩家成绩进行排序,筛选top5的进行展示~
div>
div>
div>
<script src="/src/js/play.js">script>
body>
html>
* {
margin: 0;
padding: 0;
}
body {
background-image: url(../img/last.jpg);
background-repeat: no-repeat;
background-size: 100%;
background-attachment: fixed;
}
#game-box {
position: absolute;
left: 0;
top: 0;
width: 50%;
height: 100vh;
border: 2px solid black;
overflow: hidden;
/*因为设置为绝对定位,后面设置子元素的高度大小100%会溢出,使得子元素超出的部分隐藏*/
}
#rank-rule {
position: absolute;
right: 0;
top: 0;
width: 50%;
height: 100vh;
}
.game-name {
text-align: center;
margin-top: 20px;
color: aliceblue;
font-size: larger;
font-weight: 800;
}
/* 四个轨道的区域 */
.crack-box {
width: 100%;
height: 100%;
/* border: 1px solid white; */
display: flex;
margin: 0 auto;
margin-top: 10px;
margin-bottom: 10px;
width: 80%;
height: 90%;
background-color: rgba(2, 8, 37, 0.3);
position: relative;
}
/* 轨道 */
.crack-box div {
position: relative;
width: 25%;
height: 100%;
border: 1px solid rgba(0, 0, 0, 0.347);
cursor: pointer;
}
/* 滑落的方块样式 */
.crack-box .crack div {
position: absolute;
/* 设置脱离文档流,这样生成的小方块不会互相干扰 */
width: 100%;
height: 10%;
background-color: aliceblue;
border-radius: 10%;
}
/* 作为轨道的按钮 */
.crack:nth-child(1)::after {
content: "Q";
}
.crack:nth-child(2)::after {
content: "W";
}
.crack:nth-child(3)::after {
content: "E";
}
.crack:nth-child(4)::after {
content: "R";
}
.crack {
pointer-events: none;
/* 这样才能使用js选择.crack::after */
}
/*伪元素样式*/
.crack::after {
pointer-events: auto;
/* 这样才能使用js选择.crack::after */
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: 0;
width: 100%;
height: 10%;
box-shadow: -5px -5px 10px rgba(138, 177, 167, 0.496);
background-color: rgba(187, 186, 186, 0.476);
cursor: pointer;
font-size: 30px;
font-weight: 900;
color: rgba(245, 11, 11, 0.625);
}
/* 伪元素点击时的属性 */
.onclick::after {
content: "";
background-color: red;
color: black;
}
.prefect {
position: absolute;
margin: 0 auto;
width: auto;
height: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/*调节位置,使得居中*/
text-align: center;
font-size: 2rem;
font-weight: 900;
font-family: fantasy;
color: rgba(247, 31, 31, 0.7);
background-color: rgba(136, 233, 127, 0);
z-index: 99;
display: none;
}
.good {
position: absolute;
margin: 0 auto;
width: auto;
height: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/*调节位置,使得居中*/
text-align: center;
font-size: 2rem;
font-weight: 900;
font-family: fantasy;
color: rgba(38, 18, 212, 0.676);
background-color: rgba(136, 233, 127, 0);
z-index: 99;
display: none;
}
.miss {
position: absolute;
margin: 0 auto;
width: auto;
height: auto;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/*调节位置,使得居中*/
text-align: center;
font-size: 2rem;
font-weight: 900;
font-family: fantasy;
color: rgba(240, 225, 23, 0.598);
background-color: rgba(136, 233, 127, 0);
z-index: 99;
display: none;
}
/* //开始游戏按钮样式 */
button {
border-radius: 10px;
text-shadow: 0px 1px 0px #2f6627;
box-shadow: 0px 0px 0px 2px #9fb4f2;
font-family: Arial;
color: #ffffff;
/* font-size: 10px; */
background: #44c76776;
padding: 12px 30px 12px 30px;
border: solid #18ab29 1px;
text-decoration: none;
}
button:hover {
color: #ffffff;
background: #e92311af;
text-decoration: none;
}
.rank-list{
color: white;
font-size: 20px;
height: 60%;
width: 100%;
/* border: 2px solid red; */
position: absolute;
top: 5px;
right: 0;
}
/* rank表样式 */
.rank-list table caption{
font-size: 40px;
color: red;
}
.rank-list table{
width: 100%;
/* height: 200px; 如果指定了这个高度,td行就会根据这个高度进行分布,到时候删除行的时候就会很丑*/
border-top: 1px solid rgba(255, 255, 255, 0.5);
/* border-left: 1px solid rgba(255, 255, 255, 0.5); */
text-align: center;
vertical-align: center;
table-layout: fixed;
}
.rank-list table th{
border-right: 1px solid rgba(255, 255, 255, 0.5);
border-bottom: 1px solid rgba(255, 255, 255, 0.5);
padding: 8px;
}
.rank-list table td{
padding: 8px;
border-right: 1px solid rgba(255, 255, 255, 0.5);
border-bottom: 1px solid rgba(255, 255, 255, 0.5);
}
.rulebox{
position: relative;
right: 0;
top: 70%;
text-align: center;
}
/**问题:
*设置高度宽度为百分号时,是根据第一个position不是static的父元素的大小进行设置的
*设置伪元素的伪类效果:p:hover::after,跟正常的思维相反。。
*但是p:focus::after就不启作用,由于js不能选取到伪元素,所以设置如下属性,这样选取到.crack,其实是选中了.crack::after
.crack{
pointer-events: none;
}
.crack::after{
pointer-events: auto;
}
*/
var socre = 0; //分数
var num = 1; //玩家编号
var items = new Array(); //玩家积分数组
// 随机在四个轨道内生成小方块
function CreateBlock() {
var crackNumber = Math.floor(Math.random() * 4); //轨道编号
var blockNum = Math.floor(Math.random() * 3 + 1); //轨道滑落方块数量,1~3块
var fatherBox = document.getElementsByClassName("crack")[crackNumber]; //找到父级元素
for (var i = 0; i < blockNum; i++) {
var block = document.createElement('div');
fatherBox.appendChild(block);
block.timer = null;
//获取轨道的长度
var target = fatherBox.offsetHeight
startMove(block, target);
}
}
// 小方块向下滑落,然后消失
function startMove(obj, target) {
clearInterval(obj.timer); //清除计时器
var y = 1;
var top = 0;
obj.timer = setInterval(function () {
if (top < target - obj.offsetHeight) {
top += y; //每次滑落1px
obj.style.top = top + "px";
} else {
obj.remove();
clearInterval(obj.timer); //清除计时器
}
}, 10);
}
// QWER健按下事件
document.onkeydown = function (event) {
if (event.keyCode == 81) {
var crack = document.getElementsByClassName('crack')[0];
crack.classList.add('onclick');
addSorce(crack);
showSorces();
}
if (event.keyCode == 87) {
var crack = document.getElementsByClassName('crack')[1];
crack.classList.add('onclick');
addSorce(crack);
showSorces();
}
if (event.keyCode == 69) {
var crack = document.getElementsByClassName('crack')[2];
crack.classList.add('onclick');
addSorce(crack);
showSorces();
}
if (event.keyCode == 82) {
var crack = document.getElementsByClassName('crack')[3];
crack.classList.add('onclick');
addSorce(crack);
showSorces();
}
}
// QWER健按下事件
document.onkeyup = function (event) {
if (event.keyCode == 81) {
var crack = document.getElementsByClassName('crack')[0];
crack.classList.remove('onclick');
}
if (event.keyCode == 87) {
var crack = document.getElementsByClassName('crack')[1];
crack.classList.remove('onclick');
}
if (event.keyCode == 69) {
var crack = document.getElementsByClassName('crack')[2];
crack.classList.remove('onclick');
}
if (event.keyCode == 82) {
var crack = document.getElementsByClassName('crack')[3];
crack.classList.remove('onclick');
}
}
//判断按钮点击,小方块在什么位置,进而加多少分
function addSorce(crack) {
var firstBlock = crack.firstChild; //获取该轨道的第一个小方块
if (firstBlock) { //如果该轨道存在小方块
var blockTop = firstBlock.offsetTop;
var blockHeight = firstBlock.offsetHeight;
var crackHeight = crack.offsetHeight;
// console.log(blockTop,blockHeight,crackHeight);
var prefect = document.getElementsByClassName("prefect")[0];
var good = document.getElementsByClassName("good")[0];
var miss = document.getElementsByClassName("miss")[0];
// console.log(blockTop, blockHeight,crackHeight);
if (blockTop <= crackHeight - blockHeight && blockTop >= crackHeight - blockHeight * 1.3) {
socre += 2; //加2分
prefect.style.display = "block";
firstBlock.remove();
} else if (blockTop >= crackHeight - blockHeight * 1.8 && blockTop < crackHeight - blockHeight * 1.3) {
socre += 1;
good.style.display = "block";
} else {
miss.style.display = "block";
}
}
}
// 每隔一段时间去除miss,prefect.good的样式
function remove() {
var prefect = document.getElementsByClassName("prefect")[0];
var good = document.getElementsByClassName("good")[0];
var miss = document.getElementsByClassName("miss")[0];
prefect.style.display = "none";
good.style.display = "none";
miss.style.display = "none";
}
//显示分数
function showSorces() {
var elem = document.getElementsByClassName("sorce")[0];
elem.innerHTML = socre;
elem.style.color = 'red';
}
//"开始游戏"按钮函数
function gameTime() {
var time = 20;
var eleTime = document.getElementsByClassName('time')[0];
var timer = setInterval(function () {
if (time >= 0) {
CreateBlock();
eleTime.innerHTML = time + "s";
eleTime.style.color = "red"
time--;
} else {
clearInterval(timer);
//到时间,清空还在轨道上的方块
var blocks = document.getElementsByClassName('crack');
for (var i = 0; i < blocks.length; i++) {
while (blocks[i].hasChildNodes()) {
blocks[i].removeChild(blocks[i].firstChild);
}
}
alert("time is run out")
var player = {
name: "玩家" + num,
socre: socre
};
items.push(player);
items.sort(function (a, b) { //默认是按照字符串大小排序,改成按数字
return (b.socre - a.socre); //降序
});
num++; //玩家编号+1
socre = 0; //重置
showSorces(); //重置分数
showRankList(); //展示分数top5
}
}, 1000)
}
//展示积分表
function showRankList() {
var table = document.getElementsByClassName("rank-table")[0];
console.log(table.rows.length);
if (table.rows.length > 0) { //先把所有的行删除
for (var i = table.rows.length - 1; i > 0; i--) {
table.deleteRow(i);
}
}
//从数组中读取数组,写到积分表中
var maxLength = 5; //top5
if (items.length < 5) {
maxLength = items.length; //最多读出5个
}
for (var i = 0; i < maxLength; i++) {
var row = document.getElementsByClassName("rank-table")[0].insertRow(i + 1); //i+1是表示插入在th后面
var name = row.insertCell(0);
var socre = row.insertCell(1);
name.innerHTML = items[i].name;
socre.innerHTML = items[i].socre;
}
}
setInterval(remove, 800); //定时清理prefect,miss,good的标志