planck-js
Version:
2D physics engine for JavaScript/HTML5 game development
178 lines (151 loc) • 5.56 kB
JavaScript
/*
* 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;
}