前言
-
課程實驗要求,迫不得已看了一點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,鍵盤事件,定時器等等=.=
效果
Code
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game</title>
<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">0</span></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>積分+2</div>
<div class="good">good~<br>OvO<br>積分+1</div>
<div class="miss">miss~<br>OvO<br>積分+0</div>
</div>
<div id="rank-rule">
<div class="rankbox">
<div class="rank-list">
<table class="rank-table">
<caption>遊戲積分表Top5</caption>
<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>
css
* {
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;
}
*/
javascript
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的標誌