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的标志
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章