【前端】弹球特效(重力模拟)

在这里插入图片描述
在这里插入图片描述

弹球特效

文章目录


请添加图片描述

import React, { useRef, useEffect } from 'react';

const BouncingBallSimulation = () => {
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    let animationFrameId;

    // Set canvas size
    canvas.width = 900;
    canvas.height = 1600;

    // Circle properties
    const centerX = canvas.width / 2;
    const centerY = canvas.height / 2;
    const radius = Math.min(centerX, centerY) * 0.7;

    // Ball properties
    const ballRadius = 15;
    let x = centerX;
    let y = centerY - radius + ballRadius;
    let dx = 2;
    let dy = 0;

    // Gravity and friction
    const gravity = 0.2;
    const friction = 0.99;

    // Matrix rain properties
    const fontSize = 14;
    const columns = canvas.width / fontSize;
    const drops = [];
    for (let i = 0; i < columns; i++) {
      drops[i] = 1;
    }

    const drawMatrixRain = () => {
      ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
      ctx.fillRect(0, 0, canvas.width, canvas.height);

      ctx.fillStyle = '#0F0';
      ctx.font = `${fontSize}px monospace`;

      for (let i = 0; i < drops.length; i++) {
        const text = String.fromCharCode(0x30A0 + Math.random() * 96);
        ctx.fillText(text, i * fontSize, drops[i] * fontSize);

        if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
          drops[i] = 0;
        }
        drops[i]++;
      }
    };

    const draw = () => {
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // Draw matrix rain
      drawMatrixRain();

      // Draw circle
      ctx.beginPath();
      ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
      ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
      ctx.stroke();

      // Draw ball
      ctx.beginPath();
      ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
      ctx.fillStyle = 'white';
      ctx.fill();

      // Apply gravity
      dy += gravity;

      // Ball movement and collision detection
      const nextX = x + dx;
      const nextY = y + dy;
      const distanceFromCenter = Math.sqrt((nextX - centerX) ** 2 + (nextY - centerY) ** 2);

      if (distanceFromCenter + ballRadius > radius) {
        // Calculate the normal vector
        const nx = (nextX - centerX) / distanceFromCenter;
        const ny = (nextY - centerY) / distanceFromCenter;

        // Calculate the dot product
        const dotProduct = dx * nx + dy * ny;

        // Update velocity
        dx = (dx - 2 * dotProduct * nx) * friction;
        dy = (dy - 2 * dotProduct * ny) * friction;
      } else {
        x = nextX;
        y = nextY;
      }

      animationFrameId = requestAnimationFrame(draw);
    };

    draw();

    return () => {
      cancelAnimationFrame(animationFrameId);
    };
  }, []);

  return (
    <div className="flex items-center justify-center w-full h-full bg-black">
      <canvas ref={canvasRef} className="border border-gray-300" />
    </div>
  );
};

export default BouncingBallSimulation;

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Byyyi耀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值