好吧,让我们试一试吧!我们将不得不按距离而不是按障碍对这些对象进行排序。我的意思是,对于两个对象 A 和 B,A 可以明显地阻碍 B,B 可以明显地阻碍 A,或者两者都不阻碍另一个。如果 A 阻碍了 B,我们将首先绘制 B,反之亦然。为了解决这个问题,我们需要能够判断 A 是否阻碍了 B,或者相反。
这是我想出的。我只是测试这个能力有限,所以可能仍然存在缺陷,但思考过程是合理的。
步骤 1. 将每个对象映射到其边界,保存原始对象以供以后使用:
let step1 = objects.map(o => ({
original: o,
xmin: o.x,
xmax: o.x + o.w,
ymin: o.y,
ymax: o.y + o.h
}));
第 2 步。将每个对象映射到两个角,当在它们之间画一条线时,会形成相机视野的最大障碍:
let step2 = step1.map(o => {
const [closestX, farthestX] = [o.xmin, o.xmax].sort((a, b) => Math.abs(camera.x - a) - Math.abs(camera.x - b));
const [closestY, farthestY] = [o.ymin, o.ymax].sort((a, b) => Math.abs(camera.y - a) - Math.abs(camera.y - b));
return {
original: o.original,
x1: closestX,
y1: o.xmin <= camera.x && camera.x <= o.xmax ? closestY : farthestY,
x2: o.ymin <= camera.y && camera.y <= o.ymax ? closestX : farthestX,
y2: closestY
};
});
第 3 步。对对象进行排序。从相机到一个对象的每个端点绘制一条线段。如果另一个对象的端点之间的线段相交,则另一个对象更近,必须在后面绘制。
let step3 = step2.sort((a, b) => {
const camSegmentA1 = {
x1: camera.x,
y1: camera.y,
x2: a.x1,
y2: a.y1
};
const camSegmentA2 = {
x1: camera.x,
y1: camera.y,
x2: a.x2,
y2: a.y2
};
const camSegmentB1 = {
x1: camera.x,
y1: camera.y,
x2: b.x1,
y2: b.y1
};
const camSegmentB2 = {
x1: camera.x,
y1: camera.y,
x2: b.x2,
y2: b.y2
};
// Intersection function taken from here: https://stackoverflow.com/a/24392281
function intersects(seg1, seg2) {
const a = seg1.x1, b = seg1.y1, c = seg1.x2, d = seg1.y2,
p = seg2.x1, q = seg2.y1, r = seg2.x2, s = seg2.y2;
const det = (c - a) * (s - q) - (r - p) * (d - b);
if (det === 0) {
return false;
} else {
lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / det;
gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / det;
return (0 < lambda && lambda < 1) && (0 < gamma && gamma < 1);
}
}
function squaredDistance(pointA, pointB) {
return Math.pow(pointB.x - pointA.x, 2) + Math.pow(pointB.y - pointA.y, 2);
}
if (intersects(camSegmentA1, b) || intersects(camSegmentA2, b)) {
return -1;
} else if (intersects(camSegmentB1, a) || intersects(camSegmentB2, a)) {
return 1;
} else {
return Math.max(squaredDistance(camera, {x: b.x1, y: b.y1}), squaredDistance(camera, {x: b.x2, y: b.y2})) - Math.max(squaredDistance(camera, {x: a.x1, y: a.y1}), squaredDistance(camera, {x: a.x2, y: a.y2}));
}
});
第 4 步。最后一步——取回原始对象,按从远到近的顺序排序:
let results = step3.map(o => o.original);
现在,把它们放在一起:
results = objects.map(o => {
const xmin = o.x,
xmax = o.x + o.w,
ymin = o.y,
ymax = o.y + o.h;
const [closestX, farthestX] = [xmin, xmax].sort((a, b) => Math.abs(camera.x - a) - Math.abs(camera.x - b));
const [closestY, farthestY] = [ymin, ymax].sort((a, b) => Math.abs(camera.y - a) - Math.abs(camera.y - b));
return {
original: o,
x1: closestX,
y1: xmin <= camera.x && camera.x <= xmax ? closestY : farthestY,
x2: ymin <= camera.y && camera.y <= ymax ? closestX : farthestX,
y2: closestY
};
}).sort((a, b) => {
const camSegmentA1 = {
x1: camera.x,
y1: camera.y,
x2: a.x1,
y2: a.y1
};
const camSegmentA2 = {
x1: camera.x,
y1: camera.y,
x2: a.x2,
y2: a.y2
};
const camSegmentB1 = {
x1: camera.x,
y1: camera.y,
x2: b.x1,
y2: b.y1
};
const camSegmentB2 = {
x1: camera.x,
y1: camera.y,
x2: b.x2,
y2: b.y2
};
// Intersection function taken from here: https://stackoverflow.com/a/24392281
function intersects(seg1, seg2) {
const a = seg1.x1, b = seg1.y1, c = seg1.x2, d = seg1.y2,
p = seg2.x1, q = seg2.y1, r = seg2.x2, s = seg2.y2;
const det = (c - a) * (s - q) - (r - p) * (d - b);
if (det === 0) {
return false;
} else {
lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / det;
gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / det;
return (0 < lambda && lambda < 1) && (0 < gamma && gamma < 1);
}
}
function squaredDistance(pointA, pointB) {
return Math.pow(pointB.x - pointA.x, 2) + Math.pow(pointB.y - pointA.y, 2);
}
if (intersects(camSegmentA1, b) || intersects(camSegmentA2, b)) {
return -1;
} else if (intersects(camSegmentB1, a) || intersects(camSegmentB2, a)) {
return 1;
}
return Math.max(squaredDistance(camera, {x: b.x1, y: b.y1}), squaredDistance(camera, {x: b.x2, y: b.y2})) - Math.max(squaredDistance(camera, {x: a.x1, y: a.y1}), squaredDistance(camera, {x: a.x2, y: a.y2}));
}).map(o => o.original);
让我知道这是否有效!