这个能够生成我们的齿轮啮合网络的方法应该是这样的:
使用这个方法你可以生成互相啮合的齿轮的整个网络,如下所示:
See the Pen GWbbpO by molunerfinn ( @molunerfinn ) on CodePen .
以下是冲突检测查询的一个可能的实现:
function detectCollision(newGear, neighbor) { var result = false; var that = this; this.gears.forEach(function (gear) { var dist = distance(gear.x, gear.y, newGear.x, newGear.y); if (dist < gear.radius + newGear.radius + 2 * that.connectionRadius + 5 && neighbor != gear) { result = true; } }); return result; }
可以使用类似的方法实现冲突的近邻查询。但是你应该注意一个细节,那就是我们必须避免大齿轮以很大的角速度旋转。否则一些齿轮在动画的帧与帧之间转动得太多,将会形成混乱的情况。
下一个逻辑步骤就是增加我们模型的深度。我们可以随机放置几层,但是这样会让它们看起来不自然。这些层可以通过一些共同的转轴来进行交互。我们可以通过从一层到另一层复制圆点和角速度来模拟这种效果。
function tryAddFromLayer(x, y, legs, angularSpeed) { // 通过所给的参数创建一个新的齿轮 var newGear = new Gear(x, y, this.connectionRadius, legs, this.fillStyle, this.strokeStyle); if (!this.detectCollision(newGear, null) // 别忘了确保它不会转的太快 && this.minFps * angularSpeed * newGear.radius < newGear.diameter ) { newGear.angularSpeed = angularSpeed; // 调整转速 this.gears.push(newGear); // 添加到图层 } }
现在,我们能够堆积从以前生成的层中挑选齿轮,并从中生成新的齿轮:
function addFromLayer(layers, options, maxR) { var retries = 0; while (this.gears.length < options.maxGears && retries < options.qouta) { // 选择一个随机的层 var layerIdx = Math.floor((options.generator.random() * layers.length)); var layer = layers[layerIdx]; // 从这个层里挑选一个随机的齿轮 var gearIdx = Math.floor((options.generator.random() * layer.gears.length)); var gear = layer.gears[gearIdx]; // 随机选择这个齿轮的齿数 var legs = options.minLegs + Math.floor((options.generator.random() * (maxLegsFromRadius(maxR, this.connectionRadius) - options.minLegs))); // 向当前的图层里添加结果 this.tryAddFromLayer(gear.x, gear.y, legs, gear.angularSpeed); retries++; } }
这是算法的一个可能的输出:
See the Pen dvBBZz by molunerfinn ( @molunerfinn ) on CodePen .
所有的源码你都可以通过查看上面的 codepen 的源码以及github 仓库源码 获取