Beispiel #1
0
void
Sector::draw(DrawingContext& context)
{
  context.set_ambient_color( ambient_light );
  context.push_transform();
  context.set_translation(camera->get_translation());

  for(auto i = gameobjects.begin(); i != gameobjects.end(); ++i) {
    GameObjectPtr& object = *i;
    if(!object->is_valid())
      continue;

    if (draw_solids_only)
    {
      TileMap* tm = dynamic_cast<TileMap*>(object.get());
      if (tm && !tm->is_solid())
        continue;
    }

    object->draw(context);
  }

  if(show_collrects) {
    Color color(1.0f, 0.0f, 0.0f, 0.75f);
    for(auto i = moving_objects.begin(); i != moving_objects.end(); ++i) {
      MovingObject* object = *i;
      const Rectf& rect = object->get_bbox();

      context.draw_filled_rect(rect, color, LAYER_FOREGROUND1 + 10);
    }
  }

  context.pop_transform();
}
Beispiel #2
0
HitResponse
BonusBlock::collision(GameObject& other, const CollisionHit& hit_){

  Player* player = dynamic_cast<Player*> (&other);
  if (player) {
    if (player->does_buttjump)
      try_drop(player);
  }

  BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
  if(badguy) {
    // hit contains no information for collisions with blocks.
    // Badguy's bottom has to be below the top of the block
    // SHIFT_DELTA is required to slide over one tile gaps.
    if( badguy->can_break() && ( badguy->get_bbox().get_bottom() > bbox.get_top() + SHIFT_DELTA ) ){
      try_open(player);
    }
  }
  Portable* portable = dynamic_cast<Portable*> (&other);
  if(portable) {
    MovingObject* moving = dynamic_cast<MovingObject*> (&other);
    if(moving->get_bbox().get_top() > bbox.get_bottom() - SHIFT_DELTA) {
      try_open(player);
    }
  }
  return Block::collision(other, hit_);
}
void
FlipLevelTransformer::transform_moving_object(float height, MovingObject& object)
{
  Vector pos = object.get_pos();
  pos.y = height - pos.y - object.get_bbox().get_height();
  object.set_pos(pos);
}
Beispiel #4
0
HitResponse
Brick::collision(GameObject& other, const CollisionHit& hit_){

  Player* player = dynamic_cast<Player*> (&other);
  if (player) {
    if (player->does_buttjump) try_break(player);
    if (player->is_stone() && player->get_velocity().y >= 280) try_break(player); // stoneform breaks through bricks
  }

  BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
  if(badguy) {
    // hit contains no information for collisions with blocks.
    // Badguy's bottom has to be below the top of the brick
    // SHIFT_DELTA is required to slide over one tile gaps.
    if( badguy->can_break() && ( badguy->get_bbox().get_bottom() > bbox.get_top() + SHIFT_DELTA ) ){
      try_break(player);
    }
  }
  Portable* portable = dynamic_cast<Portable*> (&other);
  if(portable) {
    MovingObject* moving = dynamic_cast<MovingObject*> (&other);
    if(moving->get_bbox().get_top() > bbox.get_bottom() - SHIFT_DELTA) {
      try_break(player);
    }
  }
  Explosion* explosion = dynamic_cast<Explosion*> (&other);
  if(explosion && explosion->hurts()) {
    try_break(player);
  }
  IceCrusher* icecrusher = dynamic_cast<IceCrusher*> (&other);
  if(icecrusher && coin_counter == 0)
    try_break(player);
  return Block::collision(other, hit_);
}
Beispiel #5
0
void
Sector::collision_tilemap(collision::Constraints* constraints,
                          const Vector& movement, const Rectf& dest,
                          MovingObject& object) const
{
  // calculate rectangle where the object will move
  float x1 = dest.get_left();
  float x2 = dest.get_right();
  float y1 = dest.get_top();
  float y2 = dest.get_bottom();

  for(auto i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) {
    TileMap* solids = *i;

    // test with all tiles in this rectangle
    Rect test_tiles = solids->get_tiles_overlapping(Rectf(x1, y1, x2, y2));

    for(int x = test_tiles.left; x < test_tiles.right; ++x) {
      for(int y = test_tiles.top; y < test_tiles.bottom; ++y) {
        const Tile* tile = solids->get_tile(x, y);
        if(!tile)
          continue;
        // skip non-solid tiles
        if(!tile->is_solid ())
          continue;
        Rectf tile_bbox = solids->get_tile_bbox(x, y);

        /* If the tile is a unisolid tile, the "is_solid()" function above
         * didn't do a thorough check. Calculate the position and (relative)
         * movement of the object and determine whether or not the tile is
         * solid with regard to those parameters. */
        if(tile->is_unisolid ()) {
          Vector relative_movement = movement
            - solids->get_movement(/* actual = */ true);

          if (!tile->is_solid (tile_bbox, object.get_bbox(), relative_movement))
            continue;
        } /* if (tile->is_unisolid ()) */

        if(tile->is_slope ()) { // slope tile
          AATriangle triangle;
          int slope_data = tile->getData();
          if (solids->get_drawing_effect() & VERTICAL_FLIP)
            slope_data = AATriangle::vertical_flip(slope_data);
          triangle = AATriangle(tile_bbox, slope_data);

          collision::rectangle_aatriangle(constraints, dest, triangle,
              solids->get_movement(/* actual = */ false));
        } else { // normal rectangular tile
          check_collisions(constraints, movement, dest, tile_bbox, NULL, NULL,
              solids->get_movement(/* actual = */ false));
        }
      }
    }
  }
}
Beispiel #6
0
bool
Igel::can_see(const MovingObject& o) const
{
  Rectf ob = o.get_bbox();

  bool inReach_left = ((ob.p2.x < bbox.p1.x) && (ob.p2.x >= bbox.p1.x-((dir == LEFT) ? RANGE_OF_VISION : 0)));
  bool inReach_right = ((ob.p1.x > bbox.p2.x) && (ob.p1.x <= bbox.p2.x+((dir == RIGHT) ? RANGE_OF_VISION : 0)));
  bool inReach_top = (ob.p2.y >= bbox.p1.y);
  bool inReach_bottom = (ob.p1.y <= bbox.p2.y);

  return ((inReach_left || inReach_right) && inReach_top && inReach_bottom);
}
HitResponse
PneumaticPlatform::collision(GameObject& other, const CollisionHit& )
{

  // somehow the hit parameter does not get filled in, so to determine (hit.top == true) we do this:
  MovingObject* mo = dynamic_cast<MovingObject*>(&other);
  if (!mo) return FORCE_MOVE;
  if ((mo->get_bbox().p2.y) > (get_bbox().p1.y + 2)) return FORCE_MOVE;

  Player* pl = dynamic_cast<Player*>(mo);
  if (pl) {
    if (pl->is_big()) contacts.insert(0);
    Portable* po = pl->get_grabbed_object();
    MovingObject* pomo = dynamic_cast<MovingObject*>(po);
    if (pomo) contacts.insert(pomo);
  }

  contacts.insert(&other);
  return FORCE_MOVE;
}
Beispiel #8
0
HitResponse
Brick::collision(GameObject& other, const CollisionHit& hit){
    BadGuy* badguy = dynamic_cast<BadGuy*> (&other);
    if(badguy) {
      // hit contains no information for collisions with blocks.
      // Badguy's bottom has to be below the top of the brick
      // +7 is required to slide over one tile gaps.
      if( badguy->can_break() && ( badguy->get_bbox().get_bottom() > get_bbox().get_top() + 7.0 ) ){
        try_break(false);
      }
    }
    Portable* portable = dynamic_cast<Portable*> (&other);
    if(portable) {
      MovingObject* moving = dynamic_cast<MovingObject*> (&other);
      if(moving->get_bbox().get_top() > get_bbox().get_bottom() - 7.0) {
        try_break();
      }
    }
   return Block::collision(other, hit);
}
HitResponse
BicyclePlatform::collision(GameObject& other, const CollisionHit& )
{

    // somehow the hit parameter does not get filled in, so to determine (hit.top == true) we do this:
    MovingObject* mo = dynamic_cast<MovingObject*>(&other);
    if (!mo) return FORCE_MOVE;
    if ((mo->get_bbox().p2.y) > (bbox.p1.y + 2)) return FORCE_MOVE;

    Player* pl = dynamic_cast<Player*>(mo);
    if (pl) {
        if (pl->is_big()) momentum += 0.1 * Sector::current()->get_gravity();
        Portable* po = pl->get_grabbed_object();
        MovingObject* pomo = dynamic_cast<MovingObject*>(po);
        if (contacts.insert(pomo).second) momentum += 0.1 * Sector::current()->get_gravity();
    }

    if (contacts.insert(&other).second) momentum += 0.1 * Sector::current()->get_gravity();
    return FORCE_MOVE;
}
Beispiel #10
0
void
AngryStone::active_update(float elapsed_time) {
  BadGuy::active_update(elapsed_time);

  if (frozen) {
    return;
  }

  switch (state) {


    case IDLE: {
      MovingObject* player = get_nearest_player();
      if(player) {
        MovingObject* badguy = this;
        const Vector playerPos = player->get_pos();
        const Vector badguyPos = badguy->get_pos();
        float dx = (playerPos.x - badguyPos.x);
        float dy = (playerPos.y - badguyPos.y);

        float playerHeight = player->get_bbox().get_height();
        float badguyHeight = badguy->get_bbox().get_height();

        float playerWidth = player->get_bbox().get_width();
        float badguyWidth = badguy->get_bbox().get_width();

        if ((dx > -playerWidth) && (dx < badguyWidth)) {
          if (dy > 0) {
            attackDirection.x = 0;
            attackDirection.y = 1;
          } else {
            attackDirection.x = 0;
            attackDirection.y = -1;
          }
          if ((attackDirection.x != oldWallDirection.x) || (attackDirection.y != oldWallDirection.y)) {
            sprite->set_action("charging");
            timer.start(CHARGE_TIME);
            state = CHARGING;
          }
        } else if ((dy > -playerHeight) && (dy < badguyHeight)) {
          if (dx > 0) {
            attackDirection.x = 1;
            attackDirection.y = 0;
          } else {
            attackDirection.x = -1;
            attackDirection.y = 0;
          }
          if ((attackDirection.x != oldWallDirection.x) || (attackDirection.y != oldWallDirection.y)) {
            sprite->set_action("charging");
            timer.start(CHARGE_TIME);
            state = CHARGING;
          }
        }
      }
    } break;

    case CHARGING: {
      if (timer.check()) {
        sprite->set_action("attacking");
        timer.start(ATTACK_TIME);
        state = ATTACKING;
        physic.enable_gravity(false);
        physic.set_velocity_x(CHARGE_SPEED * attackDirection.x);
        physic.set_velocity_y(CHARGE_SPEED * attackDirection.y);
        oldWallDirection.x = 0;
        oldWallDirection.y = 0;
      }
    } break;

    case ATTACKING: {
      if (timer.check()) {
        timer.start(RECOVER_TIME);
        state = RECOVERING;
        sprite->set_action("idle");
        physic.enable_gravity(true);
        physic.set_velocity_x(0);
        physic.set_velocity_y(0);
      }
    } break;

    case RECOVERING: {
      if (timer.check()) {
        state = IDLE;
        sprite->set_action("idle");
        physic.enable_gravity(true);
        physic.set_velocity_x(0);
        physic.set_velocity_y(0);
      }
    } break;
  }

}
Beispiel #11
0
void
Explosion::explode()
{
  if (state != STATE_WAITING)
    return;
  state = STATE_EXPLODING;

  set_action(hurt ? "default" : "pop", 1);
  sprite->set_animation_loops(1); //TODO: this is necessary because set_action will not set "loops" when "action" is the default action
  sprite->set_angle(graphicsRandom.randf(0, 360)); // a random rotation on the sprite to make explosions appear more random
  SoundManager::current()->play(hurt ? "sounds/explosion.wav" : "sounds/firecracker.ogg", get_pos());

#if 0
  // spawn some particles
  // TODO: provide convenience function in MovingSprite or MovingObject?
  for (int i = 0; i < 100; i++) {
    Vector ppos = bbox.get_middle();
    float angle = graphicsRandom.randf(-M_PI_2, M_PI_2);
    float velocity = graphicsRandom.randf(450, 900);
    float vx = sin(angle)*velocity;
    float vy = -cos(angle)*velocity;
    Vector pspeed = Vector(vx, vy);
    Vector paccel = Vector(0, 1000);
    Sector::current()->add_object(new SpriteParticle("images/objects/particles/explosion.sprite", "default", ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS-1));
  }
#endif

  if (push) {
    Vector center = get_bbox ().get_middle ();
    std::vector<MovingObject*> near_objects = Sector::current()->get_nearby_objects (center, 10.0 * 32.0);

    for (size_t i = 0; i < near_objects.size (); i++) {
      MovingObject *obj = near_objects[i];
      Vector obj_vector = obj->get_bbox ().get_middle ();
      Vector direction = obj_vector - center;
      float distance = direction.norm ();

      /* If the distance is very small, for example because "obj" is the badguy
       * causing the explosion, skip this object. */
      if (distance <= 1.0)
        continue;

      /* The force decreases with the distance squared. In the distance of one
       * tile (32 pixels) you will have a speed increase of 150 pixels/s. */
      float force = 150.0 * 32.0*32.0 / (distance * distance);
      if (force > 200.0)
        force = 200.0;

      Vector add_speed = direction.unit () * force;

      Player *player = dynamic_cast<Player *> (obj);
      if (player) {
        player->add_velocity (add_speed);
      }

      WalkingBadguy *badguy = dynamic_cast<WalkingBadguy *> (obj);
      if (badguy) {
        badguy->add_velocity (add_speed);
      }
    } /* for (i = 0 ... near_objects) */
  } /* if (push) */
}
void
Sector::collision_static_constrains(MovingObject& object)
{
  using namespace collision;
  float infinity = (std::numeric_limits<float>::has_infinity ? std::numeric_limits<float>::infinity() : std::numeric_limits<float>::max());

  Constraints constraints;
  Vector movement = object.get_movement();
  Rect& dest = object.dest;
  float owidth = object.get_bbox().get_width();
  float oheight = object.get_bbox().get_height();

  for(int i = 0; i < 2; ++i) {
    collision_static(&constraints, Vector(0, movement.y), dest, object);
    if(!constraints.has_constraints())
      break;

    // apply calculated horizontal constraints
    if(constraints.bottom < infinity) {
      float height = constraints.bottom - constraints.top;
      if(height < oheight) {
        // we're crushed, but ignore this for now, we'll get this again
        // later if we're really crushed or things will solve itself when
        // looking at the vertical constraints
      }
      dest.p2.y = constraints.bottom - DELTA;
      dest.p1.y = dest.p2.y - oheight;
    } else if(constraints.top > -infinity) {
      dest.p1.y = constraints.top + DELTA;
      dest.p2.y = dest.p1.y + oheight;
    }
  }
  if(constraints.has_constraints()) {
    if(constraints.hit.bottom) {
      dest.move(constraints.ground_movement);
    }
    if(constraints.hit.top || constraints.hit.bottom) {
      constraints.hit.left = false;
      constraints.hit.right = false;
      object.collision_solid(constraints.hit);
    }
  }

  constraints = Constraints();
  for(int i = 0; i < 2; ++i) {
    collision_static(&constraints, movement, dest, object);
    if(!constraints.has_constraints())
      break;

    // apply calculated vertical constraints
    if(constraints.right < infinity) {
      float width = constraints.right - constraints.left;
      if(width + SHIFT_DELTA < owidth) {
        printf("Object %p crushed horizontally... L:%f R:%f\n", &object,
            constraints.left, constraints.right);
        CollisionHit h;
        h.left = true;
        h.right = true;
        h.crush = true;
        object.collision_solid(h);
      } else {
        dest.p2.x = constraints.right - DELTA;
        dest.p1.x = dest.p2.x - owidth;
      }
    } else if(constraints.left > -infinity) {
      dest.p1.x = constraints.left + DELTA;
      dest.p2.x = dest.p1.x + owidth;
    }
  }

  if(constraints.has_constraints()) {
    if( constraints.hit.left || constraints.hit.right
        || constraints.hit.top || constraints.hit.bottom
        || constraints.hit.crush )
      object.collision_solid(constraints.hit);
  }

  // an extra pass to make sure we're not crushed horizontally
  constraints = Constraints();
  collision_static(&constraints, movement, dest, object);
  if(constraints.bottom < infinity) {
    float height = constraints.bottom - constraints.top;
    if(height + SHIFT_DELTA < oheight) {
      printf("Object %p crushed vertically...\n", &object);
      CollisionHit h;
      h.top = true;
      h.bottom = true;
      h.crush = true;
      object.collision_solid(h);
    }
  }
}
Beispiel #13
0
void
Sector::collision_static_constrains(MovingObject& object)
{
  using namespace collision;
  float infinity = (std::numeric_limits<float>::has_infinity ? std::numeric_limits<float>::infinity() : std::numeric_limits<float>::max());

  Constraints constraints;
  Vector movement = object.get_movement();
  Vector pressure = Vector(0,0);
  Rectf& dest = object.dest;

  for(int i = 0; i < 2; ++i) {
    collision_static(&constraints, Vector(0, movement.y), dest, object);
    if(!constraints.has_constraints())
      break;

    // apply calculated horizontal constraints
    if(constraints.get_position_bottom() < infinity) {
      float height = constraints.get_height ();
      if(height < object.get_bbox().get_height()) {
        // we're crushed, but ignore this for now, we'll get this again
        // later if we're really crushed or things will solve itself when
        // looking at the vertical constraints
        pressure.y += object.get_bbox().get_height() - height;
      } else {
        dest.p2.y = constraints.get_position_bottom() - DELTA;
        dest.p1.y = dest.p2.y - object.get_bbox().get_height();
      }
    } else if(constraints.get_position_top() > -infinity) {
      dest.p1.y = constraints.get_position_top() + DELTA;
      dest.p2.y = dest.p1.y + object.get_bbox().get_height();
    }
  }
  if(constraints.has_constraints()) {
    if(constraints.hit.bottom) {
      dest.move(constraints.ground_movement);
    }
    if(constraints.hit.top || constraints.hit.bottom) {
      constraints.hit.left = false;
      constraints.hit.right = false;
      object.collision_solid(constraints.hit);
    }
  }

  constraints = Constraints();
  for(int i = 0; i < 2; ++i) {
    collision_static(&constraints, movement, dest, object);
    if(!constraints.has_constraints())
      break;

    // apply calculated vertical constraints
    float width = constraints.get_width ();
    if(width < infinity) {
      if(width + SHIFT_DELTA < object.get_bbox().get_width()) {
        // we're crushed, but ignore this for now, we'll get this again
        // later if we're really crushed or things will solve itself when
        // looking at the horizontal constraints
        pressure.x += object.get_bbox().get_width() - width;
      } else {
        float xmid = constraints.get_x_midpoint ();
        dest.p1.x = xmid - object.get_bbox().get_width()/2;
        dest.p2.x = xmid + object.get_bbox().get_width()/2;
      }
    } else if(constraints.get_position_right() < infinity) {
      dest.p2.x = constraints.get_position_right() - DELTA;
      dest.p1.x = dest.p2.x - object.get_bbox().get_width();
    } else if(constraints.get_position_left() > -infinity) {
      dest.p1.x = constraints.get_position_left() + DELTA;
      dest.p2.x = dest.p1.x + object.get_bbox().get_width();
    }
  }

  if(constraints.has_constraints()) {
    if( constraints.hit.left || constraints.hit.right
        || constraints.hit.top || constraints.hit.bottom
        || constraints.hit.crush )
      object.collision_solid(constraints.hit);
  }

  // an extra pass to make sure we're not crushed vertically
  if (pressure.y > 0) {
    constraints = Constraints();
    collision_static(&constraints, movement, dest, object);
    if(constraints.get_position_bottom() < infinity) {
      float height = constraints.get_height ();
      if(height + SHIFT_DELTA < object.get_bbox().get_height()) {
        CollisionHit h;
        h.top = true;
        h.bottom = true;
        h.crush = pressure.y > 16;
        object.collision_solid(h);
      }
    }
  }

  // an extra pass to make sure we're not crushed horizontally
  if (pressure.x > 0) {
    constraints = Constraints();
    collision_static(&constraints, movement, dest, object);
    if(constraints.get_position_right() < infinity) {
      float width = constraints.get_width ();
      if(width + SHIFT_DELTA < object.get_bbox().get_width()) {
        CollisionHit h;
        h.top = true;
        h.bottom = true;
        h.left = true;
        h.right = true;
        h.crush = pressure.x > 16;
        object.collision_solid(h);
      }
    }
  }
}