【前端】HTML+JS 实现超燃小球分裂全过程

0 阅读4分钟

前言

🍊缘由

沉浸式体验:感受小球碰撞的震撼!

大家好,我是JavaDog程序狗

今天给大家整点好玩的——用纯前端实现圆形弹球无限分裂效果,看看你的电脑能否抗住!

正文

🎯主要目标

1. 搭建基础HTML结构

2. 设置基本样式

3. JavaScript实现步骤

4. 完整HTML代码

🍪目标讲解

一. 搭建小球分裂HTML结构

首先,得画个HTML容器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小球碰撞生成器</title>
    <style>
        /* 样式部分 */
    </style>
</head>
<body>
    <div id="container">
        <div id="circle"></div>
        <div id="counter">小球数量: 0</div>
    </div>
    <script>
        // JavaScript代码
    </script>
</body>
</html>

二. 设置基本样式

body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f0f0f0;
    font-family: Arial, sans-serif;
    overflow: hidden;
}

#container {
    position: relative;
    width: 500px;
    height: 500px;
}

#circle {
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    border: 2px solid #333;
    box-sizing: border-box;
    background-color: #fff;
}

.ball {
    position: absolute;
    border-radius: 50%;
    background-color: #3498db;
    transform: translate(-50%, -50%);
}

#counter {
    position: absolute;
    top: 20px;
    left: -56px;
    font-size: 18px;
    color: #333;
    background-color: rgba(255, 255, 255, 0.7);
    padding: 5px 10px;
    border-radius: 5px;
}

三. JavaScript实现步骤拆解

  • 3.1 初始化变量和元素
const container = document.getElementById('container');
const circle = document.getElementById('circle');
const counter = document.getElementById('counter');

const circleRadius = circle.offsetWidth / 2;
const ballRadius = 5;
const maxBalls = 3000;
let ballCount = 0;
const balls = [];
  • 3.2 创建初始小球
function createBall(x, y) {
    if (ballCount >= maxBalls) return;
    
    // 创建DOM元素
    const ballElement = document.createElement('div');
    ballElement.className = 'ball';
    ballElement.style.width = `${ballRadius * 2}px`;
    ballElement.style.height = `${ballRadius * 2}px`;
    container.appendChild(ballElement);
    
    // 随机速度方向
    const angle = Math.random() * Math.PI * 2;
    const speed = 2;
    const vx = Math.cos(angle) * speed;
    const vy = Math.sin(angle) * speed;
    
    // 存储小球数据
    const ball = {
        x,
        y,
        vx,
        vy,
        element: ballElement
    };
    
    balls.push(ball);
    ballCount++;
    counter.textContent = `小球数量: ${ballCount}`;
    
    // 如果是第一个小球,开始动画
    if (balls.length === 1) {
        animate();
    }
}

// 创建初始小球
createBall(circleRadius, circleRadius);
  • 3.3 实现动画循环
function animate() {
    if (ballCount >= maxBalls) return;
    
    for (let i = 0; i < balls.length; i++) {
        const ball = balls[i];
        
        // 移动小球
        ball.x += ball.vx;
        ball.y += ball.vy;
        
        // 检查碰撞
        const distanceFromCenter = Math.sqrt(
            Math.pow(ball.x - circleRadius, 2) + 
            Math.pow(ball.y - circleRadius, 2)
        );
        
        // 碰撞处理
        if (distanceFromCenter + ballRadius >= circleRadius) {
            // 反弹逻辑
            const angle = Math.atan2(ball.y - circleRadius, ball.x - circleRadius);
            const normalX = Math.cos(angle);
            const normalY = Math.sin(angle);
            const dotProduct = ball.vx * normalX + ball.vy * normalY;
            
            ball.vx = ball.vx - 2 * dotProduct * normalX;
            ball.vy = ball.vy - 2 * dotProduct * normalY;
            
            // 防止小球卡在边缘
            ball.x = circleRadius + (circleRadius - ballRadius - 1) * Math.cos(angle);
            ball.y = circleRadius + (circleRadius - ballRadius - 1) * Math.sin(angle);
            
            // 创建新小球
            if (ballCount < maxBalls) {
                createBall(ball.x, ball.y);
            }
        }
        
        // 更新DOM位置
        ball.element.style.left = `${ball.x}px`;
        ball.element.style.top = `${ball.y}px`;
    }
    
    requestAnimationFrame(animate);
}
  • 3.4 内存管理机制
// 定期清理异常小球
setInterval(() => {
    for (let i = balls.length - 1; i >= 0; i--) {
        const ball = balls[i];
        const distanceFromCenter = Math.sqrt(
            Math.pow(ball.x - circleRadius, 2) + 
            Math.pow(ball.y - circleRadius, 2)
        );
        
        // 移除超出边界的小球
        if (distanceFromCenter > circleRadius * 1.5) {
            ball.element.remove();
            balls.splice(i, 1);
            ballCount--;
            counter.textContent = `小球数量: ${ballCount}`;
        }
    }
}, 5000);

四. 完整步骤及全部HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>小球碰撞生成器</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
            font-family: Arial, sans-serif;
            overflow: hidden;
        }
        
        #container {
            position: relative;
            width: 500px;
            height: 500px;
        }
        
        #circle {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            border: 2px solid #333;
            box-sizing: border-box;
            background-color: #fff;
        }
        
        .ball {
            position: absolute;
            border-radius: 50%;
            background-color: #3498db;
            transform: translate(-50%, -50%);
        }
        
        #counter {
            position: absolute;
            top: 20px;
            left: -56px;
            font-size: 18px;
            color: #333;
            background-color: rgba(255, 255, 255, 0.7);
            padding: 5px 10px;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <div id="container">
        <div id="circle"></div>
        <div id="counter">小球数量: 0</div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const container = document.getElementById('container');
            const circle = document.getElementById('circle');
            const counter = document.getElementById('counter');
            
            const circleRadius = circle.offsetWidth / 2;
            const ballRadius = 5;
            const maxBalls = 3000;
            let ballCount = 0;
            
            // 存储所有小球的数组
            const balls = [];
            
            // 创建初始小球
            createBall(circleRadius, circleRadius);
            
            // 动画循环
            function animate() {
                if (ballCount >= maxBalls) {
                    return; // 达到最大数量后停止
                }
                
                // 更新所有小球位置
                for (let i = 0; i < balls.length; i++) {
                    const ball = balls[i];
                    
                    // 移动小球
                    ball.x += ball.vx;
                    ball.y += ball.vy;
                    
                    // 检查碰撞
                    const distanceFromCenter = Math.sqrt(
                        Math.pow(ball.x - circleRadius, 2) + 
                        Math.pow(ball.y - circleRadius, 2)
                    );
                    
                    // 如果碰到边缘
                    if (distanceFromCenter + ballRadius >= circleRadius) {
                        // 反弹
                        const angle = Math.atan2(ball.y - circleRadius, ball.x - circleRadius);
                        
                        // 计算反弹后的方向
                        const normalX = Math.cos(angle);
                        const normalY = Math.sin(angle);
                        
                        const dotProduct = ball.vx * normalX + ball.vy * normalY;
                        
                        ball.vx = ball.vx - 2 * dotProduct * normalX;
                        ball.vy = ball.vy - 2 * dotProduct * normalY;
                        
                        // 确保小球不会卡在边缘
                        ball.x = circleRadius + (circleRadius - ballRadius - 1) * Math.cos(angle);
                        ball.y = circleRadius + (circleRadius - ballRadius - 1) * Math.sin(angle);
                        
                        // 创建新小球
                        if (ballCount < maxBalls) {
                            createBall(ball.x, ball.y);
                        }
                    }
                    
                    // 更新DOM元素位置
                    ball.element.style.left = `${ball.x}px`;
                    ball.element.style.top = `${ball.y}px`;
                }
                
                requestAnimationFrame(animate);
            }
            
            // 创建新小球
            function createBall(x, y) {
                if (ballCount >= maxBalls) return;
                
                const ballElement = document.createElement('div');
                ballElement.className = 'ball';
                ballElement.style.width = `${ballRadius * 2}px`;
                ballElement.style.height = `${ballRadius * 2}px`;
                container.appendChild(ballElement);
                
                // 随机速度方向
                const angle = Math.random() * Math.PI * 2;
                const speed = 2;
                const vx = Math.cos(angle) * speed;
                const vy = Math.sin(angle) * speed;
                
                const ball = {
                    x,
                    y,
                    vx,
                    vy,
                    element: ballElement
                };
                
                balls.push(ball);
                ballCount++;
                counter.textContent = `小球数量: ${ballCount}`;
                
                // 如果这是第一个小球,开始动画
                if (balls.length === 1) {
                    animate();
                }
            }
            
            // 内存管理:定期清理超出边界的小球(虽然理论上不应该发生)
            setInterval(() => {
                for (let i = balls.length - 1; i >= 0; i--) {
                    const ball = balls[i];
                    const distanceFromCenter = Math.sqrt(
                        Math.pow(ball.x - circleRadius, 2) + 
                        Math.pow(ball.y - circleRadius, 2)
                    );
                    
                    // 如果小球超出边界很远(异常情况),移除它
                    if (distanceFromCenter > circleRadius * 1.5) {
                        ball.element.remove();
                        balls.splice(i, 1);
                        ballCount--;
                        counter.textContent = `小球数量: ${ballCount}`;
                    }
                }
            }, 5000);
        });
    </script>
</body>
</html>

总结

这篇文章介绍了如何用纯前端技术实现圆形弹球无限分裂效果。

从HTML结构搭建开始,创建了一个圆形容器和计数器;然后通过CSS设置基本样式,包括圆形边界和小球样式;JavaScript部分实现了小球创建、碰撞检测、反弹逻辑和无限分裂效果,并添加了内存管理机制防止性能问题。

最终效果是小球在圆形边界内不断碰撞分裂,数量指数级增长,直到达到上限3000个。

文章提供了完整的代码实现,适合前端开发者学习动画原理和性能优化技巧。

🍈猜你想问

如何与博主联系进行探讨

关注公众号【JavaDog程序狗】

公众号回复【入群】或者【加入】,便可成为【程序员学习交流摸鱼群】的一员,问题随便问,牛逼随便吹,目前群内已有超过380+个小伙伴啦!!!

2. 踩踩博主博客

javadog.net

里面有博主的私密联系方式呦 !,大家可以在里面留言,随意发挥,有问必答😘

🍯猜你喜欢

文章推荐

【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)

【规范】看看人家Git提交描述,那叫一个规矩

【项目实战】SpringBoot+uniapp+uview2打造H5+小程序+APP入门学习的聊天小项目

【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序

【模块分层】还不会SpringBoot项目模块分层?来这手把手教你!