基于自制类弦理论的物理模拟

基本实体:宇宙的基本实体是旋转的线段。线段属性:线段突然出现 → 逐渐缩短 → 消失。线段有颜色,颜色在拼接时色散,分配到相邻线段。线段会旋转,旋转速度与平移速度成反比,线段是局部时间的具象化:线段的存在与消失对应局部时间的产生与流逝。2. 结构假设,拼接结构:线段通过离散拼接构成网络。拼接处有节点,节点约束旋转幅度。拼接必定扭曲。引力本质:线段网络的结构体现为引力,节点处的约束与色散传递对应引力相互作用,空间生成:线段碰到空间边界会使边界向外扩散,空间由此膨胀。3. 宇宙初始条件,初始宇宙是一个球体,球内每个整数坐标点产生一条线段。 线段消失后,同一位置会有新线段补充(守恒或循环)。<!DOCTYPE html>

<html lang="zh-CN">

<head>

    <meta charset="UTF-8">

    <title>自定义引力线段模拟器</title>

    <style>

        body { margin: 0; display: flex; flex-direction: column; align-items: center; background: #000; color: #fff; font-family: Arial; }

        #canvas { border: 2px solid #444; background: #111; }

        .controls { margin: 10px 0; display: flex; gap: 10px; align-items: center; }

        button { padding: 5px 15px; cursor: pointer; background: #333; color: #fff; border: 1px solid #666; }

        input { width: 100px; padding: 5px; background: #222; color: #fff; border: 1px solid #666; }

    </style>

</head>

<body>

    <div class="controls">

        <label>时间倍数:</label>

        <input type="number" id="timeScale" value="1" min="0.1" step="0.1">

        <button onclick="resetSim()">重置模拟</button>

    </div>

    <canvas id="canvas" width="800" height="600"></canvas>

 

    <script>

        const canvas = document.getElementById('canvas');

        const ctx = canvas.getContext('2d');

        let timeScale = 1;

        let segments = [];

        let polygons = [];

        const MAX_SEGMENTS = 200;

        const NODE_DIST = 15;

        const MAX_LIFE = 100; // 线段最大生命周期

 

        class Segment {

            constructor(x, y) {

                this.x = x; this.y = y;

                this.len = Math.random() * 30 + 20;

                this.angle = Math.random() * Math.PI * 2;

                this.angleSpeed = (Math.random() - 0.5) * 0.02;

                this.lenDecay = 0.01;

                this.color = `hsl(${Math.random() * 360}, 80%, 50%)`;

                this.nodes = [{x: this.x, y: this.y}, this.getEndPoint()];

                this.life = MAX_LIFE; // 新增:生命周期

            }

 

            getEndPoint() {

                return {

                    x: this.x + Math.cos(this.angle) * this.len,

                    y: this.y + Math.sin(this.angle) * this.len

                };

            }

 

            update() {

                this.angle += this.angleSpeed * timeScale;

                this.len -= this.lenDecay * timeScale;

                this.life -= 1 * timeScale; // 生命周期随时间减少

                // 生命周期耗尽或长度过短则重置

                if (this.life <= 0 || this.len < 5) {

                    this.len = Math.random() * 20 + 10;

                    this.life = MAX_LIFE;

                    this.color = `hsl(${Math.random() * 360}, 80%, 50%)`;

                }

                this.nodes[1] = this.getEndPoint();

                // 颜色亮度随生命周期调整

                const hue = parseInt(this.color.match(/hsl\((\d+)/)[1]);

                const alpha = this.life / MAX_LIFE; // 透明度与生命周期正相关

                this.displayColor = `hsla(${hue}, 80%, 50%, ${alpha})`;

            }

 

            draw() {

                // 线段颜色使用带透明度的displayColor,不再是黑色

                ctx.beginPath();

                ctx.moveTo(this.nodes[0].x, this.nodes[0].y);

                ctx.lineTo(this.nodes[1].x, this.nodes[1].y);

                ctx.strokeStyle = this.displayColor;

                ctx.lineWidth = 2;

                ctx.stroke();

                // 节点绘制

                this.nodes.forEach(node => {

                    ctx.beginPath();

                    ctx.arc(node.x, node.y, 3, 0, Math.PI * 2);

                    ctx.fillStyle = `rgba(255,255,255,${this.life/MAX_LIFE})`;

                    ctx.fill();

                });

            }

        }

 

        function checkCollisionAndMerge() {

            const nodeMap = new Map();

            segments.forEach((seg, segIdx) => {

                seg.nodes.forEach((node, nodeIdx) => {

                    const key = `${Math.round(node.x / NODE_DIST)}_${Math.round(node.y / NODE_DIST)}`;

                    if (!nodeMap.has(key)) nodeMap.set(key, []);

                    nodeMap.get(key).push({seg, node, segIdx, nodeIdx});

                });

            });

            for (const [key, nodes] of nodeMap) {

                if (nodes.length < 2) continue;

                const vertices = nodes.map(item => item.node);

                const uniqueVerts = vertices.filter((v, i) => 

                    vertices.findIndex(u => u.x === v.x && u.y === v.y) === i

                );

                if (uniqueVerts.length >= 3) {

                    // 多边形透明度随线段平均生命周期调整

                    const avgLife = nodes.reduce((sum, item) => sum + item.seg.life, 0) / nodes.length;

                    const polyColor = nodes[0].seg.displayColor.replace(/[^,]+(?=\))/, avgLife/MAX_LIFE);

                    polygons.push({ vertices: [...uniqueVerts], color: polyColor });

                    nodes.forEach(item => item.seg.angleSpeed *= 0.5);

                }

            }

        }

 

        function drawPolygons() {

            polygons.forEach(poly => {

                ctx.beginPath();

                ctx.moveTo(poly.vertices[0].x, poly.vertices[0].y);

                poly.vertices.forEach(v => ctx.lineTo(v.x, v.y));

                ctx.closePath();

                ctx.fillStyle = poly.color.replace('50%,', '20%,');

                 ctx.strokeStyle = poly.color;

                 ctx.lineWidth = 1;

                 ctx.fill();

                 ctx.stroke();

             });

             if (polygons.length > 50) polygons.shift();

         }

         function initSim() {

             segments = [];

             polygons = [];

             for (let i = 0; i < MAX_SEGMENTS; i++) {

                 const x = Math.floor(Math.random() * (canvas.width - 40)) + 20;

                 const y = Math.floor(Math.random() * (canvas.height - 40)) + 20;

                 segments.push(new Segment(x, y));

             }

         }

         function resetSim() {

             initSim();

         }

         function animate() {

             ctx.clearRect(0, 0, canvas.width, canvas.height);

             timeScale = parseFloat(document.getElementById('timeScale').value) || 1;

             segments.forEach(seg => seg.update());

             segments.forEach(seg => seg.draw());

             checkCollisionAndMerge();

             drawPolygons();

             requestAnimationFrame(animate);

         }

         window.addEventListener('resize', () => {

             canvas.width = Math.min(window.innerWidth - 40, 800);

             canvas.height = Math.min(window.innerHeight - 100, 600);

         });

         initSim();

         animate();

     </script>

 </body>

 </html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值