JS+Position实现类接元宝游戏

一、实现效果

二、实现过程

先看一眼HTML结构

<div class="top-bar"><span>得分:</span><span id="score">0</span></div>
<div class="container">
    <div class="gem-container">
        <div class="gem" id="gem0">
            <img src="./img/blueGem.png" alt="蓝宝石" />
        </div>
        <div class="gem" id="gem1">
            <img src="./img/purpleGem.png" alt="紫宝石" />
        </div>
        <div class="gem" id="gem2">
            <img src="./img/blueGem.png" alt="蓝宝石" />
        </div>
        <div class="gem" id="gem3">
            <img src="./img/purpleGem.png" alt="紫宝石" />
        </div>
        <div class="gem" id="gem4">
            <img src="./img/blueGem.png" alt="蓝宝石" />
        </div>
    </div>
    <div class="car" id="car">
        <img src="./img/car.png" alt="矿车" />
    </div>
</div>

接下来是过程:

1.小车移动

先获取小车当前的left,使用split取到数字

全局监听键盘左右键,keyCode分别是37和39,同时判断在边框时不再生效移动

因为上面使用spilit()的原因,取到的小车left是字符串,使用eval()将其视为数字计算

计算后更改小车的left

document.onkeydown = function (e) {
    left = car.style.left.split("px")[0];
    if (e.keyCode == 37 && car.style.left != "0px") {  // 监听方向键左且不在边框最左侧
        left = eval(left) - 20;
        car.style.left = left + "px";
    }
    if (e.keyCode == 39 && car.style.left != "400px") {  // 监听方向键右且不在边框最右侧
        left = eval(left) + 20;
        car.style.left = left + "px";
    }
};

2.随机出现宝石

HTML共定义5个宝石,命名分别是gem0~4,因此使用Math方法随机获取0~4整数作为索引

以此获取到宝石后,做判断:该索引的宝石是否存在,若存在则再次随机(以此避免重复使同一个宝石出现)

然后对出现的宝石触发下落

最后对上述过程做一个循环器,每隔4秒执行

// 随机指定宝石出现
function randomGem() {
    let index = Math.floor(Math.random() * 5);
    let gemId = "gem" + index;
    let gemEl = document.getElementById(gemId);
    return gemEl;
}

// 宝石出现循环器
setInterval(function () {
    let gemEl = randomGem(); // 获取随机的宝石
    for (let i = 0; gemEl.style.display == "block"; i++) {  // 遍历宝石以获取未出现的宝石
        gemEl = randomGem();
    }
    gemEl.style.display = "block";
    gemDown(gemEl);
}, 4000);

3.宝石下落

这个比较简单,获取上文函数中的gemEl(宝石元素),初始化它的top为0px(否则会为空值导致报错)

设定循环器:获取宝石的top,然后对其增加并赋给宝石,这里要实现流程的下落,尽可能将循环器定义的循环速度高一些,我这里采用100毫秒

// 宝石下落
function gemDown(gemEl) {
    gemEl.style.top = "0px"; // 初始化gem的top
    const gemDown = setInterval(function () {  // 下落循环器
        let gemTop = gemEl.style.top.split("px")[0];
        gemTop = eval(gemTop) + 10;
        gemEl.style.top = gemTop + "px";
    }, 100);
}

4.判断是否接取宝石

难点主要集中在这里了

不着急一步步来:

(1)先算出宝石到达小车时的top是多少,作为判定线

if (gemEl.style.top == "720px") {
}

(2) 到达判定线时,判断是否接住宝石

概念大概如下图,主要计算最左侧接取和最右侧接取,宝石接取的范围即是: 最左侧的值~最右侧的值

接下来计算:

分别获取小车和宝石的left

当宝石在最左侧:宝石left + 30 (自身宽度) - 10 (避免造成擦边接取以减少接取范围)

当宝石在最右侧:宝石left + 10 (原理同上),但此时的小车最右侧的left应该等于当前left+自身宽度,即:小车left + 100 (自身宽度)

作为代码就是:eval(gemLeft) + 20 >= carLeft && gemLeft <= eval(carLeft) + 90

// 判定是否接住宝石
function isCatch(gemEl) {
    let gemLeft = gemEl.style.left.split("px")[0];
    let carLeft = car.style.left.split("px")[0];
    if (
        eval(gemLeft) + 20 >= carLeft && // 最左侧判定
        gemLeft <= eval(carLeft) + 90 // 最右侧判定
    )
        return true;
    else return false;
}

 

结合第(1)步就是

 // 宝石到达判定线
if (gemEl.style.top == "720px") {
    // 判断是否接住宝石
    if (isCatch(gemEl)) {
    }
}

(3)实现当移动小车使用小车左右侧碰撞宝石仍可以接取宝石

实现这个有个前提就是:一直在做判断是否接取,那就定义一个循环器呗

连起来就是,宝石到达判定线开始,每0.1秒做判断是否接取了宝石

// 宝石到达判定线
if (gemEl.style.top == "720px") {
    const chkCatch = setInterval(function () {  // 在宝石掉出边框前循环判断是否接住(小车左右侧接触宝石也可以接取)
        // 判断是否接住宝石
        if (isCatch(gemEl)) {
            clearInterval(gemDown);
            clearInterval(chkCatch); // 清理下落和判定接取的循环器
            gemEl.style.display = "none";
            score.innerText = ++scoreNum; // 接住加分
        }
    }, 100);
}

(4)判断宝石是否掉到边框外

很简单不赘述,留意要放在循环器中

// 直到掉出边框未接住
if (gemEl.style.top == "810px") {
    clearInterval(gemDown);
    clearInterval(chkCatch);
    gemEl.style.display = "none";
    score.innerText = --scoreNum; // 未接住扣分
}

三、源码

最后源码奉上,我已经把img替换,这样直接就能跑起来了

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>接宝石</title>
        <style>
            .top-bar {
                width: 500px;
                margin: 0 auto;
            }
            
            .container {
                width: 500px;
                height: 800px;
                margin: 0 auto;
                border: 2px black solid;
                background-color: burlywood;
            }

            .gem-container {
                position: relative;
            }

            .gem {
                width: 30px;
                height: 30px;
                float: left;
                line-height: 30px;
                text-align: center;
                font-size: 900;
                color: red;
                position: absolute;
                top: 0;
                left: 0;
                display: inline;
                background-color: yellow;
                border-radius: 15px;
            }

            .car {
                position: relative;
                top: 750px;
                left: 0px;
                width: 100px;
                height: 50px;
                background-color: gray;
            }
        </style>
    </head>

    <body>
        <div class="top-bar"><span>得分:</span><span id="score">0</span></div>
        <div class="container">
            <div class="gem-container">
                <div class="gem" id="gem0">$</div>
                <div class="gem" id="gem1">$</div>
                <div class="gem" id="gem2">$</div>
                <div class="gem" id="gem3">$</div>
                <div class="gem" id="gem4">$</div>
            </div>
            <div class="car" id="car"></div>
        </div>

        <script>
            const gem = document.getElementsByClassName("gem"); // 宝石
            const car = document.getElementById("car"); // 小车
            const score = document.getElementById("score"); //得分
            let scoreNum = 0; // 得分数字
            let left = 0; // 小车的left数字
            car.style.left = "0px"; // 初始化小车的left

            // 初始隐藏宝石,并给宝石left赋值
            let gemLeft = 0;
            for (let i of gem) {
                i.style.display = "none";
                gemLeft += 80;
                i.style.left = gemLeft + "px";
            }

            // 监听键盘按键以控制小车移动
            document.onkeydown = function (e) {
                left = car.style.left.split("px")[0];
                if (e.keyCode == 37 && car.style.left != "0px") {  // 监听方向键左且不在边框最左侧
                    left = eval(left) - 20;
                    car.style.left = left + "px";
                }
                if (e.keyCode == 39 && car.style.left != "400px") {  // 监听方向键右且不在边框最右侧
                    left = eval(left) + 20;
                    car.style.left = left + "px";
                }
            };

            // 随机指定宝石出现
            function randomGem() {
                let index = Math.floor(Math.random() * 5);
                let gemId = "gem" + index;
                let gemEl = document.getElementById(gemId);
                return gemEl;
            }

            // 宝石出现循环器
            setInterval(function () {
                let gemEl = randomGem(); // 获取随机的宝石
                for (let i = 0; gemEl.style.display == "block"; i++) {  // 遍历宝石以获取未出现的宝石
                    gemEl = randomGem();
                }
                gemEl.style.display = "block";
                gemDown(gemEl);
            }, 4000);

            // 宝石下落
            function gemDown(gemEl) {
                gemEl.style.top = "0px"; // 初始化gem的top
                const gemDown = setInterval(function () {  // 下落循环器
                    let gemTop = gemEl.style.top.split("px")[0];
                    gemTop = eval(gemTop) + 10;
                    gemEl.style.top = gemTop + "px";
                    // 宝石到达判定线
                    if (gemEl.style.top == "720px") {
                        const chkCatch = setInterval(function () {  // 在宝石掉出边框前循环判断是否接住(小车左右侧接触宝石也可以接取)
                            // 判断是否接住宝石
                            if (isCatch(gemEl)) {
                                clearInterval(gemDown);
                                clearInterval(chkCatch); // 清理下落和判定接取的循环器
                                gemEl.style.display = "none";
                                score.innerText = ++scoreNum; // 接住加分
                            }
                            // 直到掉出边框未接住
                            if (gemEl.style.top == "810px") {
                                clearInterval(gemDown);
                                clearInterval(chkCatch);
                                gemEl.style.display = "none";
                                score.innerText = --scoreNum; // 未接住扣分
                            }
                        }, 100);
                    }
                }, 100);
            }

            // 判定是否接住宝石
            function isCatch(gemEl) {
                let gemLeft = gemEl.style.left.split("px")[0];
                let carLeft = car.style.left.split("px")[0];
                if (
                    eval(gemLeft) + 20 >= carLeft && // 最左侧判定
                    gemLeft <= eval(carLeft) + 90 // 最右侧判定
                )
                    return true;
                else return false;
            }
        </script>
    </body>
</html>

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值