UNPKG

planck-js

Version:

2D physics engine for JavaScript/HTML5 game development

178 lines (151 loc) 5.56 kB
/* * Copyright (c) 2016 Ali Shakiba http://shakiba.me/planck.js * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ var create = require('../util/create'); var Settings = require('../Settings'); var Shape = require('../Shape'); var Contact = require('../Contact'); var Manifold = require('../Manifold'); var Math = require('../common/Math'); var Transform = require('../common/Transform'); var Vec2 = require('../common/Vec2'); var Rot = require('../common/Rot'); var EdgeShape = require('./EdgeShape'); var ChainShape = require('./ChainShape'); var CircleShape = require('./CircleShape'); Contact.AddType(EdgeShape.TYPE, CircleShape.TYPE, EdgeCircleContact); Contact.AddType(ChainShape.TYPE, CircleShape.TYPE, ChainCircleContact); function EdgeCircleContact(manifold, xfA, fixtureA, indexA, xfB, fixtureB, indexB) { Assert(fixtureA.GetType() == EdgeShape.TYPE); Assert(fixtureB.GetType() == CircleShape.TYPE); var shapeA = fixtureA.GetShape(); var shapeB = fixtureB.GetShape(); CollideEdgeCircle(manifold, shapeA, xfA, shapeB, xfB); } function ChainCircleContact(manifold, xfA, fixtureA, indexA, xfB, fixtureB, indexB) { Assert(fixtureA.GetType() == ChainShape.TYPE); Assert(fixtureB.GetType() == CircleShape.TYPE); var chain = fixtureA.GetShape(); var edge = new EdgeShape(); chain.GetChildEdge(edge, indexA); var shapeA = edge; var shapeB = fixtureB.GetShape(); CollideEdgeCircle(manifold, shapeA, xfA, shapeB, xfB); } // Compute contact points for edge versus circle. // This accounts for edge connectivity. function CollideEdgeCircle(manifold, edgeA, xfA, circleB, xfB) { manifold.pointCount = 0; // Compute circle in frame of edge var Q = Transform.MulT(xfA, Transform.Mul(xfB, circleB.m_p)); var A = edgeA.m_vertex1; var B = edgeA.m_vertex2; var e = Vec2.Sub(B, A); // Barycentric coordinates var u = Vec2.Dot(e, Vec2.Sub(B, Q)); var v = Vec2.Dot(e, Vec2.Sub(Q, A)); var radius = edgeA.m_radius + circleB.m_radius; // Region A if (v <= 0.0) { var P = Vec2(A); var d = Vec2.Sub(Q, P); var dd = Vec2.Dot(d, d); if (dd > radius * radius) { return; } // Is there an edge connected to A? if (edgeA.m_hasVertex0) { var A1 = edgeA.m_vertex0; var B1 = A; var e1 = Vec2.Sub(B1, A1); var u1 = Vec2.Dot(e1, Vec2.Sub(B1, Q)); // Is the circle in Region AB of the previous edge? if (u1 > 0.0) { return; } } manifold.type = Manifold.e_circles; manifold.localNormal.SetZero(); manifold.localPoint.Set(P); manifold.pointCount = 1; manifold.points[0].localPoint.Set(circleB.m_p); manifold.points[0].id.key = 0; manifold.points[0].id.cf.indexA = 0; manifold.points[0].id.cf.typeA = Manifold.e_vertex; manifold.points[0].id.cf.indexB = 0; manifold.points[0].id.cf.typeB = Manifold.e_vertex; return; } // Region B if (u <= 0.0) { var P = Vec2(B); var d = Vec2.Sub(Q, P); var dd = Vec2.Dot(d, d); if (dd > radius * radius) { return; } // Is there an edge connected to B? if (edgeA.m_hasVertex3) { var B2 = edgeA.m_vertex3; var A2 = B; var e2 = Vec2.Sub(B2, A2); var v2 = Vec2.Dot(e2, Vec2.Sub(Q, A2)); // Is the circle in Region AB of the next edge? if (v2 > 0.0) { return; } } manifold.type = Manifold.e_circles; manifold.localNormal.SetZero(); manifold.localPoint.Set(P); manifold.pointCount = 1; manifold.points[0].localPoint.Set(circleB.m_p); manifold.points[0].id.key = 0; manifold.points[0].id.cf.indexA = 1; manifold.points[0].id.cf.typeA = Manifold.e_vertex; manifold.points[0].id.cf.indexB = 0; manifold.points[0].id.cf.typeB = Manifold.e_vertex; return; } // Region AB var den = Vec2.Dot(e, e); Assert(den > 0.0); var P = Vec2.WAdd(u / den, A, v / den, B); var d = Vec2.Sub(Q, P); var dd = Vec2.Dot(d, d); if (dd > radius * radius) { return; } var n = Vec2(-e.y, e.x); if (Vec2.Dot(n, Vec2.Sub(Q, A)) < 0.0) { n.Set(-n.x, -n.y); } n.Normalize(); manifold.type = Manifold.e_faceA; manifold.localNormal = n; manifold.localPoint.Set(A); manifold.pointCount = 1; manifold.points[0].localPoint.Set(circleB.m_p); manifold.points[0].id.key = 0; manifold.points[0].id.cf.indexA = 0; manifold.points[0].id.cf.typeA = Manifold.e_face; manifold.points[0].id.cf.indexB = 0; manifold.points[0].id.cf.typeB = Manifold.e_vertex; }