the-world-engine
Version:
three.js based, unity like game engine for browser
401 lines (364 loc) • 12.6 kB
JavaScript
import { b2_maxManifoldPoints } from "../common/b2_settings.js";
import { b2Min, b2Vec2, b2Rot, b2Transform } from "../common/b2_math.js";
import { b2ContactFeatureType, b2ContactID } from "./b2_collision.js";
import { b2ManifoldType, b2ClipVertex, b2ClipSegmentToLine } from "./b2_collision.js";
const b2CollideEdgeAndCircle_s_Q = new b2Vec2;
const b2CollideEdgeAndCircle_s_e = new b2Vec2;
const b2CollideEdgeAndCircle_s_d = new b2Vec2;
const b2CollideEdgeAndCircle_s_e1 = new b2Vec2;
const b2CollideEdgeAndCircle_s_e2 = new b2Vec2;
const b2CollideEdgeAndCircle_s_P = new b2Vec2;
const b2CollideEdgeAndCircle_s_n = new b2Vec2;
const b2CollideEdgeAndCircle_s_id = new b2ContactID;
export function b2CollideEdgeAndCircle(e, o, n, t, c) {
e.pointCount = 0;
const s = b2Transform.MulTXV(n, b2Transform.MulXV(c, t.m_p, b2Vec2.s_t0), b2CollideEdgeAndCircle_s_Q);
const b = o.m_vertex1;
const l = o.m_vertex2;
const i = b2Vec2.SubVV(l, b, b2CollideEdgeAndCircle_s_e);
const d = b2CollideEdgeAndCircle_s_n.Set(i.y, -i.x);
const r = b2Vec2.DotVV(d, b2Vec2.SubVV(s, b, b2Vec2.s_t0));
const _ = o.m_oneSided;
if (_ && r < 0) {
return;
}
const C = b2Vec2.DotVV(i, b2Vec2.SubVV(l, s, b2Vec2.s_t0));
const g = b2Vec2.DotVV(i, b2Vec2.SubVV(s, b, b2Vec2.s_t0));
const a = o.m_radius + t.m_radius;
const V = b2CollideEdgeAndCircle_s_id;
V.cf.indexB = 0;
V.cf.typeB = b2ContactFeatureType.e_vertex;
if (g <= 0) {
const n = b;
const c = b2Vec2.SubVV(s, n, b2CollideEdgeAndCircle_s_d);
const l = b2Vec2.DotVV(c, c);
if (l > a * a) {
return;
}
if (o.m_oneSided) {
const e = o.m_vertex0;
const n = b;
const t = b2Vec2.SubVV(n, e, b2CollideEdgeAndCircle_s_e1);
const c = b2Vec2.DotVV(t, b2Vec2.SubVV(n, s, b2Vec2.s_t0));
if (c > 0) {
return;
}
}
V.cf.indexA = 0;
V.cf.typeA = b2ContactFeatureType.e_vertex;
e.pointCount = 1;
e.type = b2ManifoldType.e_circles;
e.localNormal.SetZero();
e.localPoint.Copy(n);
e.points[0].id.Copy(V);
e.points[0].localPoint.Copy(t.m_p);
return;
}
if (C <= 0) {
const n = l;
const c = b2Vec2.SubVV(s, n, b2CollideEdgeAndCircle_s_d);
const b = b2Vec2.DotVV(c, c);
if (b > a * a) {
return;
}
if (o.m_oneSided) {
const e = o.m_vertex3;
const n = l;
const t = b2Vec2.SubVV(e, n, b2CollideEdgeAndCircle_s_e2);
const c = b2Vec2.DotVV(t, b2Vec2.SubVV(s, n, b2Vec2.s_t0));
if (c > 0) {
return;
}
}
V.cf.indexA = 1;
V.cf.typeA = b2ContactFeatureType.e_vertex;
e.pointCount = 1;
e.type = b2ManifoldType.e_circles;
e.localNormal.SetZero();
e.localPoint.Copy(n);
e.points[0].id.Copy(V);
e.points[0].localPoint.Copy(t.m_p);
return;
}
const p = b2Vec2.DotVV(i, i);
const f = b2CollideEdgeAndCircle_s_P;
f.x = 1 / p * (C * b.x + g * l.x);
f.y = 1 / p * (C * b.y + g * l.y);
const y = b2Vec2.SubVV(s, f, b2CollideEdgeAndCircle_s_d);
const E = b2Vec2.DotVV(y, y);
if (E > a * a) {
return;
}
if (r < 0) {
d.Set(-d.x, -d.y);
}
d.Normalize();
V.cf.indexA = 0;
V.cf.typeA = b2ContactFeatureType.e_face;
e.pointCount = 1;
e.type = b2ManifoldType.e_faceA;
e.localNormal.Copy(d);
e.localPoint.Copy(b);
e.points[0].id.Copy(V);
e.points[0].localPoint.Copy(t.m_p);
}
var b2EPAxisType;
(function(e) {
e[e["e_unknown"] = 0] = "e_unknown";
e[e["e_edgeA"] = 1] = "e_edgeA";
e[e["e_edgeB"] = 2] = "e_edgeB";
})(b2EPAxisType || (b2EPAxisType = {}));
class b2EPAxis {
constructor() {
this.normal = new b2Vec2;
this.type = b2EPAxisType.e_unknown;
this.index = 0;
this.separation = 0;
}
}
class b2TempPolygon {
constructor() {
this.vertices = [];
this.normals = [];
this.count = 0;
}
}
class b2ReferenceFace {
constructor() {
this.i1 = 0;
this.i2 = 0;
this.v1 = new b2Vec2;
this.v2 = new b2Vec2;
this.normal = new b2Vec2;
this.sideNormal1 = new b2Vec2;
this.sideOffset1 = 0;
this.sideNormal2 = new b2Vec2;
this.sideOffset2 = 0;
}
}
const b2ComputeEdgeSeparation_s_axis = new b2EPAxis;
const b2ComputeEdgeSeparation_s_axes = [ new b2Vec2, new b2Vec2 ];
function b2ComputeEdgeSeparation(e, o, n) {
const t = b2ComputeEdgeSeparation_s_axis;
t.type = b2EPAxisType.e_edgeA;
t.index = -1;
t.separation = -Number.MAX_VALUE;
t.normal.SetZero();
const c = b2ComputeEdgeSeparation_s_axes;
c[0].Copy(n);
c[1].Copy(n).SelfNeg();
for (let n = 0; n < 2; ++n) {
let s = Number.MAX_VALUE;
for (let t = 0; t < e.count; ++t) {
const b = b2Vec2.DotVV(c[n], b2Vec2.SubVV(e.vertices[t], o, b2Vec2.s_t0));
if (b < s) {
s = b;
}
}
if (s > t.separation) {
t.index = n;
t.separation = s;
t.normal.Copy(c[n]);
}
}
return t;
}
const b2ComputePolygonSeparation_s_axis = new b2EPAxis;
const b2ComputePolygonSeparation_s_n = new b2Vec2;
function b2ComputePolygonSeparation(e, o, n) {
const t = b2ComputePolygonSeparation_s_axis;
t.type = b2EPAxisType.e_unknown;
t.index = -1;
t.separation = -Number.MAX_VALUE;
t.normal.SetZero();
for (let c = 0; c < e.count; ++c) {
const s = b2Vec2.NegV(e.normals[c], b2ComputePolygonSeparation_s_n);
const b = b2Vec2.DotVV(s, b2Vec2.SubVV(e.vertices[c], o, b2Vec2.s_t0));
const l = b2Vec2.DotVV(s, b2Vec2.SubVV(e.vertices[c], n, b2Vec2.s_t0));
const i = b2Min(b, l);
if (i > t.separation) {
t.type = b2EPAxisType.e_edgeB;
t.index = c;
t.separation = i;
t.normal.Copy(s);
}
}
return t;
}
const b2CollideEdgeAndPolygon_s_xf = new b2Transform;
const b2CollideEdgeAndPolygon_s_centroidB = new b2Vec2;
const b2CollideEdgeAndPolygon_s_edge1 = new b2Vec2;
const b2CollideEdgeAndPolygon_s_normal1 = new b2Vec2;
const b2CollideEdgeAndPolygon_s_edge0 = new b2Vec2;
const b2CollideEdgeAndPolygon_s_normal0 = new b2Vec2;
const b2CollideEdgeAndPolygon_s_edge2 = new b2Vec2;
const b2CollideEdgeAndPolygon_s_normal2 = new b2Vec2;
const b2CollideEdgeAndPolygon_s_tempPolygonB = new b2TempPolygon;
const b2CollideEdgeAndPolygon_s_ref = new b2ReferenceFace;
const b2CollideEdgeAndPolygon_s_clipPoints = [ new b2ClipVertex, new b2ClipVertex ];
const b2CollideEdgeAndPolygon_s_clipPoints1 = [ new b2ClipVertex, new b2ClipVertex ];
const b2CollideEdgeAndPolygon_s_clipPoints2 = [ new b2ClipVertex, new b2ClipVertex ];
export function b2CollideEdgeAndPolygon(e, o, n, t, c) {
e.pointCount = 0;
const s = b2Transform.MulTXX(n, c, b2CollideEdgeAndPolygon_s_xf);
const b = b2Transform.MulXV(s, t.m_centroid, b2CollideEdgeAndPolygon_s_centroidB);
const l = o.m_vertex1;
const i = o.m_vertex2;
const d = b2Vec2.SubVV(i, l, b2CollideEdgeAndPolygon_s_edge1);
d.Normalize();
const r = b2CollideEdgeAndPolygon_s_normal1.Set(d.y, -d.x);
const _ = b2Vec2.DotVV(r, b2Vec2.SubVV(b, l, b2Vec2.s_t0));
const C = o.m_oneSided;
if (C && _ < 0) {
return;
}
const g = b2CollideEdgeAndPolygon_s_tempPolygonB;
g.count = t.m_count;
for (let e = 0; e < t.m_count; ++e) {
if (g.vertices.length <= e) {
g.vertices.push(new b2Vec2);
}
if (g.normals.length <= e) {
g.normals.push(new b2Vec2);
}
b2Transform.MulXV(s, t.m_vertices[e], g.vertices[e]);
b2Rot.MulRV(s.q, t.m_normals[e], g.normals[e]);
}
const a = t.m_radius + o.m_radius;
const V = b2ComputeEdgeSeparation(g, l, r);
if (V.separation > a) {
return;
}
const p = b2ComputePolygonSeparation(g, l, i);
if (p.separation > a) {
return;
}
const f = .98;
const y = .001;
let E;
if (p.separation - a > f * (V.separation - a) + y) {
E = p;
} else {
E = V;
}
if (C) {
const e = b2Vec2.SubVV(l, o.m_vertex0, b2CollideEdgeAndPolygon_s_edge0);
e.Normalize();
const n = b2CollideEdgeAndPolygon_s_normal0.Set(e.y, -e.x);
const t = b2Vec2.CrossVV(e, d) >= 0;
const c = b2Vec2.SubVV(o.m_vertex3, i, b2CollideEdgeAndPolygon_s_edge2);
c.Normalize();
const s = b2CollideEdgeAndPolygon_s_normal2.Set(c.y, -c.x);
const b = b2Vec2.CrossVV(d, c) >= 0;
const r = .1;
const _ = b2Vec2.DotVV(E.normal, d) <= 0;
if (_) {
if (t) {
if (b2Vec2.CrossVV(E.normal, n) > r) {
return;
}
} else {
E = V;
}
} else {
if (b) {
if (b2Vec2.CrossVV(s, E.normal) > r) {
return;
}
} else {
E = V;
}
}
}
const P = b2CollideEdgeAndPolygon_s_clipPoints;
const A = b2CollideEdgeAndPolygon_s_ref;
if (E.type === b2EPAxisType.e_edgeA) {
e.type = b2ManifoldType.e_faceA;
let o = 0;
let n = b2Vec2.DotVV(E.normal, g.normals[0]);
for (let e = 1; e < g.count; ++e) {
const t = b2Vec2.DotVV(E.normal, g.normals[e]);
if (t < n) {
n = t;
o = e;
}
}
const t = o;
const c = t + 1 < g.count ? t + 1 : 0;
P[0].v.Copy(g.vertices[t]);
P[0].id.cf.indexA = 0;
P[0].id.cf.indexB = t;
P[0].id.cf.typeA = b2ContactFeatureType.e_face;
P[0].id.cf.typeB = b2ContactFeatureType.e_vertex;
P[1].v.Copy(g.vertices[c]);
P[1].id.cf.indexA = 0;
P[1].id.cf.indexB = c;
P[1].id.cf.typeA = b2ContactFeatureType.e_face;
P[1].id.cf.typeB = b2ContactFeatureType.e_vertex;
A.i1 = 0;
A.i2 = 1;
A.v1.Copy(l);
A.v2.Copy(i);
A.normal.Copy(E.normal);
A.sideNormal1.Copy(d).SelfNeg();
A.sideNormal2.Copy(d);
} else {
e.type = b2ManifoldType.e_faceB;
P[0].v.Copy(i);
P[0].id.cf.indexA = 1;
P[0].id.cf.indexB = E.index;
P[0].id.cf.typeA = b2ContactFeatureType.e_vertex;
P[0].id.cf.typeB = b2ContactFeatureType.e_face;
P[1].v.Copy(l);
P[1].id.cf.indexA = 0;
P[1].id.cf.indexB = E.index;
P[1].id.cf.typeA = b2ContactFeatureType.e_vertex;
P[1].id.cf.typeB = b2ContactFeatureType.e_face;
A.i1 = E.index;
A.i2 = A.i1 + 1 < g.count ? A.i1 + 1 : 0;
A.v1.Copy(g.vertices[A.i1]);
A.v2.Copy(g.vertices[A.i2]);
A.normal.Copy(g.normals[A.i1]);
A.sideNormal1.Set(A.normal.y, -A.normal.x);
A.sideNormal2.Copy(A.sideNormal1).SelfNeg();
}
A.sideOffset1 = b2Vec2.DotVV(A.sideNormal1, A.v1);
A.sideOffset2 = b2Vec2.DotVV(A.sideNormal2, A.v2);
const u = b2CollideEdgeAndPolygon_s_clipPoints1;
const m = b2CollideEdgeAndPolygon_s_clipPoints2;
let T;
T = b2ClipSegmentToLine(u, P, A.sideNormal1, A.sideOffset1, A.i1);
if (T < b2_maxManifoldPoints) {
return;
}
T = b2ClipSegmentToLine(m, u, A.sideNormal2, A.sideOffset2, A.i2);
if (T < b2_maxManifoldPoints) {
return;
}
if (E.type === b2EPAxisType.e_edgeA) {
e.localNormal.Copy(A.normal);
e.localPoint.Copy(A.v1);
} else {
e.localNormal.Copy(t.m_normals[A.i1]);
e.localPoint.Copy(t.m_vertices[A.i1]);
}
let w = 0;
for (let o = 0; o < b2_maxManifoldPoints; ++o) {
const n = b2Vec2.DotVV(A.normal, b2Vec2.SubVV(m[o].v, A.v1, b2Vec2.s_t0));
if (n <= a) {
const n = e.points[w];
if (E.type === b2EPAxisType.e_edgeA) {
b2Transform.MulTXV(s, m[o].v, n.localPoint);
n.id.Copy(m[o].id);
} else {
n.localPoint.Copy(m[o].v);
n.id.cf.typeA = m[o].id.cf.typeB;
n.id.cf.typeB = m[o].id.cf.typeA;
n.id.cf.indexA = m[o].id.cf.indexB;
n.id.cf.indexB = m[o].id.cf.indexA;
}
++w;
}
}
e.pointCount = w;
}