コード例 #1
0
void ribi::Boenken::SpriteMoving::Collision(SpriteMoving * const p1, SpriteMoving * const p2)
{
  assert(p1!=p2);
  assert(p1 > p2);
  const double dx = p2->getX() - p1->getX();
  const double dy = p2->getY() - p1->getY();
  const double distance = std::sqrt((dy * dy) + (dx * dx));
  const double collision_distance
    = boost::numeric_cast<double>(p1->m_size + p2->m_size) / 2.0;
  if (distance < collision_distance)
  {
    //A collision!
    //Obtain the relative angle between the players
    const double a = GetAngle(dx,dy);
    //Obtain the players' current impulses
    double p1_a = p1->CalcImpulseAngle();
    double p1_s = p1->CalcImpulseSpeed();
    double p2_a = p2->CalcImpulseAngle();
    double p2_s = p2->CalcImpulseSpeed();
    //Obtain the new impulses
    DoPerfectElasticCollision(a, p1_a,p1_s,p2_a,p2_s);
    //Set the players' new impulses
    const double dx1 =  std::sin(p1_a) * p1_s;
    const double dy1 = -std::cos(p1_a) * p1_s;
    const double dx2 =  std::sin(p2_a) * p2_s;
    const double dy2 = -std::cos(p2_a) * p2_s;
    p1->SetSpeed(dx1,dy1);
    p2->SetSpeed(dx2,dy2);
    //std::clog << "New impulses: (" << dx1 << "," << dy1 << ")"
    //  << " (" << dx2 << "," << dy2 << ")\n";
    //Let them move away from each perpendicalar to the collision axis
    {
      const double go_away_distance = collision_distance - distance;
      assert(go_away_distance > 0);
      const double pi = boost::math::constants::pi<double>();
      const double go_away_dx1 =  std::sin(a + pi) * (go_away_distance / 2.0);
      const double go_away_dy1 = -std::cos(a + pi) * (go_away_distance / 2.0);
      const double go_away_dx2 =  std::sin(a + 0.0) * (go_away_distance / 2.0);
      const double go_away_dy2 = -std::cos(a + 0.0) * (go_away_distance / 2.0);
      p1->Move(go_away_dx1,go_away_dy1);
      p2->Move(go_away_dx2,go_away_dy2);
    }
    //Let the players move again
    p1->Move();
    p2->Move();
    #ifndef NDEBUG
    {
      const double new_dx = p2->getX() - p1->getX();
      const double new_dy = p2->getY() - p1->getY();
      const double new_distance = std::sqrt((new_dy * new_dy) + (new_dx * new_dx));
      if (new_distance < distance)
      {
        //std::clog << "Players should in general move away after a collision\n";
      }
      //assert(new_distance > distance && "Players should move away after a collision");
    }
    #endif
  }
}
コード例 #2
0
void ribi::bnkn::SpriteNonMoving::Collision(
  const SpriteNonMoving& obstacle, SpriteMoving& moving
)
{
  if (!IsCollision(obstacle,moving)) return;
  /*

    O     -
          |
          | dy (in this case > 0)
          |
        M -
    |---|
      dx (in this case > 0)
  */
  const double dx = moving.getX() - obstacle.getX();
  const double dy = moving.getY() - obstacle.getY();
  //const double collision_distance
  //  = boost::numeric_cast<double>(obstacle.m_size + moving.m_size) / 2.0;
  //Obtain the relative angle between the players

  /*

    O
     \
      \
       \
        M

  angle_players in this case 135 degrees

  */
  const double angle_players = Geometry().GetAngleClockScreen(dx,dy);

  //Obtain the moving sprite's current impulse
  double moving_angle = moving.CalcImpulseAngle();
  double moving_speed = moving.CalcImpulseSpeed();
  //Obstacles have opposite impulse
  const double pi = boost::math::constants::pi<double>();
  double obstacle_angle = moving_angle + pi;
  double obstancle_speed = moving_speed;
  //Obtain the new impulses
  DoPerfectElasticCollision(
    angle_players, obstacle_angle,obstancle_speed,moving_angle,moving_speed
  );
  //Set the player's new impulse
  const double dx2 =  std::sin(moving_angle) * moving_speed;
  const double dy2 = -std::cos(moving_angle) * moving_speed;
  moving.SetSpeed(dx2,dy2);
  //Let the player move again
  moving.Move();
}
コード例 #3
0
ファイル: main.cpp プロジェクト: RLED/ProjectRichelBilderbeek
  void advance(int phase)
  {
    if (phase == 0)
    {
      //Bounce against others
      QList<QGraphicsItem*> others = this->collidingItems();
      const int n_others = others.size();
      for (int i=0; i!=n_others; ++i)
      {
        SirSprite * const other = dynamic_cast<SirSprite*>(others[i]);
        if (!other) continue;
        if (other == this) continue;
        //Ensure checking is only done once per colliding pair
        if (this->zValue() < other->zValue()) continue;
        //Relative between players 1 and 2
        const double dx_between = other->x() - this->x();
        const double dy_between = other->y() - this->y();
        const double angle_between = GetAngle(dx_between,dy_between);
        //For this player
        const double this_dx = std::cos(this->angle) * this->speed;
        const double this_dy = -std::sin(this->angle) * this->speed;
        double this_angle = GetAngle( this_dx, this_dy);
        double this_speed = std::sqrt((this_dy * this_dy) + (this_dx * this_dx));
        //For other player
        const double other_dx = std::cos(other->angle) * other->speed;
        const double other_dy = -std::sin(other->angle) * other->speed;
        double other_angle = GetAngle( other_dx, other_dy);
        double other_speed = std::sqrt((other_dy * other_dy) + (other_dx * other_dx));

        DoPerfectElasticCollision(
          angle_between,
          this_angle,
          this_speed,
          other_angle,
          other_speed);

        this->angle = this_angle;
        this->speed = this_speed;
        other->angle = other_angle;
        other->speed = other_speed;
        //Let them move once
        setX(x() + (std::sin(angle) * speed));
        setY(y() - (std::cos(angle) * speed));
        other->setX(other->x() + (std::sin(other->angle) * other->speed));
        other->setY(other->y() - (std::cos(other->angle) * other->speed));
        //Infection?
        if (this->state == infected && other->state == susceptible)
        {
          other->setState(infected);
        }
        if (other->state == infected && this->state == susceptible)
        {
          this->setState(infected);
        }
      }
    }
    //Bounce against the edges
    else if (phase == 1)
    {
      while (1)
      {
        #ifdef __STRICT_ANSI__
        const double pi = boost::math::constants::pi<double>();
        #else
        const double pi = M_PI;
        #endif
        setX(x() + (std::sin(angle) * speed));
        setY(y() - (std::cos(angle) * speed));
        if (x() < 0.0) { setX(x()+1); angle = (0.0*pi) + ((0.0*pi) - angle); continue; }
        if (y() < 0.0) { setY(y()+1); angle = (0.5*pi) + ((0.5*pi) - angle); continue; }
        if (x() > maxx) { setX(x()-1); angle = (1.0*pi) + ((1.0*pi) - angle); continue; }
        if (y() > maxy) { setY(y()-1); angle = (1.5*pi) + ((1.5*pi) - angle); continue; }
        break;
      }
      //Resistance?
      if (state == infected && timer.elapsed() > 5.0) setState(resistant);
    }
  }