コードにかなり厳密に従って、 Randy Gaul の C++ Impulse Engineに基づいて円と多角形の間の衝突検出を実装しようとしましたが、アルゴリズムは決して true を返しません。
これがJSFiddleです。(便宜上、本文は HTML5 Canvas API を使用してレンダリングされます)
コードのスニペット (衝突検出のみ):
const circPoly = (a, b) => {
let data = {},
center = a.pos;
data.contacts = [];
center = b.mat.clone().trans().mult(center.clone().sub(b.pos));
let sep = -Number.MAX_VALUE,
faceNorm = 0;
for (let i = 0; i < b.verts2.length; ++i) {
let sep2 = b.norms[i].dot(center.clone().sub(b.verts2[i]));
if (sep2 > a.radius) return data;
if (sep2 > sep) { sep = sep2; faceNorm = i; }
}
let v1 = b.verts2[faceNorm],
v2 = b.verts2[faceNorm + 1 < b.verts2.length ? faceNorm + 1 : 0];
if (sep < 0.0001) {
data.depth = a.radius;
data.norm = b.mat.clone().mult(b.norms[faceNorm]).neg();
data.contacts[0] = data.norm.clone().vmult(a.pos.clone().sadd(a.radius));
return data;
}
let dot1 = center.clone().sub(v1).dot(v2.clone().sub(v1)),
dot2 = center.clone().sub(v2).dot(v1.clone().sub(v2));
data.depth = a.radius - sep;
if (dot1 <= 0) {
if (center.dist2(v1) > a.radius * a.radius) return data;
let norm = v1.clone().sub(center);
norm = b.mat.clone().mult(norm);
norm.norm();
data.norm = norm;
v1 = b.mat.clone().mult(v1.clone().add(b.pos));
data.contacts[0] = v1;
} else if (dot2 <= 0) {
if (center.dist2(v2) > a.radius * a.radius) return data;
let norm = v2.clone().sub(center);
norm = b.mat.clone().mult(norm);
norm.norm();
data.norm = norm;
v2 = b.mat.clone().mult(v2.clone().add(b.pos));
data.contacts[0] = v2;
} else {
let norm = b.norms[faceNorm];
if (center.clone().sub(v1).dot(norm) > a.radius) return data;
norm = b.mat.clone().mult(norm);
data.norm = norm.clone().neg();
data.contacts[0] = data.norm.clone().vmult(a.pos.clone().sadd(a.radius));
}
return data;
};
b.verts2
は、現実世界の座標でのポリゴンの頂点を指すことに注意してください。
Vector クラスに問題がないことはわかっていますが、変換行列の経験があまりないため、そのクラスがこれらのエラーの原因である可能性がありますが、そのコードはほぼ完全にから派生しています。 Impulse Engine も同様に動作するはずです。前述のように、衝突が実際に発生した場合でも、アルゴリズムは常に false を返します。ここで何が間違っていますか?初期のリターンを取り出してみましたが、負の座標を持つ接触点などの奇妙な結果が返されるだけで、明らかに正しくありません。
編集: ベクトル クラスの垂直関数をインパルス エンジンと同じように動作するように変更しました (どちらの方法も正しいですが、一方は時計回りでもう一方は反時計回りだと思います。反時計回りを反映するように頂点も変更しました)。残念ながら、それでもテストに失敗します。