You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HTML5 Canvas圆形与方形元素碰撞弹跳及旋转效果开发需求

嘿,我帮你搞定了这个Canvas弹跳碰撞的需求,结合你提到的参考思路,我扩展了方形元素和碰撞旋转的逻辑,下面是完整的实现方案:

实现思路概述

要完成这个效果,核心要处理四个关键点:

  • 给圆形和方形元素赋予基础的运动物理(速度、位置更新)
  • 边界碰撞反弹逻辑(碰到画布边缘改变运动方向)
  • 不同元素间的碰撞检测(圆-圆、圆-方)
  • 碰撞触发的旋转效果(碰撞时给元素添加旋转角度增量)
完整代码示例
<!DOCTYPE html>
<html>
<head>
    <title>Canvas Bounce & Collide with Rotation</title>
    <style>
        canvas {
            border: 2px solid #333;
        }
    </style>
</head>
<body>
    <canvas id="my_canvas" width="600" height="300"></canvas>

    <script>
        const canvas = document.getElementById("my_canvas");
        const c = canvas.getContext("2d");
        const container = { x: 0, y: 0, width: canvas.width, height: canvas.height };

        // 圆形元素类
        class Circle {
            constructor(x, y, radius, color) {
                this.x = x;
                this.y = y;
                this.radius = radius;
                this.color = color;
                this.vx = (Math.random() - 0.5) * 4;
                this.vy = (Math.random() - 0.5) * 4;
                this.rotation = 0; // 旋转角度
            }

            draw() {
                c.save();
                c.translate(this.x, this.y);
                c.rotate(this.rotation);
                c.beginPath();
                c.arc(0, 0, this.radius, 0, Math.PI * 2);
                c.fillStyle = this.color;
                c.fill();
                c.restore();
            }

            update() {
                // 边界碰撞反弹
                if (this.x + this.radius > container.width || this.x - this.radius < container.x) {
                    this.vx = -this.vx;
                    this.rotation += (Math.random() - 0.5) * 0.2; // 碰撞时旋转
                }
                if (this.y + this.radius > container.height || this.y - this.radius < container.y) {
                    this.vy = -this.vy;
                    this.rotation += (Math.random() - 0.5) * 0.2;
                }

                this.x += this.vx;
                this.y += this.vy;
                this.draw();
            }
        }

        // 方形元素类
        class Square {
            constructor(x, y, size, color) {
                this.x = x;
                this.y = y;
                this.size = size;
                this.color = color;
                this.vx = (Math.random() - 0.5) * 3;
                this.vy = (Math.random() - 0.5) * 3;
                this.rotation = 0;
            }

            draw() {
                c.save();
                c.translate(this.x, this.y);
                c.rotate(this.rotation);
                c.fillStyle = this.color;
                c.fillRect(-this.size/2, -this.size/2, this.size, this.size);
                c.restore();
            }

            update() {
                // 边界碰撞反弹
                if (this.x + this.size/2 > container.width || this.x - this.size/2 < container.x) {
                    this.vx = -this.vx;
                    this.rotation += (Math.random() - 0.5) * 0.3;
                }
                if (this.y + this.size/2 > container.height || this.y - this.size/2 < container.y) {
                    this.vy = -this.vy;
                    this.rotation += (Math.random() - 0.5) * 0.3;
                }

                this.x += this.vx;
                this.y += this.vy;
                this.draw();
            }
        }

        // 初始化元素数组
        const elements = [];
        // 添加5个圆形
        for (let i = 0; i < 5; i++) {
            const radius = 20 + Math.random() * 15;
            elements.push(new Circle(
                radius + Math.random() * (container.width - radius*2),
                radius + Math.random() * (container.height - radius*2),
                radius,
                `hsl(${Math.random()*360}, 70%, 60%)`
            ));
        }
        // 添加3个方形
        for (let i = 0; i < 3; i++) {
            const size = 30 + Math.random() * 20;
            elements.push(new Square(
                size/2 + Math.random() * (container.width - size),
                size/2 + Math.random() * (container.height - size),
                size,
                `hsl(${Math.random()*360}, 80%, 50%)`
            ));
        }

        // 碰撞检测函数
        function checkCollisions() {
            for (let i = 0; i < elements.length; i++) {
                for (let j = i + 1; j < elements.length; j++) {
                    const el1 = elements[i];
                    const el2 = elements[j];

                    if (el1 instanceof Circle && el2 instanceof Circle) {
                        // 圆-圆碰撞检测
                        const dx = el2.x - el1.x;
                        const dy = el2.y - el1.y;
                        const distance = Math.sqrt(dx*dx + dy*dy);
                        const minDist = el1.radius + el2.radius;

                        if (distance < minDist) {
                            // 计算碰撞后的速度(简化的弹性碰撞)
                            const tempVx = el1.vx;
                            const tempVy = el1.vy;
                            el1.vx = el2.vx;
                            el2.vx = tempVx;
                            el1.vy = el2.vy;
                            el2.vy = tempVy;

                            // 碰撞后旋转
                            el1.rotation += (Math.random() - 0.5) * 0.4;
                            el2.rotation += (Math.random() - 0.5) * 0.4;

                            // 分离重叠元素
                            const overlap = minDist - distance;
                            const tx = dx / distance * overlap * 0.5;
                            const ty = dy / distance * overlap * 0.5;
                            el1.x -= tx;
                            el1.y -= ty;
                            el2.x += tx;
                            el2.y += ty;
                        }
                    } else if ((el1 instanceof Circle && el2 instanceof Square) || (el1 instanceof Square && el2 instanceof Circle)) {
                        // 圆-方碰撞检测(轴对齐简化版)
                        const circle = el1 instanceof Circle ? el1 : el2;
                        const square = el1 instanceof Square ? el1 : el2;

                        // 找到圆到方形最近的点
                        const closestX = Math.max(square.x - square.size/2, Math.min(circle.x, square.x + square.size/2));
                        const closestY = Math.max(square.y - square.size/2, Math.min(circle.y, square.y + square.size/2));

                        // 计算圆中心到最近点的距离
                        const dx = circle.x - closestX;
                        const dy = circle.y - closestY;
                        const distance = Math.sqrt(dx*dx + dy*dy);

                        if (distance < circle.radius) {
                            // 反弹速度
                            circle.vx = -circle.vx;
                            circle.vy = -circle.vy;
                            square.vx = -square.vx * 0.8;
                            square.vy = -square.vy * 0.8;

                            // 碰撞旋转
                            circle.rotation += (Math.random() - 0.5) * 0.5;
                            square.rotation += (Math.random() - 0.5) * 0.6;

                            // 分离重叠
                            const overlap = circle.radius - distance;
                            const tx = dx / distance * overlap;
                            const ty = dy / distance * overlap;
                            circle.x += tx;
                            circle.y += ty;
                        }
                    }
                }
            }
        }

        // 动画循环
        function animate() {
            c.clearRect(0, 0, container.width, container.height);
            elements.forEach(el => el.update());
            checkCollisions();
            requestAnimationFrame(animate);
        }

        animate();
    </script>
</body>
</html>
关键功能解析
  • 元素类设计:分别创建了Circle和Square类,封装了位置、速度、旋转角度等属性,以及draw()(绘制元素,带旋转)和update()(更新位置、处理边界碰撞)方法。
  • 边界碰撞处理:当元素碰到画布边缘时,反转速度方向,同时随机添加旋转角度增量,模拟碰撞后的旋转效果。
  • 圆-圆碰撞:通过计算两个圆心的距离判断是否碰撞,碰撞后交换速度(简化弹性碰撞),并添加旋转,最后调整位置分离重叠元素。
  • 圆-方碰撞:找到圆到方形边界的最近点,计算距离判断碰撞,碰撞后反转两者速度(方形速度做了衰减更真实),同时添加旋转效果,同样处理重叠分离。

内容的提问来源于stack exchange,提问作者Joe Cory

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:21:23