原生JS实现挡板小球游戏

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }
        
        .box {
            width: 940px;
            height: 500px;
            border: 1px solid #000;
            margin: 50px auto;
            position: relative;
            /* cursor: none; */
        }
        
        .block {
            position: absolute;
            top: 0;
            left: 0;
            width: 94px;
            height: 36px;
            background: url(img/block.png);
        }
        
        .ball {
            position: absolute;
            width: 27px;
            height: 27px;
            background: url(img/ball.png);
        }
        
        .racket {
            position: absolute;
            width: 179px;
            height: 37px;
            background: url(img/racket.png);
            top: 450px;
            left: 10px;
        }
    </style>
</head>

<body>
    <div class="box" id="box">
        <div class="ball" id="ball"></div>
        <div class="racket" id="racket"></div>
    </div>
</body>

<script>
    // 获取dom对象
    var box = document.getElementById('box');
    var ball = document.getElementById('ball');
    var racket = document.getElementById('racket');
    // 面向对象的思维挡板,小球,地图,碰撞块,大盒子都可以是一个类

    // 创建碰撞块类

    function Block(left, top, color) {
        this.top = top;
        this.left = left;
        this.width = 94;
        this.height = 36;
        this.color = color;
        this.alive = true;
        this.init();
    }

    // 块类有一个初始化方法
    Block.prototype.init = function() {
        this.dom = document.createElement('div');
        this.dom.className = 'block';
        box.appendChild(this.dom);
        this.render();
    }

    // 块类有一个渲染方法
    Block.prototype.render = function() {
        this.dom.style.top = this.top + 'px';
        this.dom.style.left = this.left + 'px';
        this.dom.style.backgroundPosition = -this.color * this.width + 'px 0';
    };
    // 我们的block也要有碰撞检测,当被小球撞到时消失,并且反弹小球

    Block.prototype.check = function() {
        // 上边界检测
        if (b.top >= this.top - b.d && b.top <= this.top && b.left >= this.left - b.d && b.left <= this.left + this.width) {
            b.deltaY *= -1;
            this.hide();
            return true;
            // 下边界检测
        } else if (b.top <= this.top + this.height && b.top >= this.top && b.left >= this.left - b.d && b.left <= this.left + this.width) {
            b.deltaY *= -1;
            this.hide();
            return true;
            // 左边界检测
        } else if (b.left >= this.left - b.d && b.left <= this.left && b.top >= this.top && b.top <= this.top + this.height) {
            b.deltaX *= -1;
            this.hide();
            return true;
            // 右边界检测
        } else if (b.left <= this.left + this.width && b.left >= this.left && b.top >= this.top && b.top <= this.top + this.height) {
            b.deltaX *= -1;
            this.hide();
            return true;
        }
    };
    Block.prototype.hide = function() {
        this.alive = false;
        container.dom.removeChild(this.dom);
    };

    // 创建地图类

    function Map() {
        // 地图类需要有一个二维数组来表示box内的block数量
        this.data = [
            [0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
            [0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
            [0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
            [0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
            [0, 1, 2, 3, 0, 1, 2, 3, 0, 1],
            [0, 1, 2, 3, 0, 1, 2, 3, 0, 1],

        ];
        this.allBlockArr = [];
        this.render();
    }

    // Map也有一个render方法
    Map.prototype.render = function() {
        // 遍历二维数组
        for (var row = 0; row < this.data.length; row++) {
            for (var col = 0; col < this.data[row].length; col++) {
                this.allBlockArr.push(new Block(col * 94, row * 30, this.data[row][col]))
            }
        }
    };
    // 检测所有block是否被小球碰撞
    Map.prototype.checkAll = function() {
        for (var i = 0; i < this.allBlockArr.length; i++) {
            if (this.allBlockArr[i].alive) {
                var result = this.allBlockArr[i].check()
            }
            if (result) {
                break;
            }
        }
    }

    // 创建小球类
    function Ball() {
        this.left = 480;
        this.top = 400;
        this.d = 27;
        // 小球运动速度,运动角度
        this.speed = 5;
        this.angle = 50;
        // 小球的运动方向
        // 计算机采用的是弧度制,并不是角度制
        // 这里我们将圆球运动看作三角模型那么它斜向运动的speed就是斜线
        // 我们可以根据角度计算出sin 也就是对边 / 斜边 的值
        // 然后让其 * 斜边speed得到对边也就是Y轴的移动速度
        this.deltaY = Math.sin(angleChangeToRadian(this.angle)) * this.speed;
        // 三角函数中余弦就是邻边比斜边
        this.deltaX = Math.cos(angleChangeToRadian(this.angle)) * this.speed;
        this.dom = ball;
        this.fly();
    }
    // 小球有一个运动方法

    Ball.prototype.fly = function() {
        var self = this;
        var timer = setInterval(function() {
            self.left += self.deltaX;
            self.top += self.deltaY;
            self.dom.style.left = self.left + 'px';
            self.dom.style.top = self.top + 'px';
            // 每十秒让container检测是否被小球碰到
            container.check();
            map.checkAll();
            oRacket.check();
        }, 10)

    }

    // 创建一个大盒子的类
    function Box() {
        this.dom = box;
        this.width = 940;
        this.height = 500;

    }
    //  大盒子需要一个碰撞检测,当检测到小球碰撞到盒子时反弹
    Box.prototype.check = function() {
        // 左右边界检测
        // 反弹的原理是当我们的小球以X轴5 / s,Y轴 8 / s的速度下降,那么它反弹后
        // X轴的速度不变,Y轴向相反方向运动
        if (b.left >= this.width - b.d || b.left <= 0) {
            b.deltaX *= -1;
        }

        if (b.top >= this.height - b.d || b.top <= 0) {
            b.deltaY *= -1;
        }
    }


    // 创建挡板类
    function Racket() {
        this.width = 179;
        this.height = 37;
        this.top = 450;
        this.left = 10;
        this.dom = racket;
        this.move()
    }
    // 挡板移动
    Racket.prototype.move = function() {
        var self = this;
        container.dom.onmousemove = function(event) {
            event = event || window.event;
            self.left = event.clientX - container.dom.offsetLeft - self.width / 2;
            self.dom.style.left = self.left + 'px';
        }
    };
    // 挡板碰撞检测
    Racket.prototype.check = function() {
        // 上边界检测
        if (b.top >= this.top - b.d && b.top <= this.top && b.left >= this.left - b.d && b.left <= this.left + this.width) {
            b.deltaY *= -1;
            // 下边界检测
        } else if (b.top <= this.top + this.height && b.top >= this.top && b.left >= this.left - b.d && b.left <= this.left + this.width) {
            b.deltaY *= -1;
            // 左边界检测
        } else if (b.left >= this.left - b.d && b.left <= this.left && b.top >= this.top && b.top <= this.top + this.height) {
            b.deltaX *= -1;
            // 右边界检测
        } else if (b.left <= this.left + this.width && b.left >= this.left && b.top >= this.top && b.top <= this.top + this.height) {
            b.deltaX *= -1;
        }

    }
    var b = new Ball();
    var map = new Map();
    var container = new Box();
    var oRacket = new Racket()


    // 定义角度转弧度的函数
    function angleChangeToRadian(angle) {
        return angle * Math.PI / 180;
    }
</script>

</html>

posted on 2020-03-06 17:11  素心~  阅读(561)  评论(0编辑  收藏  举报

导航