当前位置:首页 > VUE

vue怎么实现小球碰撞

2026-02-24 23:36:47VUE

Vue 实现小球碰撞的方法

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

创建 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。

vue怎么实现小球碰撞

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中实现下载暂停功能,通常需要结合XMLHttpRequest或Fetch API的AbortController来控制请求中断。以下是具体实现方法: 使用XMLHtt…

vue实现打印二维码

vue实现打印二维码

安装二维码生成库 使用 qrcode 或 vue-qrcode 库生成二维码。通过 npm 安装: npm install qrcode vue-qrcode 生成二维码 在 Vue 组件中引入…

eventbus vue实现

eventbus vue实现

EventBus 实现原理 EventBus 是一种发布/订阅模式,用于 Vue 组件间的通信。核心是通过一个中央事件总线管理事件监听和触发。 创建 EventBus 在 Vue 项目中创建一个独立…

vue实现详情

vue实现详情

Vue 实现详情页的常见方法 使用动态路由 在 Vue Router 中配置动态路由参数,通过 $route.params 获取详情 ID。示例路由配置: { path: '/detail/:i…

vue实现cs

vue实现cs

Vue 实现 CS(Client-Side)渲染的常见方法 Vue.js 是一个用于构建用户界面的渐进式框架,默认采用客户端渲染(CSR)。以下是几种常见的实现方式: 使用 Vue CLI 创建项目…

vue登录实现

vue登录实现

Vue 登录实现 实现登录功能通常需要前端与后端配合,Vue 作为前端框架,主要负责表单处理、请求发送和状态管理。以下是常见的实现方式: 表单设计与数据绑定 使用 Vue 的 v-model 实现表…