Dart Documentationbox2d_htmlIsland

Island class

Island represents a grouping of objects to apply DFS solving for movement and collisions.

class Island {
  ContactListener listener;

  List<Body> bodies;
  List<Contact> contacts;
  List<Joint> joints;

  List<Position> positions;
  List<Velocity> velocities;

  int bodyCount;
  int jointCount;
  int contactCount;

  int bodyCapacity;
  int contactCapacity;
  int jointCapacity;

  int positionIterationCount;

  // Pool objects to cut down on object creation.
  ContactSolver _contactSolver;
  Vector _translation;
  ContactImpulse impulse;

  Island() :
    _contactSolver = new ContactSolver(),
    _translation = new Vector(),
    impulse = new ContactImpulse() { }

  //TODO(gregbglw): No need to keep capacity, count and array for these items as
  // in C. Simply measure the length of the array, for example, in order to
  // determine capacity.
  void init(int argBodyCapacity, int argContactCapacity, int argJointCapacity,
      ContactListener argListener) {
    bodyCapacity = argBodyCapacity;
    contactCapacity = argContactCapacity;
    jointCapacity = argJointCapacity;
    bodyCount = 0;
    contactCount = 0;

    listener = argListener;

    if (bodies == null || bodyCapacity > bodies.length) {
      bodies = new List<Body>(bodyCapacity);
    }
    if (contacts == null || contactCapacity > contacts.length) {
      contacts = new List<Contact>(contactCapacity);
    }
    if (joints == null || jointCapacity > joints.length) {
      joints = new List<Joint>(jointCapacity);
    }

    // dynamic array
    if (velocities == null || bodyCapacity > velocities.length) {
      final List<Velocity> old = velocities == null ?
          new List<Velocity>(0) : velocities;
      velocities = new List<Velocity>(bodyCapacity);
      velocities.setRange(0, old.length, old);
      for (int i=old.length; i<velocities.length; i++) {
        velocities[i] = new Velocity();
      }
    }

    // dynamic array
    if(positions == null || bodyCapacity > positions.length){
      List<Position> old = positions == null ?
          new List<Position>(0) : positions;
      positions = new List<Position>(bodyCapacity);
      positions.setRange(0, old.length, old);
      for (int i=old.length; i<positions.length; i++) {
        positions[i] = new Position();
      }
    }
  }

  void clear() {
    bodyCount = 0;
    contactCount = 0;
    jointCount = 0;
  }

  void solve(TimeStep step, Vector gravity, bool allowSleep){
    // Integrate velocities and apply damping.
    for (int i = 0; i < bodyCount; ++i){
      Body b = bodies[i];

      if (b.type != BodyType.DYNAMIC){
        continue;
      }

      final velocityDelta = new Vector(
          (b._force.x * b.invMass + gravity.x) * step.dt,
          (b._force.y * b.invMass + gravity.y) * step.dt);
      b.linearVelocity.addLocal(velocityDelta);
      num newAngularVelocity = b.angularVelocity +
          (step.dt * b.invInertia * b._torque);
      b.angularVelocity = newAngularVelocity;

      num a = (1.0 - step.dt * b.linearDamping);
      num a1 = (0.0 > (a < 1.0 ? a : 1.0) ? 0.0 : (a < 1.0 ? a : 1.0));
      b.linearVelocity.mulLocal(a1);

      num a2 = (1.0 - step.dt * b.angularDamping);
      num b1 = (a2 < 1.0 ? a2 : 1.0);
      b.angularVelocity *= 0.0 > b1 ? 0.0 : b1;
    }

    // Partition contacts so that contacts with static bodies are solved last.
    int i1 = -1;
    for (int i2 = 0; i2 < contactCount; ++i2) {
      Fixture fixtureA = contacts[i2].fixtureA;
      Fixture fixtureB = contacts[i2].fixtureB;
      Body bodyA = fixtureA.body;
      Body bodyB = fixtureB.body;
      bool nonStatic = bodyA.type != BodyType.STATIC && bodyB.type
          != BodyType.STATIC;
      if (nonStatic){
        ++i1;
        //Swap(contacts[i1], contacts[i2]);
        Contact temp = contacts[i1];
        contacts[i1] = contacts[i2];
        contacts[i2] = temp;
      }
    }

    // Initialize velocity constraints.
    _contactSolver.init(contacts, contactCount, step.dtRatio);
    _contactSolver.warmStart();

    for (int i = 0; i < jointCount; ++i){
      joints[i].initVelocityConstraints(step);
    }

    for (int i = 0; i < step.velocityIterations; ++i) {
      for (int j = 0; j < jointCount; ++j){
        joints[j].solveVelocityConstraints(step);
      }
      _contactSolver.solveVelocityConstraints();
    }

    // Post-solve (store impulses for warm starting).
    _contactSolver.storeImpulses();

    // Integrate positions.
    Vector temp = new Vector();
    for (int i = 0; i < bodyCount; ++i){
      Body b = bodies[i];

      if (b.type == BodyType.STATIC){
        continue;
      }

      // Check for large velocities.
      _translation.setFrom(b.linearVelocity);
      _translation.mulLocal(step.dt);
      if (Vector.dot(_translation, _translation) >
          Settings.MAX_TRANSLATION_SQUARED){
        num ratio = Settings.MAX_TRANSLATION / _translation.length;
        b.linearVelocity.mulLocal(ratio);
      }

      num rotation = step.dt * b.angularVelocity;
      if (rotation * rotation > Settings.MAX_ROTATION_SQUARED) {
        num ratio = Settings.MAX_ROTATION / rotation.abs();
        b.angularVelocity *= ratio;
      }

      // Store positions for continuous collision.
      b.sweep.centerZero.setFrom(b.sweep.center);
      b.sweep.angleZero = b.sweep.angle;

      // Integrate
      temp.setFrom(b.linearVelocity);
      temp.mulLocal(step.dt);
      b.sweep.center.addLocal(temp);
      b.sweep.angle += step.dt * b.angularVelocity;

      // Compute new transform
      b.synchronizeTransform();

      // Note: shapes are synchronized later.
    }

    // Iterate over constraints.
    for (int i = 0; i < step.positionIterations; ++i){
      bool contactsOkay =
          _contactSolver.solvePositionConstraints(Settings.CONTACT_BAUMGARTE);

      bool jointsOkay = true;
      for (int j = 0; j < jointCount; ++j){
        bool jointOkay =
            joints[j].solvePositionConstraints(Settings.CONTACT_BAUMGARTE);
        jointsOkay = jointsOkay && jointOkay;
      }

      if (contactsOkay && jointsOkay){
        // Exit early if the position errors are small.
        break;
      }
    }

    report(_contactSolver.constraints);


    if (allowSleep){
      num minSleepTime = Settings.BIG_NUMBER;

      num linTolSqr = Settings.LINEAR_SLEEP_TOLERANCE
          * Settings.LINEAR_SLEEP_TOLERANCE;
      num angTolSqr = Settings.ANGULAR_SLEEP_TOLERANCE
          * Settings.ANGULAR_SLEEP_TOLERANCE;

      for (int i = 0; i < bodyCount; ++i){
        Body b = bodies[i];
        if (b.type == BodyType.STATIC){
          continue;
        }

        if ((b.flags & Body.AUTO_SLEEP_FLAG) == 0){
          b.sleepTime = 0.0;
          minSleepTime = 0.0;
        }

        if ((b.flags & Body.AUTO_SLEEP_FLAG) == 0 ||
            b.angularVelocity * b.angularVelocity > angTolSqr ||
            Vector.dot(b.linearVelocity, b.linearVelocity) > linTolSqr){
          b.sleepTime = 0.0;
          minSleepTime = 0.0;
        }
        else{
          b.sleepTime += step.dt;
          minSleepTime = Math.min(minSleepTime, b.sleepTime);
        }
      }

      if (minSleepTime >= Settings.TIME_TO_SLEEP){
        for (int i = 0; i < bodyCount; ++i){
          Body b = bodies[i];
          b.awake = false;
        }
      }
    }

  }

  /** Adds a body to the Island. */
  void addBody(Body body){
    assert(bodyCount < bodyCapacity);
    body.islandIndex = bodyCount;
    bodies[bodyCount++] = body;
  }

  /** Add a contact to the Island. */
  void addContact(Contact contact) {
    assert(contactCount < contactCapacity);
    contacts[contactCount++] = contact;
  }

  /** Add a joint to the Island. */
  void addJoint(Joint joint) {
    assert(jointCount < jointCapacity);
    joints[jointCount++] = joint;
  }

  void report(List<ContactConstraint> constraints){
    if (listener == null){
      return;
    }

    for (int i = 0; i < contactCount; ++i){
      Contact c = contacts[i];

      ContactConstraint cc = constraints[i];

      for (int j = 0; j < cc.pointCount; ++j){
        impulse.normalImpulses[j] = cc.points[j].normalImpulse;
        impulse.tangentImpulses[j] = cc.points[j].tangentImpulse;
      }

      listener.postSolve(c, impulse);
    }
  }
}

Constructors

new Island() #

Island() :
  _contactSolver = new ContactSolver(),
  _translation = new Vector(),
  impulse = new ContactImpulse() { }

Properties

List<Body> bodies #

List<Body> bodies;

int bodyCapacity #

int bodyCapacity;

int bodyCount #

int bodyCount;

int contactCapacity #

int contactCapacity;

int contactCount #

int contactCount;

List<Contact> contacts #

List<Contact> contacts;

ContactImpulse impulse #

ContactImpulse impulse;

int jointCapacity #

int jointCapacity;

int jointCount #

int jointCount;

List<Joint> joints #

List<Joint> joints;

ContactListener listener #

ContactListener listener;

int positionIterationCount #

int positionIterationCount;

List<Position> positions #

List<Position> positions;

final Type runtimeType #

inherited from Object

A representation of the runtime type of the object.

external Type get runtimeType;

List<Velocity> velocities #

List<Velocity> velocities;

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

void addBody(Body body) #

Adds a body to the Island.

void addBody(Body body){
  assert(bodyCount < bodyCapacity);
  body.islandIndex = bodyCount;
  bodies[bodyCount++] = body;
}

void addContact(Contact contact) #

Add a contact to the Island.

void addContact(Contact contact) {
  assert(contactCount < contactCapacity);
  contacts[contactCount++] = contact;
}

void addJoint(Joint joint) #

Add a joint to the Island.

void addJoint(Joint joint) {
  assert(jointCount < jointCapacity);
  joints[jointCount++] = joint;
}

void clear() #

void clear() {
  bodyCount = 0;
  contactCount = 0;
  jointCount = 0;
}

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(int argBodyCapacity, int argContactCapacity, int argJointCapacity, ContactListener argListener) #

void init(int argBodyCapacity, int argContactCapacity, int argJointCapacity,
    ContactListener argListener) {
  bodyCapacity = argBodyCapacity;
  contactCapacity = argContactCapacity;
  jointCapacity = argJointCapacity;
  bodyCount = 0;
  contactCount = 0;

  listener = argListener;

  if (bodies == null || bodyCapacity > bodies.length) {
    bodies = new List<Body>(bodyCapacity);
  }
  if (contacts == null || contactCapacity > contacts.length) {
    contacts = new List<Contact>(contactCapacity);
  }
  if (joints == null || jointCapacity > joints.length) {
    joints = new List<Joint>(jointCapacity);
  }

  // dynamic array
  if (velocities == null || bodyCapacity > velocities.length) {
    final List<Velocity> old = velocities == null ?
        new List<Velocity>(0) : velocities;
    velocities = new List<Velocity>(bodyCapacity);
    velocities.setRange(0, old.length, old);
    for (int i=old.length; i<velocities.length; i++) {
      velocities[i] = new Velocity();
    }
  }

  // dynamic array
  if(positions == null || bodyCapacity > positions.length){
    List<Position> old = positions == null ?
        new List<Position>(0) : positions;
    positions = new List<Position>(bodyCapacity);
    positions.setRange(0, old.length, old);
    for (int i=old.length; i<positions.length; i++) {
      positions[i] = new Position();
    }
  }
}

new Island() #

Island() :
  _contactSolver = new ContactSolver(),
  _translation = new Vector(),
  impulse = new ContactImpulse() { }

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

void report(List<ContactConstraint> constraints) #

void report(List<ContactConstraint> constraints){
  if (listener == null){
    return;
  }

  for (int i = 0; i < contactCount; ++i){
    Contact c = contacts[i];

    ContactConstraint cc = constraints[i];

    for (int j = 0; j < cc.pointCount; ++j){
      impulse.normalImpulses[j] = cc.points[j].normalImpulse;
      impulse.tangentImpulses[j] = cc.points[j].tangentImpulse;
    }

    listener.postSolve(c, impulse);
  }
}

void solve(TimeStep step, Vector gravity, bool allowSleep) #

void solve(TimeStep step, Vector gravity, bool allowSleep){
  // Integrate velocities and apply damping.
  for (int i = 0; i < bodyCount; ++i){
    Body b = bodies[i];

    if (b.type != BodyType.DYNAMIC){
      continue;
    }

    final velocityDelta = new Vector(
        (b._force.x * b.invMass + gravity.x) * step.dt,
        (b._force.y * b.invMass + gravity.y) * step.dt);
    b.linearVelocity.addLocal(velocityDelta);
    num newAngularVelocity = b.angularVelocity +
        (step.dt * b.invInertia * b._torque);
    b.angularVelocity = newAngularVelocity;

    num a = (1.0 - step.dt * b.linearDamping);
    num a1 = (0.0 > (a < 1.0 ? a : 1.0) ? 0.0 : (a < 1.0 ? a : 1.0));
    b.linearVelocity.mulLocal(a1);

    num a2 = (1.0 - step.dt * b.angularDamping);
    num b1 = (a2 < 1.0 ? a2 : 1.0);
    b.angularVelocity *= 0.0 > b1 ? 0.0 : b1;
  }

  // Partition contacts so that contacts with static bodies are solved last.
  int i1 = -1;
  for (int i2 = 0; i2 < contactCount; ++i2) {
    Fixture fixtureA = contacts[i2].fixtureA;
    Fixture fixtureB = contacts[i2].fixtureB;
    Body bodyA = fixtureA.body;
    Body bodyB = fixtureB.body;
    bool nonStatic = bodyA.type != BodyType.STATIC && bodyB.type
        != BodyType.STATIC;
    if (nonStatic){
      ++i1;
      //Swap(contacts[i1], contacts[i2]);
      Contact temp = contacts[i1];
      contacts[i1] = contacts[i2];
      contacts[i2] = temp;
    }
  }

  // Initialize velocity constraints.
  _contactSolver.init(contacts, contactCount, step.dtRatio);
  _contactSolver.warmStart();

  for (int i = 0; i < jointCount; ++i){
    joints[i].initVelocityConstraints(step);
  }

  for (int i = 0; i < step.velocityIterations; ++i) {
    for (int j = 0; j < jointCount; ++j){
      joints[j].solveVelocityConstraints(step);
    }
    _contactSolver.solveVelocityConstraints();
  }

  // Post-solve (store impulses for warm starting).
  _contactSolver.storeImpulses();

  // Integrate positions.
  Vector temp = new Vector();
  for (int i = 0; i < bodyCount; ++i){
    Body b = bodies[i];

    if (b.type == BodyType.STATIC){
      continue;
    }

    // Check for large velocities.
    _translation.setFrom(b.linearVelocity);
    _translation.mulLocal(step.dt);
    if (Vector.dot(_translation, _translation) >
        Settings.MAX_TRANSLATION_SQUARED){
      num ratio = Settings.MAX_TRANSLATION / _translation.length;
      b.linearVelocity.mulLocal(ratio);
    }

    num rotation = step.dt * b.angularVelocity;
    if (rotation * rotation > Settings.MAX_ROTATION_SQUARED) {
      num ratio = Settings.MAX_ROTATION / rotation.abs();
      b.angularVelocity *= ratio;
    }

    // Store positions for continuous collision.
    b.sweep.centerZero.setFrom(b.sweep.center);
    b.sweep.angleZero = b.sweep.angle;

    // Integrate
    temp.setFrom(b.linearVelocity);
    temp.mulLocal(step.dt);
    b.sweep.center.addLocal(temp);
    b.sweep.angle += step.dt * b.angularVelocity;

    // Compute new transform
    b.synchronizeTransform();

    // Note: shapes are synchronized later.
  }

  // Iterate over constraints.
  for (int i = 0; i < step.positionIterations; ++i){
    bool contactsOkay =
        _contactSolver.solvePositionConstraints(Settings.CONTACT_BAUMGARTE);

    bool jointsOkay = true;
    for (int j = 0; j < jointCount; ++j){
      bool jointOkay =
          joints[j].solvePositionConstraints(Settings.CONTACT_BAUMGARTE);
      jointsOkay = jointsOkay && jointOkay;
    }

    if (contactsOkay && jointsOkay){
      // Exit early if the position errors are small.
      break;
    }
  }

  report(_contactSolver.constraints);


  if (allowSleep){
    num minSleepTime = Settings.BIG_NUMBER;

    num linTolSqr = Settings.LINEAR_SLEEP_TOLERANCE
        * Settings.LINEAR_SLEEP_TOLERANCE;
    num angTolSqr = Settings.ANGULAR_SLEEP_TOLERANCE
        * Settings.ANGULAR_SLEEP_TOLERANCE;

    for (int i = 0; i < bodyCount; ++i){
      Body b = bodies[i];
      if (b.type == BodyType.STATIC){
        continue;
      }

      if ((b.flags & Body.AUTO_SLEEP_FLAG) == 0){
        b.sleepTime = 0.0;
        minSleepTime = 0.0;
      }

      if ((b.flags & Body.AUTO_SLEEP_FLAG) == 0 ||
          b.angularVelocity * b.angularVelocity > angTolSqr ||
          Vector.dot(b.linearVelocity, b.linearVelocity) > linTolSqr){
        b.sleepTime = 0.0;
        minSleepTime = 0.0;
      }
      else{
        b.sleepTime += step.dt;
        minSleepTime = Math.min(minSleepTime, b.sleepTime);
      }
    }

    if (minSleepTime >= Settings.TIME_TO_SLEEP){
      for (int i = 0; i < bodyCount; ++i){
        Body b = bodies[i];
        b.awake = false;
      }
    }
  }

}

String toString() #

inherited from Object

Returns a string representation of this object.

external String toString();