当前位置:首页 > VUE

vue怎么实现小球碰撞

2026-02-24 23:36:47VUE

Vue 实现小球碰撞的方法

在 Vue 中实现小球碰撞效果,可以通过 Canvas 或 DOM 结合 JavaScript 的物理引擎来实现。以下是一个基于 Canvas 的实现方案。

vue怎么实现小球碰撞

创建 Vue 组件

在 Vue 项目中创建一个组件,用于绘制和更新小球的状态。

<template>
  <div>
    <canvas ref="canvas" :width="width" :height="height"></canvas>
  </div>
</template>

<script>
export default {
  data() {
    return {
      width: 800,
      height: 600,
      balls: [],
      ctx: null,
    };
  },
  mounted() {
    this.initCanvas();
    this.createBalls();
    this.animate();
  },
  methods: {
    initCanvas() {
      const canvas = this.$refs.canvas;
      this.ctx = canvas.getContext('2d');
    },
    createBalls() {
      for (let i = 0; i < 10; i++) {
        this.balls.push({
          x: Math.random() * this.width,
          y: Math.random() * this.height,
          radius: Math.random() * 20 + 10,
          dx: (Math.random() - 0.5) * 4,
          dy: (Math.random() - 0.5) * 4,
          color: `rgb(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255})`,
        });
      }
    },
    animate() {
      requestAnimationFrame(this.animate);
      this.ctx.clearRect(0, 0, this.width, this.height);
      this.updateBalls();
      this.drawBalls();
    },
    updateBalls() {
      this.balls.forEach((ball, index) => {
        ball.x += ball.dx;
        ball.y += ball.dy;

        // 边界碰撞检测
        if (ball.x + ball.radius > this.width || ball.x - ball.radius < 0) {
          ball.dx = -ball.dx;
        }
        if (ball.y + ball.radius > this.height || ball.y - ball.radius < 0) {
          ball.dy = -ball.dy;
        }

        // 小球之间的碰撞检测
        for (let j = index + 1; j < this.balls.length; j++) {
          const otherBall = this.balls[j];
          const dx = ball.x - otherBall.x;
          const dy = ball.y - otherBall.y;
          const distance = Math.sqrt(dx * dx + dy * dy);

          if (distance < ball.radius + otherBall.radius) {
            // 碰撞响应
            const angle = Math.atan2(dy, dx);
            const sin = Math.sin(angle);
            const cos = Math.cos(angle);

            // 旋转坐标系
            const x1 = 0;
            const y1 = 0;
            const x2 = dx * cos + dy * sin;
            const y2 = dy * cos - dx * sin;

            // 旋转速度
            const vx1 = ball.dx * cos + ball.dy * sin;
            const vy1 = ball.dy * cos - ball.dx * sin;
            const vx2 = otherBall.dx * cos + otherBall.dy * sin;
            const vy2 = otherBall.dy * cos - otherBall.dx * sin;

            // 碰撞后的速度(一维弹性碰撞)
            const vx1Final = ((ball.radius - otherBall.radius) * vx1 + 2 * otherBall.radius * vx2) / (ball.radius + otherBall.radius);
            const vx2Final = ((otherBall.radius - ball.radius) * vx2 + 2 * ball.radius * vx1) / (ball.radius + otherBall.radius);

            // 更新速度
            ball.dx = vx1Final * cos - vy1 * sin;
            ball.dy = vy1 * cos + vx1Final * sin;
            otherBall.dx = vx2Final * cos - vy2 * sin;
            otherBall.dy = vy2 * cos + vx2Final * sin;

            // 防止小球重叠
            const overlap = ball.radius + otherBall.radius - distance;
            const moveX = overlap * cos * 0.5;
            const moveY = overlap * sin * 0.5;
            ball.x += moveX;
            ball.y += moveY;
            otherBall.x -= moveX;
            otherBall.y -= moveY;
          }
        }
      });
    },
    drawBalls() {
      this.balls.forEach(ball => {
        this.ctx.beginPath();
        this.ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
        this.ctx.fillStyle = ball.color;
        this.ctx.fill();
        this.ctx.closePath();
      });
    },
  },
};
</script>

<style>
canvas {
  border: 1px solid #000;
}
</style>

物理引擎优化

如果需要更复杂的物理效果,可以引入物理引擎如 Matter.js 或 p5.js。

import Matter from 'matter-js';

export default {
  mounted() {
    const engine = Matter.Engine.create();
    const render = Matter.Render.create({
      element: this.$refs.canvas,
      engine: engine,
      options: {
        width: this.width,
        height: this.height,
        wireframes: false,
      },
    });

    const balls = [];
    for (let i = 0; i < 10; i++) {
      balls.push(Matter.Bodies.circle(
        Math.random() * this.width,
        Math.random() * this.height,
        Math.random() * 20 + 10,
        {
          restitution: 0.8,
          render: {
            fillStyle: `rgb(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255})`,
          },
        }
      ));
    }

    Matter.Composite.add(engine.world, balls);
    Matter.Engine.run(engine);
    Matter.Render.run(render);
  },
};

关键点说明

  • 使用 Canvas 绘制小球,并通过 requestAnimationFrame 实现动画循环。
  • 边界碰撞检测通过判断小球是否超出画布边界实现。
  • 小球之间的碰撞检测通过计算距离和半径之和实现。
  • 碰撞响应通过旋转坐标系简化为一维弹性碰撞问题。

通过以上方法,可以在 Vue 中实现小球的碰撞效果。

vue怎么实现小球碰撞

标签: 小球vue
分享给朋友:

相关文章

vue设计与实现目录

vue设计与实现目录

以下是《Vue设计与实现》一书的典型目录结构(根据常见技术书籍及Vue核心内容整理): 响应式系统 响应式数据的基本原理 依赖收集与触发更新 实现简易响应式系统 Proxy与Reflec…

vue 实现简单登陆

vue 实现简单登陆

以下是一个使用 Vue 3 实现的简单登录功能示例,包含表单验证和基础交互逻辑: 创建 Vue 组件 <template> <div class="login-contain…

vue实现分屏

vue实现分屏

Vue 实现分屏的方法 分屏功能通常用于展示多个独立内容区域,以下是几种常见的实现方式: 使用 CSS Grid 布局 通过 CSS Grid 可以轻松创建分屏布局,在 Vue 组件中直接应用样式:…

vue实现过滤

vue实现过滤

Vue实现过滤的方法 在Vue中实现数据过滤可以通过多种方式完成,以下是几种常见的方法: 使用计算属性过滤 计算属性是Vue中处理数据过滤的理想选择,它们基于响应式依赖进行缓存,只有在相关依赖发生改…

vue权限实现

vue权限实现

Vue 权限实现方案 基于路由的权限控制 通过路由守卫实现权限验证,在路由配置中添加meta字段标记权限要求。在router.beforeEach中检查用户权限与路由要求的匹配情况。 // rout…

vue实现 toast

vue实现 toast

Vue 实现 Toast 组件 在 Vue 中实现 Toast 组件可以通过多种方式完成,以下是几种常见的方法: 使用全局组件和事件总线 创建一个全局的 Toast 组件,并通过事件总线或 Vue…