javascript-原生javascript實現節奏大師小遊戲

前言

  • 課程實驗要求,迫不得已看了一點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>&nbsp&nbsp&nbsp
            <span>遊戲時間:<span class="time"></span></span>&nbsp&nbsp&nbsp
            <span>積分:<span class="sorce">0</span></span>&nbsp&nbsp&nbsp
            <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的標誌
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章