小球碰撞问题

题目:

今天遇到了一个比较复杂的问题,准备用canvas实现一下这个效果
小球碰撞问题_第1张图片

实现方案

<!--/**
   * @author: liuk
   * @date: 2023/4/9
   * @describe: 小球位置
  */-->
<!doctype html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=10">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="generator" content="editplus@">
    <meta name="author" content="作者">
    <meta name="keywords" content="关键字">
    <meta name="description" content="描述">
    <title>小球位置</title>
    <link rel="shortcut icon" href=""/><!-- 网页图标 -->
    <link rel="stylesheet" type="javascript" href="">
    <style type="text/css">
        canvas {
            background-color: #ccc;
        }
    </style>
</head>
<body>
<canvas></canvas>
<script type="text/javascript">
    const canvas = document.getElementsByTagName('canvas')[0],
        ctx = canvas.getContext('2d');

    class Ball {
        constructor(startPos, direction, box, obstacle, r = 5) {
            const [startX, startY] = startPos;//小球运动起点
            this.x = this.limitPos(startX, r, 100);
            this.y = this.limitPos(startY, r, 100);

            const [direction1, direction2] = direction // 小球初始方向
            this.dx = (direction2[0] - direction1[0]) / 10;
            this.dy = (direction2[1] - direction1[1]) / 10;

            const [box1, box2, box3, box4] = box // 外围框(暂定为长方形)
            canvas.width = box3[0] - box1[0];
            canvas.height = box3[1] - box1[1];
            this.boxStartpos = box1;// 盒子左上点坐标

            this.obstacleArr = obstacle;// 障碍物位置,求出 y = kx +b
            this.k = null;
            this.b = null;
            this.xx = null;

            this.color = 'blue';
            this.r = r;
            this.timer = null
        }

        init() {
            //定时器
            return new Promise((resolve, reject) => {
                this.lineFn()
                const self = this
                this.timer = setInterval(function () {
                    ctx.clearRect(0, 0, canvas.width, canvas.height)
                    self.update();
                    self.renderLine()
                    self.renderBall();
                    self.isLineInner([self.x, self.y], (val) => {
                        resolve(val)
                    })
                }, 10);
            })

        }

        update() {//小球运动
            this.x += this.dx;
            this.y += this.dy;
            if (this.x < this.r || this.x > canvas.width - this.r) {
                this.dx = -this.dx;
            }
            if (this.y < this.r || this.y > canvas.height - this.r) {
                this.dy = -this.dy;
            }
        }

        renderBall() { // 小球渲染
            ctx.beginPath();
            ctx.globalAlpha = '1';
            ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
            ctx.closePath();
            ctx.fillStyle = this.color;
            ctx.fill();
        }

        renderLine() {// 障碍物渲染
            ctx.beginPath();
            ctx.moveTo(this.obstacleArr[0][0], this.obstacleArr[0][1]);
            ctx.lineTo(this.obstacleArr[1][0], this.obstacleArr[1][1]);
            ctx.lineWidth = 1;
            ctx.strokeStyle = 'red';
            ctx.stroke()
        }

        limitPos(count, r, boxL) {// 限制球在盒子内
            return count < r || count > boxL - r ? r : count;
        }

        lineFn() {//求出 障碍物的线性方程  y = kx + b
            // 斜率
            const k = ((this.obstacleArr[1][1] - this.obstacleArr[0][1]) / (this.obstacleArr[1][0] - this.obstacleArr[0][0]))
            this.k = k
            if (Math.abs(k) === Infinity) {
                this.xx = this.obstacleArr[0][0]; // x = 常数
            } else if (k === 0) {
                this.b = this.obstacleArr[0][1]; // y = 常数}
            } else {
                this.b = this.obstacleArr[0][1] - (k * this.obstacleArr[0][0])
            }
        }

        isLineInner(pos, callback) { // 判断点是否在线上
            const [x, y] = pos
            if (x < Math.min(this.obstacleArr[0][0], this.obstacleArr[1][0]) ||
                x > Math.max(this.obstacleArr[0][0], this.obstacleArr[1][0]) ||
                y < Math.min(this.obstacleArr[0][1], this.obstacleArr[1][1]) ||
                y > Math.max(this.obstacleArr[0][1], this.obstacleArr[1][1])) {
                return
            } else if (this.xx && this.xx === x) {//情况1
                callback([this.boxStartpos[0] + x, this.boxStartpos[1] + y]);
                window.clearInterval(this.timer)
                return [this.boxStartpos[0] + x, this.boxStartpos[1] + y]
            } else if (this.k === 0 && y === this.b) {//情况2
                callback([this.boxStartpos[0] + x, this.boxStartpos[1] + y]);
                window.clearInterval(this.timer)
                return [this.boxStartpos[0] + x, this.boxStartpos[1] + y]
            } else if (this.y.toFixed() === (this.k * x + this.b).toFixed()) {//情况3
                callback([this.boxStartpos[0] + x, this.boxStartpos[1] + y]);
                window.clearInterval(this.timer)
                return [this.boxStartpos[0] + x, this.boxStartpos[1] + y]
            }
        }
    }

    function getEndPos(startPos, direction, box, obstacle) {
        const ball = new Ball(startPos, direction, box, obstacle);
        ball.init().then((val) => {
            alert('当前小球位置为   ' + JSON.stringify(val))
        })
    }

    getEndPos([5, 10], [[0, 0], [5, 5]], [[0, 0], [500, 0], [500, 500], [0, 500]], [[300, 200], [300, 500]])
</script>
</body>
</html>

实现效果

小球障碍物碰撞题目实现

你可能感兴趣的:(#,知识储备,javascript,前端,开发语言)