Contact abstract class
This class defines contact between two shapes.
abstract class Contact { /** Used when crawling contact graph when forming islands. */ static const int ISLAND_FLAG = 0x0001; static const int TOUCHING_FLAG = 0x0002; static const int ENABLED_FLAG = 0x0004; static const int FILTER_FLAG = 0x0008; static const int BULLET_HIT_FLAG = 0x0010; /** The flags for this Contact. */ int flags; /** World pool and list pointers. */ //TODO(gregbglw): Write benchmark comparing this linked list style with just // using a list. Contact prev; Contact next; /** Nodes for connecting bodies. */ ContactEdge edge1; ContactEdge edge2; Fixture fixtureA; Fixture fixtureB; Manifold manifold; num toiCount; DefaultWorldPool pool; /** Pool manifold for internal use. */ final Manifold _oldManifold; Contact(DefaultWorldPool pool) : manifold = new Manifold(), fixtureA = null, fixtureB = null, edge1 = new ContactEdge(), edge2 = new ContactEdge(), pool = pool, _oldManifold = new Manifold() { } /** * Initialization for pooling. */ void init(Fixture fixA, Fixture fixB) { flags = 0; fixtureA = fixA; fixtureB = fixB; manifold.pointCount = 0; prev = null; next = null; edge1.contact = null; edge1.prev = null; edge1.next = null; edge1.other = null; edge2.contact = null; edge2.prev = null; edge2.next = null; edge2.other = null; toiCount = 0; } /** * Intializes the given world manifold. */ void getWorldManifold(WorldManifold worldManifold) { final Body bodyA = fixtureA.body; final Body bodyB = fixtureB.body; final Shape shapeA = fixtureA.shape; final Shape shapeB = fixtureB.shape; worldManifold.initialize(manifold, bodyA.originTransform, shapeA.radius, bodyB.originTransform, shapeB.radius); } /** * Is this contact touching */ bool get touching() { return (flags & TOUCHING_FLAG) == TOUCHING_FLAG; } /** * Enable/disable this contact. This can be used inside the pre-solve * contact listener. The contact is only disabled for the current time step * (or sub-step in continuous collisions). */ void set enabled(bool flag) { if (flag) { flags |= ENABLED_FLAG; } else { flags &= ~ENABLED_FLAG; } } bool get enabled () { return (flags & ENABLED_FLAG) == ENABLED_FLAG; } /** Abstract method. */ abstract void evaluate(Manifold argManifold, Transform xfA, Transform xfB); /** * Flag this contact for filtering. Filtering will occur the next time step. */ void flagForFiltering() { flags |= FILTER_FLAG; } void update(ContactListener listener) { _oldManifold.setFrom(manifold); // Re-enable this contact. flags |= ENABLED_FLAG; bool touching = false; bool wasTouching = (flags & TOUCHING_FLAG) == TOUCHING_FLAG; bool sensorA = fixtureA.isSensor; bool sensorB = fixtureB.isSensor; bool sensor = sensorA || sensorB; Body bodyA = fixtureA.body; Body bodyB = fixtureB.body; Transform xfA = bodyA.originTransform; Transform xfB = bodyB.originTransform; if (sensor) { Shape shapeA = fixtureA.shape; Shape shapeB = fixtureB.shape; touching = pool.collision.testOverlap(shapeA, shapeB, xfA, xfB); // Sensors don't generate manifolds. manifold.pointCount = 0; } else { evaluate(manifold, xfA, xfB); touching = manifold.pointCount > 0; // Match old contact ids to new contact ids and copy the // stored impulses to warm start the solver. for (int i = 0; i < manifold.pointCount; ++i) { ManifoldPoint mp2 = manifold.points[i]; mp2.normalImpulse = 0.0; mp2.tangentImpulse = 0.0; ContactID id2 = mp2.id; for (int j = 0; j < _oldManifold.pointCount; ++j) { ManifoldPoint mp1 = _oldManifold.points[j]; if (mp1.id.isEqual(id2)) { mp2.normalImpulse = mp1.normalImpulse; mp2.tangentImpulse = mp1.tangentImpulse; break; } } } if (touching != wasTouching) { bodyA.awake = true; bodyB.awake = true; } } if (touching) { flags |= TOUCHING_FLAG; } else { flags &= ~TOUCHING_FLAG; } if (listener == null) { return; } if (wasTouching == false && touching == true) { listener.beginContact(this); } if (wasTouching == true && touching == false) { listener.endContact(this); } if (sensor == false && touching) { listener.preSolve(this, _oldManifold); } } }
Subclasses
CircleContact, PolygonAndCircleContact, PolygonContact
Constructors
new Contact(DefaultWorldPool pool) #
Contact(DefaultWorldPool pool) : manifold = new Manifold(), fixtureA = null, fixtureB = null, edge1 = new ContactEdge(), edge2 = new ContactEdge(), pool = pool, _oldManifold = new Manifold() { }
Static Properties
const int BULLET_HIT_FLAG #
static const int BULLET_HIT_FLAG = 0x0010;
const int ENABLED_FLAG #
static const int ENABLED_FLAG = 0x0004;
const int FILTER_FLAG #
static const int FILTER_FLAG = 0x0008;
const int ISLAND_FLAG #
Used when crawling contact graph when forming islands.
static const int ISLAND_FLAG = 0x0001;
const int TOUCHING_FLAG #
static const int TOUCHING_FLAG = 0x0002;
Properties
ContactEdge edge1 #
Nodes for connecting bodies.
ContactEdge edge1;
ContactEdge edge2 #
ContactEdge edge2;
bool enabled #
Enable/disable this contact. This can be used inside the pre-solve contact listener. The contact is only disabled for the current time step (or sub-step in continuous collisions).
bool get enabled () { return (flags & ENABLED_FLAG) == ENABLED_FLAG; }
void set enabled(bool flag) { if (flag) { flags |= ENABLED_FLAG; } else { flags &= ~ENABLED_FLAG; } }
int flags #
The flags for this Contact.
int flags;
DefaultWorldPool pool #
DefaultWorldPool pool;
final Type runtimeType #
A representation of the runtime type of the object.
external Type get runtimeType;
num toiCount #
num toiCount;
final bool touching #
Is this contact touching
bool get touching() { return (flags & TOUCHING_FLAG) == TOUCHING_FLAG; }
Operators
bool operator ==(other) #
The equality operator.
The default behavior for all Object
s is to return true if and
only if this
and
other are the same object.
If a subclass overrides the equality operator it should override
the hashCode
method as well to maintain consistency.
bool operator ==(other) => identical(this, other);
Methods
new Contact(DefaultWorldPool pool) #
Contact(DefaultWorldPool pool) : manifold = new Manifold(), fixtureA = null, fixtureB = null, edge1 = new ContactEdge(), edge2 = new ContactEdge(), pool = pool, _oldManifold = new Manifold() { }
void flagForFiltering() #
Flag this contact for filtering. Filtering will occur the next time step.
void flagForFiltering() { flags |= FILTER_FLAG; }
void getWorldManifold(WorldManifold worldManifold) #
Intializes the given world manifold.
void getWorldManifold(WorldManifold worldManifold) { final Body bodyA = fixtureA.body; final Body bodyB = fixtureB.body; final Shape shapeA = fixtureA.shape; final Shape shapeB = fixtureB.shape; worldManifold.initialize(manifold, bodyA.originTransform, shapeA.radius, bodyB.originTransform, shapeB.radius); }
int hashCode() #
Get a hash code for this object.
All objects have hash codes. Hash codes are guaranteed to be the
same for objects that are equal when compared using the equality
operator ==
. Other than that there are no guarantees about
the hash codes. They will not be consistent between runs and
there are no distribution guarantees.
If a subclass overrides hashCode
it should override the
equality operator as well to maintain consistency.
external int hashCode();
void init(Fixture fixA, Fixture fixB) #
Initialization for pooling.
void init(Fixture fixA, Fixture fixB) { flags = 0; fixtureA = fixA; fixtureB = fixB; manifold.pointCount = 0; prev = null; next = null; edge1.contact = null; edge1.prev = null; edge1.next = null; edge1.other = null; edge2.contact = null; edge2.prev = null; edge2.next = null; edge2.other = null; toiCount = 0; }
noSuchMethod(String name, List args) #
noSuchMethod
is invoked when users invoke a non-existant method
on an object. The name of the method and the arguments of the
invocation are passed to noSuchMethod
. If noSuchMethod
returns a value, that value becomes the result of the original
invocation.
The default behavior of noSuchMethod
is to throw a
noSuchMethodError
.
external Dynamic noSuchMethod(String name, List args);
const Object() #
Creates a new Object
instance.
Object
instances have no meaningful state, and are only useful
through their identity. An Object
instance is equal to itself
only.
const Object();
String toString() #
Returns a string representation of this object.
external String toString();
void update(ContactListener listener) #
void update(ContactListener listener) { _oldManifold.setFrom(manifold); // Re-enable this contact. flags |= ENABLED_FLAG; bool touching = false; bool wasTouching = (flags & TOUCHING_FLAG) == TOUCHING_FLAG; bool sensorA = fixtureA.isSensor; bool sensorB = fixtureB.isSensor; bool sensor = sensorA || sensorB; Body bodyA = fixtureA.body; Body bodyB = fixtureB.body; Transform xfA = bodyA.originTransform; Transform xfB = bodyB.originTransform; if (sensor) { Shape shapeA = fixtureA.shape; Shape shapeB = fixtureB.shape; touching = pool.collision.testOverlap(shapeA, shapeB, xfA, xfB); // Sensors don't generate manifolds. manifold.pointCount = 0; } else { evaluate(manifold, xfA, xfB); touching = manifold.pointCount > 0; // Match old contact ids to new contact ids and copy the // stored impulses to warm start the solver. for (int i = 0; i < manifold.pointCount; ++i) { ManifoldPoint mp2 = manifold.points[i]; mp2.normalImpulse = 0.0; mp2.tangentImpulse = 0.0; ContactID id2 = mp2.id; for (int j = 0; j < _oldManifold.pointCount; ++j) { ManifoldPoint mp1 = _oldManifold.points[j]; if (mp1.id.isEqual(id2)) { mp2.normalImpulse = mp1.normalImpulse; mp2.tangentImpulse = mp1.tangentImpulse; break; } } } if (touching != wasTouching) { bodyA.awake = true; bodyB.awake = true; } } if (touching) { flags |= TOUCHING_FLAG; } else { flags &= ~TOUCHING_FLAG; } if (listener == null) { return; } if (wasTouching == false && touching == true) { listener.beginContact(this); } if (wasTouching == true && touching == false) { listener.endContact(this); } if (sensor == false && touching) { listener.preSolve(this, _oldManifold); } }