@awayfl/poki-player
Version:
AVM Player for poki games
549 lines (480 loc) • 17.8 kB
text/typescript
/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* 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.
*/
import { b2CircleShape } from "../../Collision/Shapes/b2CircleShape";
import { b2ConcaveArcShape } from "../../Collision/Shapes/b2ConcaveArcShape";
import { b2Shape } from "../../Collision/Shapes/b2Shape";
import { b2Collision } from "../../Collision/b2Collision";
import { b2ContactPoint } from "../../Collision/b2ContactPoint";
import { b2Manifold } from "../../Collision/b2Manifold";
import { b2ManifoldPoint } from "../../Collision/b2ManifoldPoint";
import { b2Mat22, b2Vec2, b2XForm } from "../../Common/Math";
import { b2Body } from "../b2Body";
import { b2ContactListener } from "../b2ContactListener";
import { b2Contact } from "./b2Contact";
import { b2PolyAndCircleContact } from "./b2PolyAndCircleContact";
export class b2ConcaveArcAndCircleContact extends b2PolyAndCircleContact
{
public static Create(shape1:b2Shape, shape2:b2Shape, allocator:any):b2Contact{
return new b2ConcaveArcAndCircleContact(shape1, shape2);
}
public static Destroy(contact:b2Contact, allocator:any) : void{
//
}
constructor(shape1:b2Shape, shape2:b2Shape){
super(shape1, shape2);
}
//~b2CircleContact() {}
//
static readonly s_evalCP:b2ContactPoint = new b2ContactPoint();
//Edited version of b2CollidePolyAndCircle
public static b2CollideConcaveArcAndCircle(
manifolds:b2Manifold[],
polygon:b2ConcaveArcShape, xf1:b2XForm, //Note the type defying name
circle:b2CircleShape, xf2:b2XForm) : number
{
var conservative:boolean = false;
var b2_nullFeature:number /** uint */=b2Collision.b2_nullFeature;
var manifold:b2Manifold = manifolds[0];
var manifoldCount:number = 0;
manifold.pointCount = 0;
var tPoint:b2ManifoldPoint;
var dX:number;
var dY:number;
var tVec:b2Vec2;
var tMat:b2Mat22;
var positionX:number;
var positionY:number;
// Compute circle position in the frame of the polygon.
//b2Vec2 c = b2Mul(xf2, circle->m_localPosition);
tMat = xf2.R;
tVec = circle.m_localPosition;
var cX:number = xf2.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
var cY:number = xf2.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
//b2Vec2 cLocal = b2MulT(xf1, c);
dX = cX - xf1.position.x;
dY = cY - xf1.position.y;
tMat = xf1.R;
var cLocalX:number = (dX * tMat.col1.x + dY * tMat.col1.y)
var cLocalY:number = (dX * tMat.col2.x + dY * tMat.col2.y)
var dist:number;
// Find the min separating edge.
var normalIndex:number /** int */ = 0;
var separation:number = -Number.MAX_VALUE;
var radius:number = circle.m_radius;
for (var i:number /** int */ = 1; i < polygon.m_vertexCount; ++i)
{
//float32 s = b2Dot(polygon->m_normals[i], cLocal - polygon->m_vertices[i]);
dX = cLocalX-polygon.m_vertices[i].x;
dY = cLocalY-polygon.m_vertices[i].y;
var s:number = polygon.m_normals[i].x * dX + polygon.m_normals[i].y * dY;
if (s > radius)
{
// Early out.
manifoldCount = 0;
return manifoldCount;
}
if (s > separation)
{
separation = s;
normalIndex = i;
}
}
//Calculate the arc separation
if( true || normalIndex==1 || normalIndex==(polygon.m_vertexCount-1))
{
s = polygon.m_normals[0].x * (cLocalX-polygon.m_vertices[0].x) + polygon.m_normals[0].y * (cLocalY-polygon.m_vertices[0].y);
var c2X:number = cLocalX-polygon.m_arcCenter.x;
var c2Y:number = cLocalY-polygon.m_arcCenter.y;
var c2:number = Math.sqrt(c2X*c2X+c2Y*c2Y);
c2X /= c2;
c2Y /= c2;
s = Math.max(s,polygon.m_radius - c2);
if (s > radius)
{
// Early out.
manifoldCount = 0;
return manifoldCount;
}
if (s > separation)
{
separation = s;
normalIndex = 0;
}
}
if((normalIndex==0) && (radius >= polygon.m_radius))
{
//In this case, the sphere can have two contact points, m_vertices[0] and m_vertices[1]
//Flash only: Defer creating second manifold until it is actually needed
if(manifolds.length<2){
manifolds[1]=new b2Manifold();
manifolds[1].pointCount = 0;
manifolds[1].points[0].normalImpulse = 0.0;
manifolds[1].points[0].tangentImpulse = 0.0;
}
manifoldCount=0;
for(i=0;i<2;i++){
dX = polygon.m_vertices[i].x-cLocalX;
dY = polygon.m_vertices[i].y-cLocalY;
var d2:number=dX*dX+dY*dY;
if(d2<radius*radius){
var d:number = Math.sqrt(d2);
manifolds[manifoldCount].pointCount=1;
tPoint = manifolds[manifoldCount].points[0];
tPoint.id.features.incidentEdge = b2_nullFeature;
tPoint.id.features.incidentVertex = i;
tPoint.id.features.referenceEdge = b2_nullFeature;
tPoint.id.features.flip = 0;
tPoint.separation = d - radius;
tPoint.normalImpulse = 0;
tPoint.tangentImpulse = 0;
dX=-dX/d;
dY=-dY/d;
manifolds[manifoldCount].normal.x = tMat.col1.x * dX + tMat.col2.x * dY;
manifolds[manifoldCount].normal.y = tMat.col1.y * dX + tMat.col2.y * dY;
//This might be outside the poly
//Perhaps it would be better to set the position to the vertex location
//b2Vec2 position = c - radius * manifold->normal;
positionX = cX - radius * manifolds[manifoldCount].normal.x;
positionY = cY - radius * manifolds[manifoldCount].normal.y;
//manifold->points[0].localPoint1 = b2MulT(xf1, position);
dX = positionX - xf1.position.x;
dY = positionY - xf1.position.y;
tMat = xf1.R;
tPoint.localPoint1.x = (dX*tMat.col1.x + dY*tMat.col1.y);
tPoint.localPoint1.y = (dX*tMat.col2.x + dY*tMat.col2.y);
//manifold->points[0].localPoint2 = b2MulT(xf2, position);
dX = positionX - xf2.position.x;
dY = positionY - xf2.position.y;
tMat = xf2.R;
tPoint.localPoint2.x = (dX*tMat.col1.x + dY*tMat.col1.y);
tPoint.localPoint2.y = (dX*tMat.col2.x + dY*tMat.col2.y);
manifoldCount++;
}
}
return manifoldCount;
}
// If the center is inside the polygon ...
if (separation < Number.MIN_VALUE)
{
manifold.pointCount = 1;
manifoldCount = 1;
if(normalIndex == 0){
//manifold->normal = b2Mul(xf1.R, -c2^);
tMat = xf1.R;
manifold.normal.x = -(tMat.col1.x * c2X + tMat.col2.x * c2Y);
manifold.normal.y = -(tMat.col1.y * c2X + tMat.col2.y * c2Y);
}else{
//manifold->normal = b2Mul(xf1.R, polygon->m_normals[normalIndex]);
tVec = polygon.m_normals[normalIndex];
tMat = xf1.R;
manifold.normal.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
manifold.normal.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
}
tPoint = manifold.points[0];
tPoint.id.features.incidentEdge = normalIndex;
tPoint.id.features.incidentVertex = b2_nullFeature;
tPoint.id.features.referenceEdge = 0;
tPoint.id.features.flip = 0;
//b2Vec2 position = c - radius * manifold->normal;
positionX = cX - radius * manifold.normal.x;
positionY = cY - radius * manifold.normal.y;
//manifold->points[0].localPoint1 = b2MulT(xf1, position);
dX = positionX - xf1.position.x;
dY = positionY - xf1.position.y;
tMat = xf1.R;
tPoint.localPoint1.x = (dX*tMat.col1.x + dY*tMat.col1.y);
tPoint.localPoint1.y = (dX*tMat.col2.x + dY*tMat.col2.y);
//manifold->points[0].localPoint2 = b2MulT(xf2, position);
dX = positionX - xf2.position.x;
dY = positionY - xf2.position.y;
tMat = xf2.R;
tPoint.localPoint2.x = (dX*tMat.col1.x + dY*tMat.col1.y);
tPoint.localPoint2.y = (dX*tMat.col2.x + dY*tMat.col2.y);
tPoint.separation = separation - radius;
return manifoldCount;
}
// Project the circle center onto the edge segment.
var vertIndex1:number /** int */ = normalIndex;
var vertIndex2:number /** int */ = vertIndex1 + 1 < polygon.m_vertexCount ? vertIndex1 + 1 : 0;
//var e:b2Vec2 = b2Math.SubtractVV(polygon.m_vertices[vertIndex2] , polygon.m_vertices[vertIndex1]);
var eX:number = polygon.m_vertices[vertIndex2].x - polygon.m_vertices[vertIndex1].x;
var eY:number = polygon.m_vertices[vertIndex2].y - polygon.m_vertices[vertIndex1].y;
//var length:number = e.Normalize();
var length:number = Math.sqrt(eX*eX + eY*eY);
eX /= length;
eY /= length;
// If the edge length is zero ...
if (length < Number.MIN_VALUE)
{
//d = b2Math.SubtractVV(cLocal , polygon.m_vertices[vertIndex1]);
dX = cLocalX - polygon.m_vertices[vertIndex1].x;
dY = cLocalY - polygon.m_vertices[vertIndex1].y;
//dist = d.Normalize();
dist = Math.sqrt(dX*dX + dY*dY);
dX /= dist;
dY /= dist;
if (dist > radius)
{
manifoldCount = 0;
return manifoldCount;
}
manifold.pointCount = 1;
manifoldCount = 1;
//manifold->normal = b2Mul(xf1.R, d);
tMat = xf1.R
manifold.normal.x = (tMat.col1.x * dX + tMat.col2.x * dY);
manifold.normal.y = (tMat.col1.y * dX + tMat.col2.y * dY);
tPoint = manifold.points[0];
tPoint.id.features.incidentEdge = b2_nullFeature;
tPoint.id.features.incidentVertex = vertIndex1;
tPoint.id.features.referenceEdge = b2_nullFeature;
tPoint.id.features.flip = 0;
//b2Vec2 position = c - radius * manifold->normal;
positionX = cX - radius * manifold.normal.x;
positionY = cY - radius * manifold.normal.y;
//manifold->points[0].localPoint1 = b2MulT(xf1, position);
dX = positionX - xf1.position.x;
dY = positionY - xf1.position.y;
tMat = xf1.R;
tPoint.localPoint1.x = (dX*tMat.col1.x + dY*tMat.col1.y);
tPoint.localPoint1.y = (dX*tMat.col2.x + dY*tMat.col2.y);
//manifold->points[0].localPoint2 = b2MulT(xf2, position);
dX = positionX - xf2.position.x;
dY = positionY - xf2.position.y;
tMat = xf2.R;
tPoint.localPoint2.x = (dX*tMat.col1.x + dY*tMat.col1.y);
tPoint.localPoint2.y = (dX*tMat.col2.x + dY*tMat.col2.y);
tPoint.separation = dist - radius;
return manifoldCount;
}
// Project the center onto the edge.
//float32 u = b2Dot(cLocal - polygon->m_vertices[vertIndex1], e);
dX = cLocalX - polygon.m_vertices[vertIndex1].x;
dY = cLocalY - polygon.m_vertices[vertIndex1].y;
tPoint = manifold.points[0];
tPoint.id.features.incidentEdge = 0;
tPoint.id.features.incidentVertex = 0;
tPoint.id.features.referenceEdge = 0;
tPoint.id.features.flip = 0;
var pX:number, pY:number;
if(normalIndex==0){
var norm:number=eX*c2X+eY*c2Y;
//This may seem like it will always eval false, but this is not so for very large arcs (where norm ~=1)
if (c2X*polygon.m_normals[0].x+c2Y*polygon.m_normals[0].y>0)
{
if (norm <0 ){
pX = polygon.m_vertices[vertIndex1].x;
pY = polygon.m_vertices[vertIndex1].y;
tPoint.id.features.incidentVertex = vertIndex1;
tPoint.id.features.incidentEdge = b2_nullFeature;
}
else
{
pX = polygon.m_vertices[vertIndex2].x;
pY = polygon.m_vertices[vertIndex2].y;
tPoint.id.features.incidentVertex = vertIndex2;
tPoint.id.features.incidentEdge = b2_nullFeature;
}
}else{
if (norm <= -polygon.m_norm){
pX = polygon.m_vertices[vertIndex1].x;
pY = polygon.m_vertices[vertIndex1].y;
tPoint.id.features.incidentVertex = vertIndex1;
tPoint.id.features.incidentEdge = b2_nullFeature;
}
else if (norm >= polygon.m_norm)
{
pX = polygon.m_vertices[vertIndex2].x;
pY = polygon.m_vertices[vertIndex2].y;
tPoint.id.features.incidentVertex = vertIndex2;
tPoint.id.features.incidentEdge = b2_nullFeature;
}
else
{
//p = b2Math.AddVV(poly.m_vertices[vertIndex1] , b2Math.MulFV(u, e));
pX = polygon.m_arcCenter.x + c2X * polygon.m_radius;
pY = polygon.m_arcCenter.y + c2Y * polygon.m_radius;
tPoint.id.features.incidentEdge = vertIndex1;
}
}
}else{
var u:number = dX*eX + dY*eY;
if (u <= 0.0)
{
pX = polygon.m_vertices[vertIndex1].x;
pY = polygon.m_vertices[vertIndex1].y;
tPoint.id.features.incidentVertex = vertIndex1;
tPoint.id.features.incidentEdge = b2_nullFeature;
}
else if (u >= length)
{
pX = polygon.m_vertices[vertIndex2].x;
pY = polygon.m_vertices[vertIndex2].y;
tPoint.id.features.incidentVertex = vertIndex2;
tPoint.id.features.incidentEdge = b2_nullFeature;
}
else
{
//p = polygon->m_vertices[vertIndex1] + u * e;
pX = eX * u + polygon.m_vertices[vertIndex1].x;
pY = eY * u + polygon.m_vertices[vertIndex1].y;
tPoint.id.features.incidentEdge = vertIndex1;
}
}
//d = b2Math.SubtractVV(xLocal , p);
dX = cLocalX - pX;
dY = cLocalY - pY;
//dist = d.Normalize();
dist = Math.sqrt(dX*dX + dY*dY);
dX /= dist;
dY /= dist;
if (dist > radius)
{
manifoldCount = 0;
return manifoldCount;
}
manifold.pointCount = 1;
manifoldCount = 1;
//manifold->normal = b2Mul(xf1.R, d);
tMat = xf1.R;
manifold.normal.x = tMat.col1.x * dX + tMat.col2.x * dY;
manifold.normal.y = tMat.col1.y * dX + tMat.col2.y * dY;
//b2Vec2 position = c - radius * manifold->normal;
positionX = cX - radius * manifold.normal.x;
positionY = cY - radius * manifold.normal.y;
//manifold->points[0].localPoint1 = b2MulT(xf1, position);
dX = positionX - xf1.position.x;
dY = positionY - xf1.position.y;
tMat = xf1.R;
tPoint.localPoint1.x = (dX*tMat.col1.x + dY*tMat.col1.y);
tPoint.localPoint1.y = (dX*tMat.col2.x + dY*tMat.col2.y);
//manifold->points[0].localPoint2 = b2MulT(xf2, position);
dX = positionX - xf2.position.x;
dY = positionY - xf2.position.y;
tMat = xf2.R;
tPoint.localPoint2.x = (dX*tMat.col1.x + dY*tMat.col1.y);
tPoint.localPoint2.y = (dX*tMat.col2.x + dY*tMat.col2.y);
tPoint.separation = dist - radius;
return manifoldCount;
}
public Evaluate(listener:b2ContactListener) : void{
var i:number /**uint */;
var v1:b2Vec2;
var v2:b2Vec2;
var mp0:b2ManifoldPoint;
var b1:b2Body = this.m_shape1.m_body;
var b2:b2Body = this.m_shape2.m_body;
//b2Manifold m0;
//memcpy(&m0, &m_manifold, sizeof(b2Manifold));
// TODO: make sure this is completely necessary
this.m0.Set(this.m_manifolds[0]);
//m1.Set(m_manifolds[1]);
this.m_manifoldCount = b2ConcaveArcAndCircleContact.b2CollideConcaveArcAndCircle(this.m_manifolds, this.m_shape1 as b2ConcaveArcShape, b1.m_xf, this.m_shape2 as b2CircleShape, b2.m_xf);
var persisted:boolean[] = [false, false];
var cp:b2ContactPoint = b2ConcaveArcAndCircleContact.s_evalCP;
cp.shape1 = this.m_shape1;
cp.shape2 = this.m_shape2;
cp.friction = this.m_friction;
cp.restitution = this.m_restitution;
// Match contact ids to facilitate warm starting.
if (this.m_manifold.pointCount > 0)
{
// Match old contact ids to new contact ids and copy the
// stored impulses to warm start the solver.
for (i = 0; i < this.m_manifold.pointCount; ++i)
{
var mp:b2ManifoldPoint = this.m_manifold.points[ i ];
mp.normalImpulse = 0.0;
mp.tangentImpulse = 0.0;
var found:boolean = false;
var idKey:number /** uint */ = mp.id._key;
for (var j:number /** int */ = 0; j < this.m0.pointCount; ++j)
{
if (persisted[j] == true)
{
continue;
}
mp0 = this.m0.points[ j ];
if (mp0.id._key == idKey)
{
persisted[j] = true;
mp.normalImpulse = mp0.normalImpulse;
mp.tangentImpulse = mp0.tangentImpulse;
// A persistent point.
found = true;
// Report persistent point.
if (listener != null)
{
cp.position = b1.GetWorldPoint(mp.localPoint1);
v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1);
v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2);
cp.velocity.Set(v2.x - v1.x, v2.y - v1.y);
cp.normal.SetV(this.m_manifold.normal);
cp.separation = mp.separation;
cp.id.key = idKey;
listener.Persist(cp);
}
break;
}
}
// Report added point.
if (found == false && listener != null)
{
cp.position = b1.GetWorldPoint(mp.localPoint1);
v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1);
v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2);
cp.velocity.Set(v2.x - v1.x, v2.y - v1.y);
cp.normal.SetV(this.m_manifold.normal);
cp.separation = mp.separation;
cp.id.key = idKey;
listener.Add(cp);
}
}
this.m_manifoldCount = 1;
}
else
{
this.m_manifoldCount = 0;
}
if (listener == null)
{
return;
}
// Report removed points.
for (i = 0; i < this.m0.pointCount; ++i)
{
if (persisted[i])
{
continue;
}
mp0 = this.m0.points[ i ];
cp.position = b1.GetWorldPoint(mp0.localPoint1);
v1 = b1.GetLinearVelocityFromLocalPoint(mp0.localPoint1);
v2 = b2.GetLinearVelocityFromLocalPoint(mp0.localPoint2);
cp.velocity.Set(v2.x - v1.x, v2.y - v1.y);
cp.normal.SetV(this.m0.normal);
cp.separation = mp0.separation;
cp.id.key = mp0.id._key;
listener.Remove(cp);
}
}
public GetManifolds():b2Manifold[]
{
return this.m_manifolds;
}
}