From b8c83bae1b0cd0367b6e3ac8c4c28e077eb1b594 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Mon, 24 May 2004 21:02:44 +0000 Subject: [PATCH] -renamed ViewPort to Camera -removed type() function from GameObject, you should better use C++ RTTI: * casting: BadGuy* badguy = dynamic_cast (object); * comparing for specific type if(typeid(object) == typeid(BadGuy)) * getting the name typeid(object).name() -moved camera handling into Camera class -tweaked camera behaviour. Look for details in http://netpanzer.berlios.de/supertux/index.php/Camera Horizontal scrolling seems to be nicely now, vertical scrolling is still a bit too hectically... SVN-Revision: 1309 --- src/Makefile.am | 4 +- src/background.cpp | 4 +- src/background.h | 5 +- src/badguy.cpp | 16 ++--- src/badguy.h | 4 +- src/button.cpp | 4 +- src/camera.cpp | 154 +++++++++++++++++++++++++++++++++++++++++++ src/{viewport.h => camera.h} | 49 ++++++++++++-- src/display_manager.cpp | 4 +- src/display_manager.h | 8 +-- src/drawable.h | 4 +- src/game_object.h | 5 -- src/gameloop.cpp | 4 +- src/gameobjs.cpp | 16 +++-- src/gameobjs.h | 26 ++------ src/leveleditor.cpp | 34 +++++----- src/particlesystem.cpp | 4 +- src/particlesystem.h | 2 +- src/player.cpp | 21 ++++-- src/player.h | 10 +-- src/special.cpp | 12 ++-- src/special.h | 9 +-- src/tilemap.cpp | 2 +- src/tilemap.h | 4 +- src/viewport.cpp | 34 ---------- src/world.cpp | 105 ++++++++++++++++++----------- src/world.h | 2 +- 27 files changed, 355 insertions(+), 191 deletions(-) create mode 100644 src/camera.cpp rename src/{viewport.h => camera.h} (52%) delete mode 100644 src/viewport.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 275b8101a..23427d01b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,8 +77,8 @@ music_manager.cpp \ music_manager.h \ musicref.cpp \ musicref.h \ -viewport.cpp \ -viewport.h \ +camera.cpp \ +camera.h \ game_object.cpp \ game_object.h \ display_manager.h \ diff --git a/src/background.cpp b/src/background.cpp index 5ebb6c546..975bff959 100644 --- a/src/background.cpp +++ b/src/background.cpp @@ -19,7 +19,7 @@ #include "background.h" #include "globals.h" -#include "viewport.h" +#include "camera.h" #include "display_manager.h" Background::Background(DisplayManager& displaymanager) @@ -53,7 +53,7 @@ Background::set_gradient(Color top, Color bottom) } void -Background::draw(ViewPort& viewport, int ) +Background::draw(Camera& viewport, int ) { if(bgtype == BACKGROUND_GRADIENT) { drawgradient(gradient_top, gradient_bottom); diff --git a/src/background.h b/src/background.h index e15439263..45af0e09e 100644 --- a/src/background.h +++ b/src/background.h @@ -40,12 +40,9 @@ public: void set_gradient(Color top, Color bottom); - virtual std::string type() const - { return "Background"; } - virtual void action(float elapsed_time); - virtual void draw(ViewPort& viewport, int layer); + virtual void draw(Camera& viewport, int layer); private: int bgtype; diff --git a/src/badguy.cpp b/src/badguy.cpp index 0bd133741..0e4b7de68 100644 --- a/src/badguy.cpp +++ b/src/badguy.cpp @@ -35,7 +35,7 @@ #include "gameloop.h" #include "display_manager.h" #include "lispwriter.h" -#include "viewport.h" +#include "camera.h" Sprite* img_mriceblock_flat_left; Sprite* img_mriceblock_flat_right; @@ -316,8 +316,7 @@ BadGuy::action_mriceblock(double elapsed_time) check_horizontal_bump(); if(mode == KICK && changed != dir) { - float scroll_x = World::current()->displaymanager - .get_viewport().get_translation().x; + float scroll_x = World::current()->camera->get_translation().x; /* handle stereo sound (number 10 should be tweaked...)*/ if (base.x < scroll_x + screen->w/2 - 10) @@ -518,8 +517,7 @@ BadGuy::action_bomb(double elapsed_time) dying = DYING_NOT; // now the bomb hurts timer.start(EXPLODETIME); - float scroll_x = World::current()->displaymanager - .get_viewport().get_translation().x; + float scroll_x = World::current()->camera->get_translation().x; /* play explosion sound */ // FIXME: is the stereo all right? maybe we should use player cordinates... if (base.x < scroll_x + screen->w/2 - 10) @@ -753,10 +751,8 @@ BadGuy::action_snowball(double elapsed_time) void BadGuy::action(float elapsed_time) { - float scroll_x = World::current()->displaymanager - .get_viewport().get_translation().x; - float scroll_y = World::current()->displaymanager - .get_viewport().get_translation().y; + float scroll_x = World::current()->camera->get_translation().x; + float scroll_y = World::current()->camera->get_translation().y; // BadGuy fall below the ground if (base.y > World::current()->get_level()->height * 32) { @@ -836,7 +832,7 @@ BadGuy::action(float elapsed_time) } void -BadGuy::draw(ViewPort& viewport, int) +BadGuy::draw(Camera& viewport, int) { float scroll_x = viewport.get_translation().x; float scroll_y = viewport.get_translation().y; diff --git a/src/badguy.h b/src/badguy.h index 6ffafda11..9c504e821 100644 --- a/src/badguy.h +++ b/src/badguy.h @@ -118,10 +118,8 @@ public: virtual void write(LispWriter& writer); virtual void action(float frame_ratio); - virtual void draw(ViewPort& viewport, int layer); + virtual void draw(Camera& viewport, int layer); virtual void collision(const MovingObject& other, int type); - virtual std::string type() const - { return "BadGuy"; }; void collision(void* p_c_object, int c_object, CollisionType type = COLLISION_NORMAL); diff --git a/src/button.cpp b/src/button.cpp index 6467474db..27697c902 100644 --- a/src/button.cpp +++ b/src/button.cpp @@ -24,7 +24,7 @@ #include "screen.h" #include "globals.h" #include "button.h" -#include "viewport.h" +#include "camera.h" Timer Button::popup_timer; @@ -87,7 +87,7 @@ void Button::draw() if(drawable) { - ViewPort viewport; + Camera viewport; viewport.set_translation(Vector(rect.x, rect.y)); drawable->draw(viewport, 0); } diff --git a/src/camera.cpp b/src/camera.cpp new file mode 100644 index 000000000..d3c66037b --- /dev/null +++ b/src/camera.cpp @@ -0,0 +1,154 @@ +// $Id$ +// +// SuperTux - A Jump'n Run +// Copyright (C) 2004 Matthias Braun +#include "lispwriter.h" +#include "player.h" +#include "level.h" +#include "globals.h" + +Camera::Camera(Player* newplayer, Level* newlevel) + : player(newplayer), level(newlevel), scrollchange(NONE) +{ + if(!player || !level) + mode = MANUAL; + else + mode = NORMAL; +} + +Camera::~Camera() +{ +} + +void +Camera::set_translation(const Vector& newtranslation) +{ + translation = newtranslation; +} + +void +Camera::write(LispWriter& writer) +{ + writer.start_list("camera"); + + if(mode == NORMAL) { + writer.write_string("mode", "normal"); + } else if(mode == AUTOSCROLL) { + writer.write_string("mode", "autoscroll"); + } else if(mode == MANUAL) { + writer.write_string("mode", "manual"); + } + + writer.end_list("camera"); +} + +static const float EPSILON = .00001; +static const float max_speed_y = 1.4; + +void +Camera::action(float elapsed_time) +{ + if(mode == NORMAL) + scroll_normal(elapsed_time); + else if(mode == AUTOSCROLL) + scroll_autoscroll(elapsed_time); +} + +void +Camera::scroll_normal(float elapsed_time) +{ + assert(level != 0 && player != 0); + + // check that we don't have division by zero later + if(elapsed_time < EPSILON) + return; + + bool do_y_scrolling = true; + + if(player->dying) + do_y_scrolling = false; + + if(do_y_scrolling) { + float target_y; + if(player->fall_mode == Player::JUMPING) + target_y = player->last_ground_y + player->base.height; + else + target_y = player->base.y + player->base.height; + + float delta_y = translation.y - (target_y - screen->h/2); + float speed_y = delta_y / elapsed_time; + + if(player->fall_mode != Player::FALLING + && player->fall_mode != Player::TRAMPOLINE_JUMP) { + if(speed_y > max_speed_y) + speed_y = max_speed_y; + else if(speed_y < -max_speed_y) + speed_y = -max_speed_y; + } + + translation.y -= speed_y * elapsed_time; + + // don't scroll before the start or after the level's end + if(translation.y > level->height * 32 - screen->h) + translation.y = level->height * 32 - screen->h; + if(translation.y < 0) + translation.y = 0; + } + + if((player->dir == ::LEFT && scrollchange == RIGHT) + || (player->dir == ::RIGHT && scrollchange == LEFT)) + scrollchange = NONE; + if(player->base.x < translation.x + screen->w/3) + scrollchange = LEFT; + else if(player->base.x > translation.x + screen->w/3*2) + scrollchange = RIGHT; + + float target_x; + if(scrollchange == LEFT) + target_x = player->base.x - screen->w/3*2; + else if(scrollchange == RIGHT) + target_x = player->base.x - screen->w/3; + else + target_x = translation.x; + + float delta_x = translation.x - target_x; + float speed_x = delta_x / elapsed_time; + + float maxv = 1 + fabsf(player->physic.get_velocity_x() * 2); + printf("SX: %f MV: %f.\n", player->physic.get_velocity_x(), maxv); + if(speed_x > maxv) + speed_x = maxv; + else if(speed_x < -maxv) + speed_x = -maxv; + + translation.x -= speed_x * elapsed_time; + + // don't scroll before the start or after the level's end + if(translation.x > level->width * 32 - screen->w) + translation.x = level->width * 32 - screen->w; + if(translation.x < 0) + translation.x = 0; +} + +void +Camera::scroll_autoscroll(float elapsed_time) +{ + // TODO +} diff --git a/src/viewport.h b/src/camera.h similarity index 52% rename from src/viewport.h rename to src/camera.h index b7a12ac01..aaa8e1959 100644 --- a/src/viewport.h +++ b/src/camera.h @@ -20,26 +20,61 @@ #define __VIEWPORT_H__ #include "vector.h" +#include "game_object.h" +#include "serializable.h" -class ViewPort +class LispReader; +class Player; +class Level; + +class Camera : public GameObject, public Serializable { public: - ViewPort(); - ~ViewPort(); + Camera(Player* player = 0, Level* level = 0); + virtual ~Camera(); + /** transforms a coordinate in world space to screen space. + * Basically you have to apply this function to each coordinate that you want + * to display on screen. + */ Vector world2screen(const Vector& worldpos) const { - return worldpos - translation; - } - + return worldpos - translation; + } + + /// parse camera mode from lisp file + void parse_camera(LispReader& reader); + /// write camera mode to a lisp file + virtual void write(LispWriter& writer); + /** returns the current translation (=scroll) vector of the viewport */ const Vector& get_translation() const { return translation; } - + /** set the curren translation vector of the viewport */ void set_translation(const Vector& translation); + virtual void action(float elapsed_time); + + enum CameraMode + { + NORMAL, AUTOSCROLL, MANUAL + }; + private: + void scroll_normal(float elapsed_time); + void scroll_autoscroll(float elapsed_time); + + enum LeftRightScrollChange + { + NONE, LEFT, RIGHT + }; + Vector translation; + + Player* player; + Level* level; + CameraMode mode; + LeftRightScrollChange scrollchange; }; #endif diff --git a/src/display_manager.cpp b/src/display_manager.cpp index 3aa27ec3d..3a9b660d9 100644 --- a/src/display_manager.cpp +++ b/src/display_manager.cpp @@ -51,10 +51,10 @@ DisplayManager::remove_drawable(Drawable* drawable) } void -DisplayManager::draw() +DisplayManager::draw(Camera& camera) { for(DisplayList::iterator i = displaylist.begin(); i != displaylist.end(); ++i) - i->object->draw(viewport, i->layer); + i->object->draw(camera, i->layer); } diff --git a/src/display_manager.h b/src/display_manager.h index d86fd5ee9..29cc10b1b 100644 --- a/src/display_manager.h +++ b/src/display_manager.h @@ -22,7 +22,7 @@ #include #include "drawable.h" -#include "viewport.h" +#include "camera.h" // some constants for predefined layer values enum { @@ -51,10 +51,7 @@ public: void remove_drawable(Drawable* object); - void draw(); - - ViewPort& get_viewport() - { return viewport; } + void draw(Camera& camera); private: class DrawingQueueEntry { @@ -74,7 +71,6 @@ private: typedef std::vector DisplayList; DisplayList displaylist; - ViewPort viewport; }; #endif diff --git a/src/drawable.h b/src/drawable.h index 7c4eef0ac..d96f20047 100644 --- a/src/drawable.h +++ b/src/drawable.h @@ -19,7 +19,7 @@ #ifndef __DRAWABLE_H__ #define __DRAWABLE_H__ -class ViewPort; +class Camera; /** interface for all game objects that can be drawn on screen. */ @@ -28,7 +28,7 @@ class Drawable public: /** This function draws the object on screen. */ - virtual void draw(ViewPort& viewport, int layer) = 0; + virtual void draw(Camera& viewport, int layer) = 0; }; #endif diff --git a/src/game_object.h b/src/game_object.h index 644baaaf8..d2824b59d 100644 --- a/src/game_object.h +++ b/src/game_object.h @@ -41,11 +41,6 @@ public: GameObject(); virtual ~GameObject(); - /** returns the name of the objecttype, this is mainly usefull for the editor. - * For the coding part you should use C++ RTTI (ie. typeid and dynamic_cast) - * instead. - */ - virtual std::string type() const = 0; /** This function is called once per frame and allows the object to update * it's state. The elapsed_time is the time since the last frame and should be * the base for all timed things. diff --git a/src/gameloop.cpp b/src/gameloop.cpp index 766223d7f..d42c20522 100644 --- a/src/gameloop.cpp +++ b/src/gameloop.cpp @@ -147,7 +147,7 @@ GameSession::levelintro(void) char str[60]; - ViewPort dummy; + Camera dummy; world->background->draw(dummy, LAYER_BACKGROUND0); sprintf(str, "%s", world->get_level()->name.c_str()); @@ -719,7 +719,7 @@ GameSession::drawresultscreen(void) { char str[80]; - ViewPort dummy; + Camera dummy; world->background->draw(dummy, LAYER_BACKGROUND0); blue_text->drawf("Result:", 0, 200, A_HMIDDLE, A_TOP, 1); diff --git a/src/gameobjs.cpp b/src/gameobjs.cpp index 6a707ef44..743d9cb9b 100644 --- a/src/gameobjs.cpp +++ b/src/gameobjs.cpp @@ -47,7 +47,7 @@ BouncyDistro::action(float elapsed_time) } void -BouncyDistro::draw(ViewPort& viewport, int ) +BouncyDistro::draw(Camera& viewport, int ) { img_distro[0]->draw(viewport.world2screen(position)); } @@ -71,7 +71,7 @@ BrokenBrick::action(float elapsed_time) } void -BrokenBrick::draw(ViewPort& viewport, int ) +BrokenBrick::draw(Camera& viewport, int ) { SDL_Rect src, dest; src.x = rand() % 16; @@ -110,7 +110,7 @@ BouncyBrick::action(float elapsed_time) } void -BouncyBrick::draw(ViewPort& viewport, int) +BouncyBrick::draw(Camera& viewport, int) { Tile::draw(viewport.world2screen(position + Vector(0, offset)), shape); } @@ -135,7 +135,7 @@ FloatingScore::action(float elapsed_time) } void -FloatingScore::draw(ViewPort& viewport, int ) +FloatingScore::draw(Camera& viewport, int ) { gold_text->draw(str, viewport.world2screen(position)); } @@ -174,7 +174,7 @@ Trampoline::write(LispWriter& writer) } void -Trampoline::draw(ViewPort& viewport, int ) +Trampoline::draw(Camera& viewport, int ) { img_trampoline[frame]->draw(viewport.world2screen(Vector(base.x, base.y))); frame = 0; @@ -264,8 +264,10 @@ Trampoline::collision(void *p_c_object, int c_object, CollisionType type) else frame = 0; - if (squish_amount < 20) + if (squish_amount < 20) { pplayer_c->physic.set_velocity_y(power); + pplayer_c->fall_mode = Player::TRAMPOLINE_JUMP; + } else if (pplayer_c->physic.get_velocity_y() < 0) pplayer_c->physic.set_velocity_y(-squish_amount/32); } @@ -316,7 +318,7 @@ FlyingPlatform::write(LispWriter& writer) } void -FlyingPlatform::draw(ViewPort& viewport, int ) +FlyingPlatform::draw(Camera& viewport, int ) { img_flying_platform->draw(viewport.world2screen(Vector(base.x, base.y))); } diff --git a/src/gameobjs.h b/src/gameobjs.h index bc0d0e7f1..ff2e31e19 100644 --- a/src/gameobjs.h +++ b/src/gameobjs.h @@ -42,9 +42,7 @@ class BouncyDistro : public GameObject, public Drawable public: BouncyDistro(DisplayManager& displaymanager, const Vector& pos); virtual void action(float elapsed_time); - virtual void draw(ViewPort& viewport, int layer); - virtual std::string type() const - { return "BouncyDistro"; }; + virtual void draw(Camera& viewport, int layer); private: Vector position; @@ -65,10 +63,7 @@ public: const Vector& pos, const Vector& movement); virtual void action(float elapsed_time); - virtual void draw(ViewPort& viewport, int layer); - - virtual std::string type() const - { return "BrokenBrick"; }; + virtual void draw(Camera& viewport, int layer); private: Timer timer; @@ -82,11 +77,8 @@ class BouncyBrick : public GameObject, public Drawable public: BouncyBrick(DisplayManager& displaymanager, const Vector& pos); virtual void action(float elapsed_time); - virtual void draw(ViewPort& viewport, int layer); + virtual void draw(Camera& viewport, int layer); - virtual std::string type() const - { return "BouncyBrick"; }; - private: Vector position; float offset; @@ -100,9 +92,7 @@ public: FloatingScore(DisplayManager& displaymanager, const Vector& pos, int s); virtual void action(float elapsed_time); - virtual void draw(ViewPort& viewport, int layer); - virtual std::string type() const - { return "FloatingScore"; }; + virtual void draw(Camera& viewport, int layer); private: Vector position; @@ -117,9 +107,7 @@ public: virtual void write(LispWriter& writer); virtual void action(float frame_ratio); - virtual void draw(ViewPort& viewport, int layer); - virtual std::string type() const - { return "Trampoline"; }; + virtual void draw(Camera& viewport, int layer); virtual void collision(const MovingObject& other, int); void collision(void *p_c_object, int c_object, CollisionType type); @@ -139,9 +127,7 @@ public: virtual void write(LispWriter& writer); virtual void action(float frame_ratio); - virtual void draw(ViewPort& viewport, int layer); - virtual std::string type() const - { return "Trampoline"; }; + virtual void draw(Camera& viewport, int layer); virtual void collision(const MovingObject& other, int); void collision(void *p_c_object, int c_object, CollisionType type); diff --git a/src/leveleditor.cpp b/src/leveleditor.cpp index 543bbc39f..fdc34336c 100644 --- a/src/leveleditor.cpp +++ b/src/leveleditor.cpp @@ -19,6 +19,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include +#include #include #include #include @@ -942,8 +943,7 @@ void le_drawlevel() Uint8 a; /* Draw the real background */ - le_world->background->draw(le_world->displaymanager.get_viewport(), - LAYER_BACKGROUND0); + le_world->background->draw(*le_world->camera, LAYER_BACKGROUND0); if(le_current.IsTile()) { @@ -1012,7 +1012,7 @@ void le_drawlevel() continue; /* to support frames: img_bsod_left[(frame / 5) % 4] */ - ViewPort viewport; + Camera viewport; viewport.set_translation(Vector(pos_x, pos_y)); badguy->draw(viewport, 0); } @@ -1028,7 +1028,8 @@ void le_change_object_properties(GameObject *pobj) Menu* object_properties_menu = new Menu(); bool loop = true; - object_properties_menu->additem(MN_LABEL,pobj->type() + " Properties",0,0); + std::string type = typeid(pobj).name(); + object_properties_menu->additem(MN_LABEL, type + " Properties",0,0); object_properties_menu->additem(MN_HL,"",0,0); BadGuy* pbad = dynamic_cast(pobj); @@ -1510,15 +1511,17 @@ void le_checkevents() if(le_current.IsObject()) { le_level_changed = true; - std::string type = le_current.obj->type(); + BadGuy* pbadguy = dynamic_cast(le_current.obj); - if(type == "BadGuy") + if(pbadguy) { - ViewPort viewport(le_world->displaymanager.get_viewport()); + Camera& camera = *le_world->camera; DisplayManager dummy; - BadGuy* pbadguy = dynamic_cast(le_current.obj); - le_world->bad_guys.push_back(new BadGuy(dummy, pbadguy->kind, cursor_x + viewport.get_translation().x, cursor_y + viewport.get_translation().y)); + le_world->bad_guys.push_back( + new BadGuy(dummy, pbadguy->kind, + cursor_x + camera.get_translation().x, + cursor_y + camera.get_translation().y)); le_world->gameobjects.push_back(le_world->bad_guys.back()); } } @@ -1678,11 +1681,11 @@ void le_change(float x, float y, int tm, unsigned int c) /* if there is a bad guy over there, remove it */ // XXX TODO for(std::vector::iterator it = le_world->gameobjects.begin(); - it != le_world->gameobjects.end(); ++it) - if ((*it)->type() == "BadGuy") + it != le_world->gameobjects.end(); ++it) { + BadGuy* badguy = dynamic_cast((*it)); + if (badguy) { - BadGuy* pbadguy = dynamic_cast((*it)); - if(rectcollision(cursor_base, pbadguy->base)) + if(rectcollision(cursor_base, badguy->base)) { delete (*it); //le_world->bad_guys.erase(it); @@ -1690,6 +1693,7 @@ void le_change(float x, float y, int tm, unsigned int c) break; } } + } break; case SQUARE: @@ -1724,9 +1728,9 @@ void le_change(float x, float y, int tm, unsigned int c) for(std::vector::iterator it = le_world->gameobjects.begin(); it != le_world->gameobjects.end(); ++it /* will be at end of loop */) { - if ((*it)->type() == "BadGuy") + MovingObject* pmobject = dynamic_cast (*it); + if (pmobject) { - MovingObject* pmobject = dynamic_cast (*it); if(pmobject->base.x/32 >= x1 && pmobject->base.x/32 <= x2 && pmobject->base.y/32 >= y1 && pmobject->base.y/32 <= y2) { diff --git a/src/particlesystem.cpp b/src/particlesystem.cpp index 83705363e..7604d32df 100644 --- a/src/particlesystem.cpp +++ b/src/particlesystem.cpp @@ -25,7 +25,7 @@ #include "world.h" #include "level.h" #include "scene.h" -#include "viewport.h" +#include "camera.h" #include "display_manager.h" ParticleSystem::ParticleSystem(DisplayManager& displaymanager) @@ -44,7 +44,7 @@ ParticleSystem::~ParticleSystem() } } -void ParticleSystem::draw(ViewPort& viewport, int layer) +void ParticleSystem::draw(Camera& viewport, int layer) { std::vector::iterator i; for(i = particles.begin(); i != particles.end(); ++i) { diff --git a/src/particlesystem.h b/src/particlesystem.h index 4f21a5c62..8bd117afe 100644 --- a/src/particlesystem.h +++ b/src/particlesystem.h @@ -48,7 +48,7 @@ public: ParticleSystem(DisplayManager& displaymanager); virtual ~ParticleSystem(); - virtual void draw(ViewPort& view, int layer); + virtual void draw(Camera& view, int layer); protected: class Particle diff --git a/src/player.cpp b/src/player.cpp index e8b4c2c87..7cae89be1 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -101,6 +101,8 @@ Player::init() duck = false; dying = DYING_NOT; + last_ground_y = 0; + fall_mode = ON_GROUND; jumping = false; can_jump = true; butt_jump = false; @@ -415,6 +417,17 @@ Player::handle_horizontal_input() void Player::handle_vertical_input() { + // set fall mode... + if(on_ground()) { + fall_mode = ON_GROUND; + last_ground_y = base.y; + } else { + if(base.y > last_ground_y) + fall_mode = FALLING; + else if(fall_mode == ON_GROUND) + fall_mode = JUMPING; + } + // Press jump key if(input.up == DOWN && can_jump && on_ground()) { @@ -596,7 +609,7 @@ Player::grabdistros() } void -Player::draw(ViewPort& viewport, int layer) +Player::draw(Camera& viewport, int layer) { PlayerSprite* sprite; @@ -857,9 +870,9 @@ Player::is_dying() bool Player::is_dead() { float scroll_x = - World::current()->displaymanager.get_viewport().get_translation().x; + World::current()->camera->get_translation().x; float scroll_y = - World::current()->displaymanager.get_viewport().get_translation().y; + World::current()->camera->get_translation().y; if(base.y > screen->h + scroll_y || base.y > World::current()->get_level()->height*32 || base.x < scroll_x - AUTOSCROLL_DEAD_INTERVAL) // can happen in auto-scrolling return true; @@ -877,7 +890,7 @@ Player::remove_powerups() } void -Player::check_bounds(ViewPort& viewport, +Player::check_bounds(Camera& viewport, bool back_scrolling, bool hor_autoscroll) { /* Keep tux in bounds: */ diff --git a/src/player.h b/src/player.h index 95b1a56b8..04473f2a2 100644 --- a/src/player.h +++ b/src/player.h @@ -112,6 +112,7 @@ class Player : public MovingObject, public Drawable public: enum HurtMode { KILL, SHRINK }; enum Power { NONE_POWER, FIRE_POWER, ICE_POWER }; + enum FallMode { ON_GROUND, JUMPING, TRAMPOLINE_JUMP, FALLING }; player_input_type input; int got_power; @@ -123,6 +124,9 @@ public: Direction dir; Direction old_dir; + float last_ground_y; + FallMode fall_mode; + bool jumping; bool can_jump; bool butt_jump; @@ -148,18 +152,16 @@ public: void grabdistros(); virtual void action(float elapsed_time); - virtual void draw(ViewPort& viewport, int layer); + virtual void draw(Camera& viewport, int layer); virtual void collision(const MovingObject& other_object, int collision_type); - virtual std::string type() const - { return "Player"; } void collision(void* p_c_object, int c_object); void kill(HurtMode mode); void is_dying(); bool is_dead(); void player_remove_powerups(); - void check_bounds(ViewPort& viewport, bool back_scrolling, bool hor_autoscroll); + void check_bounds(Camera& viewport, bool back_scrolling, bool hor_autoscroll); bool on_ground(); bool under_solid(); bool tiles_on_air(int tiles); diff --git a/src/special.cpp b/src/special.cpp index b2fffe5f6..6bbbc7c9e 100644 --- a/src/special.cpp +++ b/src/special.cpp @@ -96,9 +96,9 @@ Bullet::action(float elapsed_time) physic.set_velocity_y(-9); float scroll_x = - World::current()->displaymanager.get_viewport().get_translation().x; + World::current()->camera->get_translation().x; float scroll_y = - World::current()->displaymanager.get_viewport().get_translation().y; + World::current()->camera->get_translation().y; if (base.x < scroll_x || base.x > scroll_x + screen->w || base.y < scroll_y || @@ -112,7 +112,7 @@ Bullet::action(float elapsed_time) } void -Bullet::draw(ViewPort& viewport, int ) +Bullet::draw(Camera& viewport, int ) { if(kind == FIRE_BULLET) img_firebullet->draw(viewport.world2screen(Vector(base.x, base.y))); @@ -187,9 +187,9 @@ Upgrade::action(float elapsed_time) /* Away from the screen? Kill it! */ float scroll_x = - World::current()->displaymanager.get_viewport().get_translation().x; + World::current()->camera->get_translation().x; float scroll_y = - World::current()->displaymanager.get_viewport().get_translation().y; + World::current()->camera->get_translation().y; if(base.x < scroll_x - X_OFFSCREEN_DISTANCE || base.x > scroll_x + screen->w + X_OFFSCREEN_DISTANCE || @@ -243,7 +243,7 @@ Upgrade::action(float elapsed_time) } void -Upgrade::draw(ViewPort& viewport, int) +Upgrade::draw(Camera& viewport, int) { SDL_Rect dest; diff --git a/src/special.h b/src/special.h index 5ea0d59c2..304d20907 100644 --- a/src/special.h +++ b/src/special.h @@ -53,14 +53,11 @@ public: virtual ~Upgrade(); virtual void action(float frame_ratio); - virtual void draw(ViewPort& viewport, int layer); + virtual void draw(Camera& viewport, int layer); virtual void collision(const MovingObject& other, int); void collision(void* p_c_object, int c_object, CollisionType type); - virtual std::string type() const - { return "Upgrade"; }; - private: void bump(Player* player); }; @@ -77,12 +74,10 @@ public: int kind); virtual void action(float frame_ratio); - virtual void draw(ViewPort& viewport, int layer); + virtual void draw(Camera& viewport, int layer); void collision(int c_object); virtual void collision(const MovingObject& other_object, int type); - virtual std::string type() const - { return "Bullet"; }; int kind; diff --git a/src/tilemap.cpp b/src/tilemap.cpp index 1af2fb55e..bb6a0badc 100644 --- a/src/tilemap.cpp +++ b/src/tilemap.cpp @@ -42,7 +42,7 @@ TileMap::action(float ) } void -TileMap::draw(ViewPort& viewport, int layer) +TileMap::draw(Camera& viewport, int layer) { std::vector* tiles; switch(layer) { diff --git a/src/tilemap.h b/src/tilemap.h index 334a7e337..a1cc142a1 100644 --- a/src/tilemap.h +++ b/src/tilemap.h @@ -34,9 +34,7 @@ public: virtual ~TileMap(); virtual void action(float elapsed_time); - virtual void draw(ViewPort& viewport, int layer); - virtual std::string type() const - { return "TileMap"; } + virtual void draw(Camera& viewport, int layer); private: Level* level; diff --git a/src/viewport.cpp b/src/viewport.cpp deleted file mode 100644 index 658a9e558..000000000 --- a/src/viewport.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// $Id$ -// -// SuperTux - A Jump'n Run -// Copyright (C) 2004 Matthias Braun load(filename, this); tux = new Player(displaymanager); - gameobjects.push_back(tux); + add_object(tux); set_defaults(); - get_level()->load_gfx(); + level->load_gfx(); // add background activate_particle_systems(); background = new Background(displaymanager); @@ -65,14 +65,17 @@ World::World(const std::string& filename) } else { background->set_gradient(level->bkgd_top, level->bkgd_bottom); } - gameobjects.push_back(background); + add_object(background); // add tilemap - gameobjects.push_back(new TileMap(displaymanager, get_level())); - get_level()->load_song(); + add_object(new TileMap(displaymanager, level)); + level->load_song(); apply_bonuses(); + camera = new Camera(tux, level); + add_object(camera); + scrolling_timer.init(true); } @@ -217,7 +220,7 @@ void World::draw() { /* Draw objects */ - displaymanager.draw(); + displaymanager.draw(*camera); } void @@ -229,9 +232,8 @@ World::action(float elapsed_time) for(size_t i = 0; i < gameobjects.size(); ++i) gameobjects[i]->action(elapsed_time); - tux->check_bounds(displaymanager.get_viewport(), + tux->check_bounds(*camera, level->back_scrolling, (bool)level->hor_autoscroll_speed); - scrolling(elapsed_time); /* Handle all possible collisions. */ collision_handler(); @@ -288,35 +290,59 @@ World::action(float elapsed_time) // should be less than screen->h/2 (300) #define Y_SPACE 250 +static const float max_speed_y = 1.4; + // the time it takes to move the camera (in ms) #define CHANGE_DIR_SCROLL_SPEED 2000 +static const float EPSILON = .0001; + +#if 0 /* This functions takes cares of the scrolling */ void World::scrolling(float elapsed_time) { - float scroll_x = displaymanager.get_viewport().get_translation().x; - float scroll_y = displaymanager.get_viewport().get_translation().y; + if(elapsed_time < EPSILON) + return; + + Vector scroll = displaymanager.get_viewport().get_translation(); + bool do_y_scrolling = true; + + if(tux->dying) + do_y_scrolling = false; /* Y-axis scrolling */ + if(do_y_scrolling) { + float target_y; + // upwards we target the y position of the platforms tux stands on + if(tux->fall_mode != Player::FALLING) + target_y = tux->last_ground_y + tux->base.height; + else + target_y = tux->base.y + tux->base.height; - float tux_pos_y = tux->base.y + (tux->base.height/2); + float delta_y = scroll.y - (target_y - (screen->h/2)); + float speed_y = delta_y / elapsed_time; - if(level->height > VISIBLE_TILES_Y-1 && !tux->dying) - { - if (scroll_y < tux_pos_y - (screen->h - Y_SPACE)) - scroll_y = tux_pos_y - (screen->h - Y_SPACE); - else if (scroll_y > tux_pos_y - Y_SPACE) - scroll_y = tux_pos_y - Y_SPACE; - } + float max = max_speed_y; + if(fabsf(delta_y) > float(screen->h)/5.0) + max *= 5; + + if(speed_y > max) + speed_y = max; + else if(speed_y < -max) + speed_y = -max; - // this code prevent the screen to scroll before the start or after the level's end - if(scroll_y > level->height * 32 - screen->h) - scroll_y = level->height * 32 - screen->h; - if(scroll_y < 0) - scroll_y = 0; + scroll.y -= speed_y * elapsed_time; + + // don't scroll before the start or after the level's end + if(scroll.y > level->height * 32 - screen->h) + scroll.y = level->height * 32 - screen->h; + if(scroll.y < 0) + scroll.y = 0; + } /* X-axis scrolling */ +#if 0 /* Auto scrolling */ if(level->hor_autoscroll_speed) { @@ -324,7 +350,7 @@ void World::scrolling(float elapsed_time) displaymanager.get_viewport().set_translation(Vector(scroll_x, scroll_y)); return; } - +#endif /* Horizontal backscrolling */ float tux_pos_x = tux->base.x + (tux->base.width/2); @@ -371,31 +397,32 @@ void World::scrolling(float elapsed_time) float number = 2.5/(elapsed_time * CHANGE_DIR_SCROLL_SPEED/1000)*exp((CHANGE_DIR_SCROLL_SPEED-scrolling_timer.get_left())/1400.); if(left) number *= -1.; - scroll_x += number + scroll.x += number + constant1 * tux->physic.get_velocity_x() * elapsed_time + constant2 * tux->physic.get_acceleration_x() * elapsed_time * elapsed_time; - if ((right && final_scroll_x - scroll_x < 0) || (left && final_scroll_x - scroll_x > 0)) - scroll_x = final_scroll_x; - + if ((right && final_scroll_x - scroll.x < 0) || (left && final_scroll_x - + scroll.x > 0)) + scroll.x = final_scroll_x; } else { - if (right && scroll_x < tux_pos_x - (screen->w - X_SPACE)) - scroll_x = tux_pos_x - (screen->w - X_SPACE); - else if (left && scroll_x > tux_pos_x - X_SPACE && level->back_scrolling) - scroll_x = tux_pos_x - X_SPACE; + if (right && scroll.x < tux_pos_x - (screen->w - X_SPACE)) + scroll.x = tux_pos_x - (screen->w - X_SPACE); + else if (left && scroll.x > tux_pos_x - X_SPACE && level->back_scrolling) + scroll.x = tux_pos_x - X_SPACE; } - // this code prevent the screen to scroll before the start or after the level's end - if(scroll_x > level->width * 32 - screen->w) - scroll_x = level->width * 32 - screen->w; - if(scroll_x < 0) - scroll_x = 0; + // don't scroll before the start or after the level's end + if(scroll.x > level->width * 32 - screen->w) + scroll.x = level->width * 32 - screen->w; + if(scroll.x < 0) + scroll.x = 0; - displaymanager.get_viewport().set_translation(Vector(scroll_x, scroll_y)); + displaymanager.get_viewport().set_translation(scroll); } +#endif void World::collision_handler() diff --git a/src/world.h b/src/world.h index 80ed8803e..661cb085b 100644 --- a/src/world.h +++ b/src/world.h @@ -64,6 +64,7 @@ public: std::vector bullets; std::vector gameobjects; + Camera* camera; DisplayManager displaymanager; public: @@ -84,7 +85,6 @@ public: void draw(); void action(float elapsed_time); - void scrolling(float elapsed_time); // camera scrolling void play_music(int musictype); int get_music_type(); -- 2.11.0