예제 #1
0
/**
 * @brief Sets the x speed.
 * @param x_speed the x speed of the object in pixels per second
 */
void StraightMovement::set_x_speed(double x_speed) {

  if (std::fabs(x_speed) <= 1E-6) {
    x_speed = 0;
  }

  this->x_speed = x_speed;
  uint32_t now = System::now();

  // compute x_delay, x_move and next_move_date_x
  if (x_speed == 0) {
    x_move = 0;
  }
  else {
    if (x_speed > 0) {
      x_delay = (uint32_t) (1000 / x_speed);
      x_move = 1;
    }
    else {
      x_delay = (uint32_t) (1000 / (-x_speed));
      x_move = -1;
    }
    set_next_move_date_x(now + x_delay);
  }
  angle = Geometry::get_angle(0, 0, (int) (x_speed * 100), (int) (y_speed * 100));
  initial_xy.set_xy(get_xy());
  finished = false;

  if (get_entity() != NULL) {
    get_entity()->notify_movement_changed();
  }
}
예제 #2
0
/**
 * \brief Updates this state.
 */
void Hero::BoomerangState::update() {

  State::update();

  Hero& hero = get_entity();
  if (hero.is_animation_finished()) {

    if (direction_pressed8 == -1) {
      // the player can press the diagonal arrows before or after the boomerang key
      direction_pressed8 = get_commands().get_wanted_direction8();
    }

    int boomerang_direction8;
    if (direction_pressed8 == -1 || direction_pressed8 % 2 == 0) {
      boomerang_direction8 = get_sprites().get_animation_direction() * 2;
    }
    else {
      boomerang_direction8 = direction_pressed8;
    }
    double angle = Geometry::degrees_to_radians(boomerang_direction8 * 45);
    get_entities().add_entity(std::make_shared<Boomerang>(
        std::static_pointer_cast<Hero>(get_entity().shared_from_this()),
        max_distance,
        speed,
        angle,
        sprite_name
    ));

    hero.set_state(new FreeState(hero));
  }
}
예제 #3
0
void StraightMovement::set_speed_y(double speed_yy) {
	if(std::fabs(speed_yy) <= 1E-6) {
		speed_yy = 0;
	}
	this->speed_y = speed_yy;
	uint32_t now = System::now();

	// compute delay_x, move_x, next_move_date_x.
	if(speed_y > 0) {
		this->delay_y = (uint32_t) (1000 / this->speed_y);
		move_y = 1;
		set_next_move_date_y(now + delay_y);
	} else if(speed_y < 0) {
		this->delay_y = (uint32_t) (-1000 / this->speed_y);
		move_y = -1;
		set_next_move_date_y(now + delay_y);
	} else {
		move_y = 0;
	}

	this->angle = Geometry::get_angle(0.f, 0.f, speed_x * 100, speed_y * 100);
	start_xy.set_xy(get_xy());
	this->finished = false;

	if(get_entity() != NULL) {
		get_entity()->notify_movement_changed();
	}
}
예제 #4
0
/**
 * Tries to move the top-left corner of the entity towards an intersection of the 8*8 grid of the map.
 * This function is called only when the entity is not already aligned to the grid.
 */
void PathMovement::snap() {

  // calculate the coordinates of the closest grid intersection from the top-left corner of the entity
  int x = get_entity()->get_top_left_x();
  int y = get_entity()->get_top_left_y();
  int snapped_x = x + 4;
  int snapped_y = y + 4;
  snapped_x -= snapped_x % 8;
  snapped_y -= snapped_y % 8;

  uint32_t now = System::now();

  if (!snapping) {
    // if we haven't started to move the entity towards an intersection of the grid, do it now
    set_snapping_trajectory(Rectangle(x, y), Rectangle(snapped_x, snapped_y));
    snapping = true;
    stop_snapping_date = now + 500; // timeout
  }
  else {
    // the entity is currently trying to move towards the closest grid intersection

    uint32_t now = System::now();
    if (now >= stop_snapping_date) {
      // we could not snap the entity after the timeout:
      // this is possible when there is an (unlikely) collision with an obstacle that is not aligned to the grid
      // (typically a statue that is being moved);
      // let's try the opposite grid intersection instead
      snapped_x += (snapped_x < x) ? 8 : -8;
      snapped_y += (snapped_y < y) ? 8 : -8;
      set_snapping_trajectory(Rectangle(x, y), Rectangle(snapped_x, snapped_y));
      stop_snapping_date = now + 500;
    }
  }
}
예제 #5
0
/**
 * \brief Calculates the direction and the speed of the movement
 * depending on the target.
 */
void PathFindingMovement::recompute_movement() {

  if (target != nullptr) {
    PathFinding path_finding(get_entity()->get_map(), *get_entity(), *target);
    std::string path = path_finding.compute_path();

    uint32_t min_delay;
    if (path.size() == 0) {
      // the target is too far or there is no path
      path = create_random_path();

      // no path was found: no need to try again very soon
      // (note that the A* algorithm is very costly when it explores all nodes without finding a solution)
      min_delay = 3000;
    }
    else {
      // a path was found: we need to update it frequently (and the A* algorithm is much faster in general when there is a solution)
      min_delay = 300;
    }
    // compute a new path every random delay to avoid
    // having all path-finding entities of the map compute a path at the same time
    next_recomputation_date = System::now() + min_delay + Random::get_number(200);

    set_path(path);
  }
}
예제 #6
0
void AvatarGameObj::update_geom_offsets() {
  // Update the orientation of our physical geom to match _uprightness
  dMatrix3 grot;
  dRFromAxisAndAngle(grot, 1, 0, 0, _uprightness*M_PI_2);
  dGeomSetOffsetRotation(get_entity().get_geom("physical"), grot);
  
  // Update the position of the sticky_attach geom to match _uprightness
  dGeomSetOffsetPosition(get_entity().get_geom("sticky_attach"), 0, -sin(_uprightness*M_PI_2) + RUNNING_MAX_DELTA_Y_POS, 0);
}
예제 #7
0
void StraightMovement::set_angle(double angle) {
	double speed = get_speed();
	set_speed_x(speed * std::cos(angle));
	set_speed_y(-speed * std::sin(angle));
	this->angle = angle;

	if(get_entity() != NULL) {
		get_entity()->notify_movement_changed();
	}
}
예제 #8
0
/**
 * \brief Determines the direction defined by the directional keys currently pressed
 * and computes the corresponding movement.
 */
void PlayerMovement::set_wanted_direction() {

  if (get_entity() != NULL && get_entity()->is_on_map()) {
    GameCommands& commands = get_entity()->get_game().get_commands();
    direction8 = commands.get_wanted_direction8();
  }
  else {
    direction8 = -1;
  }
}
예제 #9
0
void StraightMovement::stop() {
	double old_angle = this->angle;
	set_speed_x(0);
	set_speed_y(0);
	this->move_x = 0;
	this->move_y = 0;
	this->angle = old_angle;

	if(get_entity() != NULL) {
		get_entity()->notify_movement_finished();
	}
}
예제 #10
0
/**
 * @brief Sets the speed to zero.
 */
void StraightMovement::stop() {

  double old_angle = this->angle;
  set_x_speed(0);
  set_y_speed(0);
  x_move = 0;
  y_move = 0;
  this->angle = old_angle;

  if (get_entity() != NULL) {
    get_entity()->notify_movement_changed();
  }
}
예제 #11
0
/**
 * @brief Changes the direction of the movement vector, keeping the same speed.
 *
 * x_speed and y_speed are recomputed so that the total speed is unchanged.
 * Warning: if x_speed and y_speed are both equal to zero, this function
 * stops the program on an error message.
 *
 * @param angle the new movement direction in radians
 */
void StraightMovement::set_angle(double angle) {

  if (!is_stopped()) {
    double speed = get_speed();
    set_x_speed(speed * std::cos(angle));
    set_y_speed(-speed * std::sin(angle));
  }
  this->angle = angle;

  if (get_entity() != NULL) {
    get_entity()->notify_movement_changed();
  }
}
예제 #12
0
파일: scene3D.cpp 프로젝트: DoubleJump/IMGL
	fn void
	update()
	{
		auto root = get_entity(0);
		if(root->dirty)
		{
			root->world_matrix = mat4::compose(root->position, root->scale, root->rotation);
		}
		for(i32 i = 1; i < scene::ctx->num_entities; ++i)
		{
			auto entity = get_entity(i);
			update_entity(entity);
		}
	}
예제 #13
0
void StraightMovement::set_speed(double speed) {
	if(speed_y == 0 && speed_x == 0) {
		speed_x = 1;
	}

	//compute the new speed vector.
	double old_angle = this->angle;
	set_speed_x(speed * std::cos(old_angle));
	set_speed_y(-speed * std::sin(old_angle));
	this->angle = old_angle;

	if(get_entity() != NULL) {
		get_entity()->notify_movement_changed();
	}
}
예제 #14
0
    bool MatchPool::pop(int size_type, MatchRes &res) {
        std::vector<MatchEntity*> camps;
        for (int i = 0;i < _camp_size; i++) {
            MatchEntity *ent = E_NEW MatchEntity;
            ent->camp = i;
            camps.push_back(ent);
        }

        int success = pop(size_type, camps);

        // merge result
        res.type = _type;
        for (size_t i = 0;i < camps.size(); i++) {
            TeamSet members;
            camps[i]->get_members(members);
            if (!success) {
                // restore
                TeamSet::iterator itr = members.begin();
                for (;itr != members.end(); ++itr) {
                    MatchEntity *ent = get_entity(*itr);
                    if (ent) {
                        ent->status = MATCH_PENDING;
                    }
                }
            } else {
                res.teams.push_back(members);
            }
            S_DELETE(camps[i]);
        }

        return success;
    }
예제 #15
0
std::string InputOutputException::get_message(ModelObject *o) const {
  std::ostringstream oss;
  switch (get_entity()) {
    case DERIVATIVE:
      if (o->get_model()->get_stage() == BEFORE_EVALUATING) {
        oss << "Derivatives cannot be read before evaluating.";
        break;
      }
    default:
      switch (get_operation()) {
        case GET:
          oss << "Not in input list.";
          break;
        case SET:
        case ADD:
        case REMOVE:
          oss << "Not in output list.";
          break;
        default:
          // should not exist
          oss << "Unknown read/write error";
      }
      break;
  };
  oss << " Violating object: \"" << o->get_name() << "\".";
  if (particle_index_ >= 0) {
    oss << " Attribute " << get_key_name() << " of particle \""
        << o->get_model()
               ->get_particle(ParticleIndex(get_particle_index()))
               ->get_name() << "\" with id " << get_particle_index();
  } else {
    oss << "Container \"" << container_name_ << "\".";
  }
  return oss.str();
}
예제 #16
0
파일: scene3D.cpp 프로젝트: DoubleJump/IMGL
	fn void
	set_parent(Scene* scene, Entity* entity, Entity* parent)
	{
		if(parent->id == entity->parent) return;
		if(entity->parent != 0) //remove from children
		{
			auto current_parent = get_entity(entity->parent);
			for(i32 i = 0; i < 8; ++i)
			{
				auto child = current_parent->children[i];
				if(child == entity->id)
				{
					child = -1;
					break;
				}
			}
		}

		entity->parent = parent->id;
		for(i32 i = 0; i < 8; ++i)
		{
			auto child = parent->children[i];
			if(child == -1)
			{
				child = entity->id;
				break;
			}
		}
	}
예제 #17
0
/**
 * \brief Changes the name of an entity.
 * \param index Index of the entity on the map.
 * \param name The new name. An empty string means no name.
 * \return \c true in case of success, \c false if the name was already used.
 */
bool MapData::set_entity_name(const EntityIndex& index, const std::string& name) {

  EntityData& entity = get_entity(index);
  const std::string& old_name = entity.get_name();

  if (name == old_name) {
    // Nothing to do.
    return true;
  }

  if (!name.empty()) {
    if (entity_exists(name)) {
      // This name is already used by another entity.
      return false;
    }
  }

  // Do the change.
  entity.set_name(name);

  if (!old_name.empty()) {
    named_entities.erase(old_name);
  }

  if (!name.empty()) {
    named_entities[name] = index;
  }

  return false;
}
예제 #18
0
/**
 * \brief Updates this state.
 */
void Hero::SwordLoadingState::update() {

  PlayerMovementState::update();

  if (is_suspended() || !is_current_state()) {
    return;
  }

  uint32_t now = System::now();

  // detect when the sword is loaded (i.e. ready for a spin attack)
  if (!sword_loaded && now >= sword_loaded_date) {
    play_load_sound();
    sword_loaded = true;
  }

  if (!get_commands().is_command_pressed(GameCommand::ATTACK)) {
    // the player has just released the sword key

    // stop loading the sword, go to the normal state or make a spin attack
    Hero& hero = get_entity();
    if (!sword_loaded) {
      // the sword was not loaded yet: go to the normal state
      hero.set_state(new FreeState(hero));
    }
    else {
      // the sword is loaded: release a spin attack
      hero.set_state(new SpinAttackState(hero));
    }
  }
}
예제 #19
0
/**
 * \brief Returns control to the hero after its hookshot movement.
 *
 * This function is called when the hero has finished the hookshot movement.
 * It checks the validity of the destination position.
 */
void Hero::HookshotState::finish_movement() {

  Hero& hero = get_entity();
  const Rectangle& hero_position = hero.get_bounding_box();
  int layer = hero.get_layer();
  Map& map = get_map();
  MapEntities& entities = get_entities();

  if (layer == 0 || !map.has_empty_ground(layer, hero_position)) {
    // the hero is totally on the same layer: no problem
    hero.start_state_from_ground();
  }
  else {
    // a part of the hero is on empty tiles: this is often illegal, especially
    // if there are jumpers; allow this only if tiles on
    // the lower layer are not obstacles, and go to this layer
    --layer;
    if (!map.test_collision_with_obstacles(layer, hero_position, hero)) {
      Sound::play("hero_lands");
      entities.set_entity_layer(hero, layer);
      hero.start_state_from_ground();
    }
    else {
      // illegal position: get back to the start point
      // TODO: get back to the closest valid point from the destination instead
      Sound::play("hero_hurt");
      hero.set_state(new BackToSolidGroundState(hero, false, 0, true));
    }
  }
}
예제 #20
0
/**
 * \brief Starts this state.
 * \param previous_state the previous state
 */
void Hero::SpinAttackState::start(const State* previous_state) {

  State::start(previous_state);

  // play the sound
  play_spin_attack_sound();

  // start the animation
  Hero& hero = get_entity();
  if (get_equipment().has_ability(Ability::SWORD_KNOWLEDGE)) {
    get_sprites().set_animation_super_spin_attack();
    std::shared_ptr<CircleMovement> movement =
        std::make_shared<CircleMovement>(false);
    movement->set_center(hero.get_xy());
    movement->set_radius_speed(128);
    movement->set_radius(24);
    movement->set_angle_speed(540);
    movement->set_max_rotations(3);
    movement->set_clockwise(true);
    hero.set_movement(movement);
  }
  else {
    get_sprites().set_animation_spin_attack();
  }
}
예제 #21
0
/**
 * \brief Stops this state.
 * \param next_state the next state
 */
void Hero::JumpingState::stop(const State* next_state) {

  State::stop(next_state);

  get_entity().clear_movement();

  if (carried_item != nullptr) {

    switch (next_state->get_previous_carried_item_behavior()) {

    case CarriedItem::BEHAVIOR_THROW:
      carried_item->throw_item(get_sprites().get_animation_direction());
      get_entities().add_entity(carried_item);
      carried_item = nullptr;
      get_sprites().set_lifted_item(nullptr);
      break;

    case CarriedItem::BEHAVIOR_DESTROY:
      carried_item = nullptr;
      get_sprites().set_lifted_item(nullptr);
      break;

    case CarriedItem::BEHAVIOR_KEEP:
      // The next state is now the owner and has incremented the refcount.
      carried_item = nullptr;
      break;

    default:
      Debug::die("Invalid carried item behavior");
    }
  }
}
예제 #22
0
/**
 * \brief Updates this state.
 */
void Hero::PlungingState::update() {

    HeroState::update();

    if (get_sprites().is_animation_finished()) {

        Hero& hero = get_entity();
        int drown = 0;
        if (hero.get_ground_below() == Ground::DEEP_WATER) {

            if (get_equipment().has_ability(Ability::SWIM)) {
                hero.set_state(new SwimmingState(hero));
            }
            else {
                drown = 1;
            }
        }
        else if (hero.get_ground_below() == Ground::LAVA) {
            drown = 4;
        }
        else {
            hero.set_state(new FreeState(hero));
        }

        if (drown > 0) {
            get_equipment().remove_life(drown);
            hero.set_state(new BackToSolidGroundState(hero, true, 300));
        }
    }
}
예제 #23
0
/**
 * \brief Tests whether the hero is cutting with his sword the specified detector
 * for which a collision was detected.
 * \param detector the detector to check
 * \return true if the sword is cutting this detector
 */
bool Hero::RunningState::is_cutting_with_sword(Detector& detector) {

  // check the distance to the detector
  const int distance = 8;
  Point tested_point = get_entity().get_facing_point();

  switch (get_sprites().get_animation_direction()) {

    case 0: // right
      tested_point.x += distance;
      break;

    case 1: // up
      tested_point.y -= distance;
      break;

    case 2: // left
      tested_point.x -= distance;
      break;

    case 3: // down
      tested_point.y += distance;
      break;
  }

  return detector.overlaps(tested_point);
}
예제 #24
0
/**
 * \brief Returns whether a teletransporter is considered as an obstacle in this state.
 * \param teletransporter a teletransporter
 * \return true if the teletransporter is an obstacle in this state
 */
bool Hero::SpinAttackState::is_teletransporter_obstacle(
    const Teletransporter& /* teletransporter */) const {

  // if the hero is pushed by an enemy or making a super spin attack,
  // don't go on a teletransporter
  return get_entity().get_movement() != nullptr;
}
예제 #25
0
/**
 * \brief Updates the position.
 */
void PathFindingMovement::update() {

  PathMovement::update();

  if (target != nullptr && target->is_being_removed()) {
    target = nullptr;
  }

  if (is_suspended()) {
    return;
  }

  if (PathMovement::is_finished()) {

    // there was a collision or the path was made
    if (target != nullptr
        && System::now() >= next_recomputation_date
        && get_entity()->is_aligned_to_grid()) {
      recompute_movement();
    }
    else {
      set_path(create_random_path());
    }
  }
}
예제 #26
0
/**
 * \copydoc Entity::State::notify_attacked_enemy
 */
void Hero::SpinAttackState::notify_attacked_enemy(
    EnemyAttack attack,
    Enemy& victim,
    const Sprite* victim_sprite,
    EnemyReaction::Reaction& result,
    bool /* killed */) {

  Hero& hero = get_entity();
  if (result.type != EnemyReaction::ReactionType::IGNORED && attack == EnemyAttack::SWORD) {

    if (victim.get_push_hero_on_sword()) {

      if (hero.get_movement() != nullptr) {
        // interrupting a super spin attack: finish with a normal one
        hero.clear_movement();
        get_sprites().set_animation_spin_attack();
      }

      being_pushed = true;
      double angle = victim.get_angle(hero, victim_sprite, nullptr);
      std::shared_ptr<StraightMovement> movement =
          std::make_shared<StraightMovement>(false, true);
      movement->set_max_distance(24);
      movement->set_speed(120);
      movement->set_angle(angle);
      hero.set_movement(movement);
    }
  }
}
예제 #27
0
/**
 * @brief Computes the position of the object controlled by this movement.
 *
 * This function should be called whenever the angle, the radius or the center changes.
 */
void CircleMovement::recompute_position() {

  Rectangle center = this->center_point;
  if (center_entity != NULL) {
    center.add_xy(center_entity->get_xy());
  }

  const Rectangle &xy = Geometry::get_xy(center, Geometry::degrees_to_radians(current_angle), current_radius);
  if (get_entity() == NULL
      || !test_collision_with_obstacles(xy.get_x() - get_entity()->get_x(), xy.get_y() - get_entity()->get_y())) {
    set_xy(xy);
    notify_position_changed();
  }
  else {
    notify_obstacle_reached();
  }
}
예제 #28
0
/**
 * \brief Notifies this state that a directional key was just pressed.
 * \param direction4 direction of the key (0 to 3)
 */
void Hero::RunningState::notify_direction_command_pressed(int direction4) {

  if (!is_bouncing()
      && direction4 != get_sprites().get_animation_direction()) {
    Hero& hero = get_entity();
    hero.set_state(new FreeState(hero));
  }
}
예제 #29
0
/**
 * \brief Stops this state.
 */
void Hero::RunningState::stop(const State* next_state) {

  State::stop(next_state);

  if (phase != 0) {
    get_entity().clear_movement();
  }
}
예제 #30
0
/**
 * \brief Starts this state.
 * \param previous_state the previous state
 */
void Hero::HookshotState::start(const State* previous_state) {

  State::start(previous_state);

  get_sprites().set_animation("hookshot");
  hookshot = std::make_shared<Hookshot>(get_entity());
  get_entities().add_entity(hookshot);
}