我正在绘制100个不同大小的圆圈到画布,它们不能重叠.这些圆圈也将是从右到左的动画(当它们离开屏幕时环回到画布的右边缘),并且还会有一些垂直的“bob”,它们也不能与任何其他圆形重叠.
以下是我目前正在尝试的,这似乎是锁定浏览器.我循环遍历圆圈集合并执行detectOverlap()函数,并将圆圈集合传递给它.
然后,detectOverlap()函数循环遍历圆圈,执行以下检查:
detectOverlap: function (bubblesArr) {
while (true) {
var hit = 0;
for (var i=0; i<bubblesArr.length; i++) {
var circle = bubblesArr[i];
var dx = this._x - circle._x;
var dy = this._y - circle._y;
var rr = this._radius + circle._radius;
if (dx * dx + dy * dy < rr * rr) {
hit++;
}
}
if (hit == 0) {
break; // didn't overlap, break out of while loop
}
// if we didn't break then there was an overlap somewhere. calc again.
this._x = Math.round(Math.random() * this.stage.getWidth());
this._y = Math.round(Math.random() * this.stage.getHeight());
}
},
如果命中== 0,循环中断,我们假设没有重叠.否则,我们随机计算新的X / Y位置并重新启动该过程.
这似乎效率低下.这样做的任何高效提示?
canvas类(入口点):
这个类是“舞台”,它构建了气泡对象,然后将它们添加到画布中.
var $container;
var listData;
var bubbles = [];
function init(l, c) {
$container = c;
listData = l;
// this just draws the canvas. full-width + 500px tall.
var stage = new Konva.Stage({
container: $container.selector,
width: window.innerWidth,
height: 500
});
// this creates the drawing layer where the bubbles will live
layer = new Konva.Layer();
// create an instance of the Bubble class for each element in the list.
for (var i=0; i<listData.length; i++) {
bubbles[i] = new celebApp.Bubble.Bubble(listData[i], stage);
}
/** TODO:::: FIGURE OUT COLLISION DETECTION */
for (var i=0; i<bubbles.length; i++) {
bubbles[i].detectOverlap(bubbles);
}
// create the Konva representation for our generated objects
for (var i=0; i<bubbles.length; i++) {
var b = bubbles[i];
layer.add(new Konva.Circle({
x: b._x,
y: b._y,
radius: b._radius,
fill: b._fill,
stroke: b._stroke,
strokeWidth: b._strokeWidth,
}));
}
// add the layer to the stage
stage.add(layer);
}
泡泡类:
这是表示绘制到屏幕的数据的类.我们需要确保这些对象中没有一个彼此重叠.
var Bubble = function (listData, stage) {
this.stage = stage;
this._x = Math.round(Math.random() * stage.getWidth()),
this._y = Math.round(Math.random() * stage.getHeight()),
this._radius = Math.round(Math.random() * 80);
this._fill = 'red';
this._stroke = 'black';
this._strokeWidth = 4;
this._speed = 3;
};
Bubble.prototype = {
detectOverlap: function (bubblesArr) {
while (true) {
var hit = 0;
for (var i=0; i<bubblesArr.length; i++) {
var circle = bubblesArr[i];
var dx = this._x - circle._x;
var dy = this._y - circle._y;
var rr = this._radius + circle._radius;
if (dx * dx + dy * dy < rr * rr) {
hit++;
}
}
if (hit == 0) {
break; // didn't overlap
}
this._x = Math.round(Math.random() * this.stage.getWidth());
this._y = Math.round(Math.random() * this.stage.getHeight());
}
},
};
编辑:刚刚根据@MarcB的评论尝试了这个 – 但是,浏览器似乎仍然锁定.是否会导致性能瓶颈,但100个项目都在运行自己的while()循环?
for (var i=0; i<bubblesArr.length; i++) {
var circle = bubblesArr[i];
var combinedRadius = Math.abs(circle._radius + this._radius);
var distance = Math.abs(this._x - circle._x);
if (distance <= combinedRadius) {
hit++;
}
}
最佳答案 这看起来像一个简单的bug.您初始化一个圆圈列表.然后,对于列表中的每个圆圈,您可以计算列表中有多少个圆圈重叠.如果找到重叠,则移动圆圈并重试.
但是每个圆圈都会在列表中找到它并发现它自身重叠.你移动它,同样的事情发生.这是一个永无止境的无限循环.
您需要让每个圆圈查找与其重叠的自身以外的圆圈.
从算法上讲,您可以使用四叉树等智能数据结构来改善此重叠检测.这样您就可以立即找到所有圆圈,这些圆圈的中心位于圆圈的一个小框内,并让您找到重叠的圆圈.
但是,如果性能是一个问题,就没有必要努力工作.而是通过x坐标对圆圈进行排序,绘制相距5的垂直条带,然后将每个圆圈放入与其相交的所有条带中.现在,对于每个圆圈,您只需搜索它相交的所有波段.
效率的下一步将是通过y坐标对每个波段进行排序,以便您可以在该波段中进行二分搜索,以找到与波段相交的所有圆,其距离可能与您的圆相交.但是这些乐队通常应该接近空,所以这并不是一场胜利.