基本实体:宇宙的基本实体是旋转的线段。线段属性:线段突然出现 → 逐渐缩短 → 消失。线段有颜色,颜色在拼接时色散,分配到相邻线段。线段会旋转,旋转速度与平移速度成反比,线段是局部时间的具象化:线段的存在与消失对应局部时间的产生与流逝。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>
1612

被折叠的 条评论
为什么被折叠?



