UNPKG

the-world-engine

Version:

three.js based, unity like game engine for browser

401 lines (364 loc) 12.6 kB
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; }