X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fbadguy%2Fzeekling.cpp;h=0ca8a561cf8e26ab0681e371c88752562f6d2e6c;hb=b91dbe6bc1d5047a127cdc688dda836c59e8c2d1;hp=e264078f672aa38c2c62bece3291f4d9550db84f;hpb=b51a3e05e9212c00c3bf7d00c6c2bf33fe8e2970;p=supertux.git diff --git a/src/badguy/zeekling.cpp b/src/badguy/zeekling.cpp index e264078f6..0ca8a561c 100644 --- a/src/badguy/zeekling.cpp +++ b/src/badguy/zeekling.cpp @@ -1,13 +1,11 @@ -// $Id$ -// // Zeekling - flyer that swoops down when she spots the player // Copyright (C) 2005 Matthias Braun -// Copyright (C) 2006 Christoph Sommer +// Copyright (C) 2006 Christoph Sommer // -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -15,184 +13,226 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -// 02111-1307, USA. +// along with this program. If not, see . -#include -#include +#include "badguy/zeekling.hpp" -#include "zeekling.hpp" -#include "random_generator.hpp" +#include -Zeekling::Zeekling(const lisp::Lisp& reader) +#include "math/random_generator.hpp" +#include "object/player.hpp" +#include "sprite/sprite.hpp" +#include "supertux/object_factory.hpp" + +Zeekling::Zeekling(const Reader& reader) : + BadGuy(reader, "images/creatures/zeekling/zeekling.sprite"), + speed(), + diveRecoverTimer(), + state(), + last_player(0), + last_player_pos(), + last_self_pos() { - reader.get("x", start_position.x); - reader.get("y", start_position.y); - sprite = sprite_manager->create("images/creatures/zeekling/zeekling.sprite"); - bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height()); - set_direction = false; state = FLYING; + speed = gameRandom.rand(130, 171); + physic.enable_gravity(false); } -Zeekling::Zeekling(float pos_x, float pos_y, Direction d) +Zeekling::Zeekling(const Vector& pos, Direction d) : + BadGuy(pos, d, "images/creatures/zeekling/zeekling.sprite"), + speed(), + diveRecoverTimer(), + state(), + last_player(0), + last_player_pos(), + last_self_pos() { - start_position.x = pos_x; - start_position.y = pos_y; - sprite = sprite_manager->create("images/creatures/zeekling/zeekling.sprite"); - bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height()); - set_direction = true; - initial_direction = d; state = FLYING; + speed = gameRandom.rand(130, 171); + physic.enable_gravity(false); } void -Zeekling::write(lisp::Writer& writer) -{ - writer.start_list("zeekling"); - - writer.write_float("x", start_position.x); - writer.write_float("y", start_position.y); - - writer.end_list("zeekling"); -} - -void -Zeekling::activate() +Zeekling::initialize() { - speed = systemRandom.rand(130, 171); - if (set_direction) {dir = initial_direction;} physic.set_velocity_x(dir == LEFT ? -speed : speed); - physic.enable_gravity(false); sprite->set_action(dir == LEFT ? "left" : "right"); } bool -Zeekling::collision_squished(Player& player) +Zeekling::collision_squished(GameObject& object) { sprite->set_action(dir == LEFT ? "squished-left" : "squished-right"); - kill_squished(player); - kill_fall(); + kill_squished(object); return true; } -void +void Zeekling::onBumpHorizontal() { + if (frozen) + { + physic.set_velocity_x(0); + return; + } if (state == FLYING) { dir = (dir == LEFT ? RIGHT : LEFT); sprite->set_action(dir == LEFT ? "left" : "right"); physic.set_velocity_x(dir == LEFT ? -speed : speed); } else - if (state == DIVING) { - dir = (dir == LEFT ? RIGHT : LEFT); - state = FLYING; - sprite->set_action(dir == LEFT ? "left" : "right"); - physic.set_velocity_x(dir == LEFT ? -speed : speed); - physic.set_velocity_y(0); - } else - if (state == CLIMBING) { - dir = (dir == LEFT ? RIGHT : LEFT); - sprite->set_action(dir == LEFT ? "left" : "right"); - physic.set_velocity_x(dir == LEFT ? -speed : speed); - } + if (state == DIVING) { + dir = (dir == LEFT ? RIGHT : LEFT); + state = FLYING; + sprite->set_action(dir == LEFT ? "left" : "right"); + physic.set_velocity_x(dir == LEFT ? -speed : speed); + physic.set_velocity_y(0); + } else + if (state == CLIMBING) { + dir = (dir == LEFT ? RIGHT : LEFT); + sprite->set_action(dir == LEFT ? "left" : "right"); + physic.set_velocity_x(dir == LEFT ? -speed : speed); + } else { + assert(false); + } } -void +void Zeekling::onBumpVertical() { + if (frozen) + { + physic.set_velocity_y(0); + physic.set_velocity_x(0); + return; + } if (state == FLYING) { physic.set_velocity_y(0); } else - if (state == DIVING) { - state = CLIMBING; - physic.set_velocity_y(speed); - sprite->set_action(dir == LEFT ? "left" : "right"); - } else - if (state == CLIMBING) { - state = FLYING; - physic.set_velocity_y(0); - } + if (state == DIVING) { + state = CLIMBING; + physic.set_velocity_y(-speed); + sprite->set_action(dir == LEFT ? "left" : "right"); + } else + if (state == CLIMBING) { + state = FLYING; + physic.set_velocity_y(0); + } } -HitResponse -Zeekling::collision_solid(GameObject& , const CollisionHit& hit) +void +Zeekling::collision_solid(const CollisionHit& hit) { - if(fabsf(hit.normal.y) > .5) { - onBumpVertical(); - } else { - onBumpHorizontal(); + if(sprite->get_action() == "squished-left" || + sprite->get_action() == "squished-right") + { + return; } - return CONTINUE; + if(hit.top || hit.bottom) { + onBumpVertical(); + } else if(hit.left || hit.right) { + onBumpHorizontal(); + } } /** * linear prediction of player and badguy positions to decide if we should enter the DIVING state */ -bool +bool Zeekling::should_we_dive() { + if (frozen) + return false; + const MovingObject* player = this->get_nearest_player(); - if (!player) return false; + if (player && last_player && (player == last_player)) { - const MovingObject* badguy = this; + // get positions, calculate movement + const Vector player_pos = player->get_pos(); + const Vector player_mov = (player_pos - last_player_pos); + const Vector self_pos = this->get_pos(); + const Vector self_mov = (self_pos - last_self_pos); - const Vector playerPos = player->get_pos(); - const Vector playerMov = player->get_movement(); + // new vertical speed to test with + float vy = 2*fabsf(self_mov.x); - const Vector badguyPos = badguy->get_pos(); - const Vector badguyMov = badguy->get_movement(); + // do not dive if we are not above the player + float height = player_pos.y - self_pos.y; + if (height <= 0) return false; - // new vertical speed to test with - float vy = -2*fabsf(badguyMov.x); + // do not dive if we are too far above the player + if (height > 512) return false; - // do not dive if we are not above the player - float height = playerPos.y - badguyPos.y; - if (height <= 0) return false; + // do not dive if we would not descend faster than the player + float relSpeed = vy - player_mov.y; + if (relSpeed <= 0) return false; - // do not dive if we would not descend faster than the player - float relSpeed = -vy + playerMov.y; - if (relSpeed <= 0) return false; + // guess number of frames to descend to same height as player + float estFrames = height / relSpeed; - // guess number of frames to descend to same height as player - float estFrames = height / relSpeed; - - // guess where the player would be at this time - float estPx = (playerPos.x + (estFrames * playerMov.x)); + // guess where the player would be at this time + float estPx = (player_pos.x + (estFrames * player_mov.x)); - // guess where we would be at this time - float estBx = (badguyPos.x + (estFrames * badguyMov.x)); + // guess where we would be at this time + float estBx = (self_pos.x + (estFrames * self_mov.x)); - // near misses are OK, too - if (fabsf(estPx - estBx) < 32) return true; + // near misses are OK, too + if (fabsf(estPx - estBx) < 8) return true; + } + + // update last player tracked, as well as our positions + last_player = player; + if (player) { + last_player_pos = player->get_pos(); + last_self_pos = this->get_pos(); + } return false; } -void +void Zeekling::active_update(float elapsed_time) { - BadGuy::active_update(elapsed_time); - if (state == FLYING) { if (should_we_dive()) { state = DIVING; - physic.set_velocity_y(-2*fabsf(physic.get_velocity_x())); + physic.set_velocity_y(2*fabsf(physic.get_velocity_x())); sprite->set_action(dir == LEFT ? "diving-left" : "diving-right"); } + BadGuy::active_update(elapsed_time); return; - } - - if (state == DIVING) { + } else if (state == DIVING) { + BadGuy::active_update(elapsed_time); return; - } - - if (state == CLIMBING) { + } else if (state == CLIMBING) { // stop climbing when we're back at initial height if (get_pos().y <= start_position.y) { state = FLYING; physic.set_velocity_y(0); } + BadGuy::active_update(elapsed_time); return; + } else { + assert(false); } +} + +void +Zeekling::freeze() +{ + BadGuy::freeze(); + physic.enable_gravity(true); +} + +void +Zeekling::unfreeze() +{ + BadGuy::unfreeze(); + physic.enable_gravity(false); + state = FLYING; + initialize(); +} +bool +Zeekling::is_freezable() const +{ + return true; } -IMPLEMENT_FACTORY(Zeekling, "zeekling") +/* EOF */