p5.js:模拟 n个彩色小球在一个3D大球体内部弹跳

向 豆包 提问:编写一个 p5.js 脚本,模拟 42 个彩色小球在一个3D大球体内部弹跳。每个小球都应留下一条逐渐消失的轨迹。大球体应缓慢旋转,并显示透明的轮廓线。请确保实现适当的碰撞检测,使小球保持在球体内部。

cd p5-demo

copy .\node_modules\p5\lib\p5.min.js .

编写 p5_3d_42_balls.html 如下

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D Bouncing Balls in Sphere</title>
    <script src="p5.min.js"></script>
</head>

<body>
<script>
    let balls = [];
    let sphereRadius = 200;
    let rotationSpeed = 0.01;

    function setup() {
        createCanvas(800, 600, WEBGL);
        for (let i = 0; i < 42; i++) {
            balls.push(new Ball());
        }
    }

    function draw() {
        background(0);
        rotateX(frameCount * rotationSpeed);
        rotateY(frameCount * rotationSpeed);

        // 绘制大球体
        stroke(255, 100);
        noFill();
        sphere(sphereRadius);

        // 更新并绘制小球
        for (let ball of balls) {
            ball.update();
            ball.display();
        }
    }

    class Ball {
        constructor() {
            this.pos = p5.Vector.random3D().mult(random(0, sphereRadius));
            this.vel = p5.Vector.random3D().mult(random(1, 3));
            this.color = color(random(255), random(255), random(255));
            this.trail = [];
            this.trailLength = 20;
        }

        update() {
            this.pos.add(this.vel);

            // 碰撞检测
            let distanceToCenter = this.pos.mag();
            if (distanceToCenter > sphereRadius) {
                let normal = this.pos.copy().normalize();
                this.vel.reflect(normal);
                // 确保小球回到球体内
                this.pos = normal.mult(sphereRadius - 0.1); 
            }

            // 更新轨迹
            this.trail.push(this.pos.copy());
            if (this.trail.length > this.trailLength) {
                this.trail.shift();
            }
        }

        display() {
            // 绘制轨迹
            for (let i = 0; i < this.trail.length; i++) {
                let alpha = map(i, 0, this.trail.length, 255, 0);
                stroke(this.color.levels[0], this.color.levels[1], this.color.levels[2], alpha);
                if (i > 0) {
                    line(this.trail[i - 1].x, this.trail[i - 1].y, this.trail[i - 1].z, this.trail[i].x, this.trail[i].y, this.trail[i].z);
                }
            }

            // 绘制小球
            fill(this.color);
            noStroke();
            push();
            translate(this.pos.x, this.pos.y, this.pos.z);
            sphere(5);
            pop();
        }
    }
</script>
</body>
</html>

双击打开 p5_3d_42_balls.html


交互式分形树

  • 描述: 创建一个分形树,用户可以通过鼠标或键盘控制树的生长角度、分支长度等参数。

  • 编写 p5_branch.html 如下

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>p5 branch Example</title>
   <script src="p5.min.js"></script>
</head>
<body>
<script>
// 创建分形树,用户可以通过鼠标控制树的生长角度、分支长度等参数。
  function setup() {
    createCanvas(800, 600);
    angleMode(DEGREES);
  }
  
  function draw() {
    background(50);
    stroke(255);
    translate(width/2, height);
    branch(map(mouseX, 0, width, 50, 150));
  }
  
  function branch(len) {
    line(0, 0, 0, -len);
    translate(0, -len);
  
    if (len > 4) {
      push();
      rotate(map(mouseY, 0, height, 20, 60));
      branch(len * 0.67);
      pop();
      push();
      rotate(-map(mouseY, 0, height, 20, 60));
      branch(len * 0.67);
      pop();
    }
  }
</script>
</body>
</html>

双击打开 p5_branch.html


动态波形生成器

  • 描述: 创建一个动态波形,用户可以通过鼠标或键盘控制波形的频率、振幅或颜色。

  • 编写 p5_wave.html 如下

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>p5 wave Example</title>
   <script src="p5.min.js"></script>
</head>
<body>
<script>
  let angle = 0;
  let amplitude = 100;
  let frequency = 0.02;
  
  function setup() {
    createCanvas(windowWidth, windowHeight);
  }
  
  function draw() {
    background(0);
    noFill();
    stroke(255);
    strokeWeight(2);
  
    beginShape();
    for (let x = 0; x < width; x += 10) {
      let y = height / 2 + sin(angle + x * frequency) * amplitude;
      vertex(x, y);
    }
    endShape();
  
    angle += 0.05;
  }
  
  function mouseMoved() {
    amplitude = map(mouseY, 0, height, 50, 200);
    frequency = map(mouseX, 0, width, 0.01, 0.1);
  }
</script>
</body>
</html>

双击打开 p5_wave.html

相关推荐
red润17 分钟前
JavaScript 二维数组初始化:为什么 fill([]) 是个大坑?
前端·javascript·代码规范
JohnYan25 分钟前
Bun技术评估 - 02 Startup
javascript·后端·bun
满分观察网友z31 分钟前
揭秘 Intersection Observer:让你的网页“活”起来!
前端·javascript
xzboss1 小时前
DOM转矢量PDF
前端·javascript
萌萌哒草头将军1 小时前
🏖️ 舒服,原来写代码还可以这么享受😎!沉浸式敲代码神器!
javascript·vue.js·react.js
waterHBO2 小时前
改写自己的浏览器插件工具 myChromeTools
javascript
FogLetter2 小时前
JavaScript 的历史:从网页点缀到改变世界的编程语言
前端·javascript·http
邹荣乐2 小时前
Vue.js项目中全面解析定义全局变量的常用方法与技巧
前端·javascript·vue.js
挽淚2 小时前
从原生JS到现代前端框架:提升开发效率的转变
javascript·vue.js
前端小巷子2 小时前
JS中的 eval
前端·javascript·面试