Dart Documentationbox2d_consoleContact

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;
  }
}

Fixture fixtureA #

Fixture fixtureA;

Fixture fixtureB #

Fixture fixtureB;

int flags #

The flags for this Contact.

int flags;

Manifold manifold #

Manifold manifold;

Contact next #

Contact next;

DefaultWorldPool pool #

DefaultWorldPool pool;

Contact prev #

World pool and list pointers.

Contact prev;

final Type runtimeType #

inherited from Object

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) #

inherited from Object

The equality operator.

The default behavior for all Objects 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() { }

abstract void evaluate(Manifold argManifold, Transform xfA, Transform xfB) #

Abstract method.

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() #

inherited from Object

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) #

inherited from Object

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() #

inherited from 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() #

inherited from Object

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);
  }
}