From: Matthias Braun Date: Fri, 31 Mar 2006 01:18:10 +0000 (+0000) Subject: - Yet another try in the endless quest for perfect collision detection. X-Git-Url: https://git.octo.it/?a=commitdiff_plain;h=02288dc76442bd6616a200a2d22c0954d2fc8180;p=supertux.git - Yet another try in the endless quest for perfect collision detection. This version seems to be working quiet good. Only bug I could find was when jumping on skull tiles that are jumping themselfes at the same moment... - Change paths to be no game objects anymore - slightly changed path syntax SVN-Revision: 3139 --- diff --git a/data/images/objects/platforms/big.png b/data/images/objects/platforms/big.png new file mode 100644 index 000000000..c53d32bb2 Binary files /dev/null and b/data/images/objects/platforms/big.png differ diff --git a/data/images/objects/platforms/big.sprite b/data/images/objects/platforms/big.sprite new file mode 100644 index 000000000..dda1e870c --- /dev/null +++ b/data/images/objects/platforms/big.sprite @@ -0,0 +1,6 @@ +(supertux-sprite + (action + (name "default") + (images "big.png") + ) +) diff --git a/data/images/objects/platforms/small.png b/data/images/objects/platforms/small.png new file mode 100644 index 000000000..880915be9 Binary files /dev/null and b/data/images/objects/platforms/small.png differ diff --git a/data/images/objects/platforms/small.sprite b/data/images/objects/platforms/small.sprite new file mode 100644 index 000000000..2c00179e0 --- /dev/null +++ b/data/images/objects/platforms/small.sprite @@ -0,0 +1,6 @@ +(supertux-sprite + (action + (name "default") + (images "small.png") + ) +) diff --git a/data/images/objects/trampoline/trampoline.sprite b/data/images/objects/trampoline/trampoline.sprite index f7775becc..4b9e58d9b 100644 --- a/data/images/objects/trampoline/trampoline.sprite +++ b/data/images/objects/trampoline/trampoline.sprite @@ -1,5 +1,6 @@ (supertux-sprite (action + (name "normal") (x-offset 0) (y-offset 0) (images "trampoline1-0.png" diff --git a/data/images/tiles/doodads/iceshrub.sprite b/data/images/tiles/doodads/iceshrub.sprite index 35b4c9e93..03c1227ef 100644 --- a/data/images/tiles/doodads/iceshrub.sprite +++ b/data/images/tiles/doodads/iceshrub.sprite @@ -1,5 +1,6 @@ (supertux-sprite (action + (name "normal") (images "iceshrub.png") ) ) diff --git a/data/levels/test/light.stl b/data/levels/test/light.stl index c19971f41..a880c4585 100644 --- a/data/levels/test/light.stl +++ b/data/levels/test/light.stl @@ -78,6 +78,6 @@ (mriceblock (x 1180) (y 15) (stay-on-platform #f)) (mriceblock (x 939) (y 22) (stay-on-platform #f)) (mriceblock (x 703) (y 25) (stay-on-platform #f)) - (stalactite (x 322) (y 287) (stay-on-platform #f)) + (stalactite (x 322) (y 288) (stay-on-platform #f)) ) ) diff --git a/data/levels/test/platform.stl b/data/levels/test/platform.stl index c20008d87..e25eb38ac 100644 --- a/data/levels/test/platform.stl +++ b/data/levels/test/platform.stl @@ -129,67 +129,54 @@ (speed 0.500000) ) - (path - (name "path1") - (circular #t) - (nodes - (node (x 0) (y 0)) - (node (x 0) (y 0)) - (node (x 0) (y -100)) - (node (x -100)(y -100)) - ) + (platform + (path + (mode "pingpong") + (node (x 200) (y 850)) + (node (x 200) (y 750)) + (node (x 100) (y 750)) ) - (path - (name "path2") - (circular #t) - (nodes - (node (x 0) (y 0) (time 1)) - (node (x 0) (y 0) (time 1)) - (node (x 0) (y -100) (time 1)) - (node (x 0) (y -100) (time 1)) - ) + (sprite "images/objects/platforms/small.sprite") + ) + (platform + (path + (mode "pingpong") + (node (x 264) (y 850) (time 1)) + (node (x 264) (y 850) (time 1)) + (node (x 264) (y 750) (time 1)) + (node (x 264) (y 750) (time 1)) ) - (path - (name "path3") - (circular #t) - (nodes - (node (x 0) (y 0) (time 1)) - (node (x 0) (y 0) (time 1)) - (node (x 0) (y -100) (time 2)) - ) + (sprite "images/objects/platforms/small.sprite") + ) + (platform + (path + (mode "circular") + (node (x 328) (y 850) (time 1)) + (node (x 328) (y 850) (time 1)) + (node (x 328) (y 750) (time 2)) ) - (path - (name "path4") - (circular #t) - (nodes - (node (x 0) (y 0) (time 1)) - (node (x 0) (y -100) (time 1)) - (node (x 0) (y -200) (time 1)) - (node (x 0) (y -100) (time 1)) - ) + (sprite "images/objects/platforms/small.sprite") + ) + (platform + (path + (mode "circular") + (node (x 392) (y 850) (time 1)) + (node (x 392) (y 750) (time 1)) + (node (x 392) (y 650) (time 0.6)) + (node (x 392) (y 750) (time 1)) ) - (path - (name "path5") - (circular #f) - (nodes - (node) - (node (y -100)) - (node (x 100)) - (node (y 0)) - (node (x 0)) - ) + (sprite "images/objects/platforms/small.sprite") + ) + (platform + (path + (mode "circular") + (node (x 456) (y 750)) + (node (x 100) (y 300)) + (node (x 456) (y 300)) + (node (x 456) (y 750)) ) - - (platform (path "path1") (x 200) (y 850) (type "block1")) - (platform (path "path1") (x 232) (y 850) (type "block3")) - (platform (path "path2") (x 264) (y 850) (type "block1")) - (platform (path "path2") (x 296) (y 850) (type "block3")) - (platform (path "path3") (x 328) (y 850) (type "block1")) - (platform (path "path3") (x 360) (y 850) (type "block3")) - (platform (path "path4") (x 392) (y 850) (type "block1")) - (platform (path "path4") (x 424) (y 850) (type "block3")) - (platform (path "path5") (x 456) (y 850) (type "block1")) - (platform (path "path5") (x 488) (y 850) (type "block3")) + (sprite "images/objects/platforms/small.sprite") + ) (powerup (x 100) (y 700) (sprite "images/powerups/egg/egg.sprite")) (jumpy (x 140) (y 750)) (spawnpoint (name "main") (x 340) (y 800)) diff --git a/data/levels/test/simple.stl b/data/levels/test/simple.stl index c16c76318..ca9065df1 100644 --- a/data/levels/test/simple.stl +++ b/data/levels/test/simple.stl @@ -11,7 +11,7 @@ (speed 0.5)) (spawnpoint (name "main") (x 150) (y 100)) (rock (x 50) (y 50)) - ;(rock (x 50) (y 100)) + (rock (x 50) (y 100)) ;(rock (x 50) (y 150)) (tilemap (layer "background") diff --git a/data/levels/test/yeti.stl b/data/levels/test/yeti.stl index 836d65b94..d909f4ae5 100644 --- a/data/levels/test/yeti.stl +++ b/data/levels/test/yeti.stl @@ -122,25 +122,25 @@ Level.finish(); ) (particles-snow ) - (yeti_stalactite (x 97) (y 46)) - (yeti_stalactite (x 128) (y 47)) - (yeti_stalactite (x 161) (y 47)) - (yeti_stalactite (x 191) (y 47)) - (yeti_stalactite (x 223) (y 48)) - (yeti_stalactite (x 255) (y 49)) - (yeti_stalactite (x 288) (y 48)) - (yeti_stalactite (x 321) (y 49)) - (yeti_stalactite (x 352) (y 49)) - (yeti_stalactite (x 384) (y 49)) - (yeti_stalactite (x 417) (y 49)) - (yeti_stalactite (x 576) (y 49)) - (yeti_stalactite (x 545) (y 51)) - (yeti_stalactite (x 512) (y 50)) - (yeti_stalactite (x 479) (y 49)) - (yeti_stalactite (x 448) (y 49)) - (yeti_stalactite (x 607) (y 49)) - (yeti_stalactite (x 639) (y 49)) - (yeti_stalactite (x 671) (y 49)) + (yeti_stalactite (x 97) (y 32)) + (yeti_stalactite (x 128) (y 32)) + (yeti_stalactite (x 161) (y 32)) + (yeti_stalactite (x 191) (y 32)) + (yeti_stalactite (x 223) (y 32)) + (yeti_stalactite (x 255) (y 32)) + (yeti_stalactite (x 288) (y 32)) + (yeti_stalactite (x 321) (y 32)) + (yeti_stalactite (x 352) (y 32)) + (yeti_stalactite (x 384) (y 32)) + (yeti_stalactite (x 417) (y 32)) + (yeti_stalactite (x 576) (y 32)) + (yeti_stalactite (x 545) (y 32)) + (yeti_stalactite (x 512) (y 32)) + (yeti_stalactite (x 479) (y 32)) + (yeti_stalactite (x 448) (y 32)) + (yeti_stalactite (x 607) (y 32)) + (yeti_stalactite (x 639) (y 32)) + (yeti_stalactite (x 671) (y 32)) ) ) diff --git a/data/levels/world2/christoph2.stl b/data/levels/world2/christoph2.stl index f2fad15cd..15f956309 100644 --- a/data/levels/world2/christoph2.stl +++ b/data/levels/world2/christoph2.stl @@ -152,17 +152,35 @@ (x 2674) (y 1242) ) - (platform (path "path1") (x 1984) (y 1568) (type "block1")) - (platform (path "path1") (x 2016) (y 1568) (type "block2")) - (platform (path "path1") (x 2048) (y 1568) (type "block2")) - (platform (path "path1") (x 2080) (y 1568) (type "block3")) - (platform (path "path2") (x 1856) (y 736) (type "block1")) - (platform (path "path2") (x 1888) (y 736) (type "block2")) - (platform (path "path2") (x 1920) (y 736) (type "block2")) - (platform (path "path2") (x 1952) (y 736) (type "block3")) - (platform (path "path3") (x 896) (y 736) (type "block1")) - (platform (path "path3") (x 928) (y 736) (type "block2")) - (platform (path "path3") (x 960) (y 736) (type "block2")) - (platform (path "path3") (x 992) (y 736) (type "block3")) + (platform + (sprite "images/objects/platforms/big.sprite") + (path + (mode "circular") + (node (x 1984) (y 1568) (time 1)) + (node (x 1984) (y 1568) (time 3)) + (node (x 1984) (y 1152) (time 1)) + (node (x 1984) (y 1152) (time 1)) + ) + ) + (platform + (sprite "images/objects/platforms/big.sprite") + (path + (mode "circular") + (node (x 1856) (y 736) (time 1)) + (node (x 1856) (y 736) (time 3)) + (node (x 1856) (y 1152) (time 1)) + (node (x 1856) (y 1152) (time 1)) + ) + ) + (platform + (sprite "images/objects/platforms/big.sprite") + (path + (mode "circular") + (node (x 896) (y 736) (time 1)) + (node (x 896) (y 736) (time 2)) + (node (x 896) (y 288) (time 1)) + (node (x 896) (y 288) (time 1)) + ) + ) ) ) diff --git a/data/levels/world2/level2.stl b/data/levels/world2/level2.stl index d7cebdb26..008c12ce2 100644 --- a/data/levels/world2/level2.stl +++ b/data/levels/world2/level2.stl @@ -197,7 +197,7 @@ (message (_ "Drink me"))) (powerup (x 3168) (y 416) - (sprite "eat-me") + (sprite "images/objects/eat-me/eat-me.sprite") (script "levelflip();") ) (bonusblock (x 672) (y 1056) diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 85d28953f..5cbcf1a58 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -177,7 +177,7 @@ BadGuy::collision_player(Player& player, const CollisionHit& ) (get_bbox().p1.y + get_bbox().p2.y) / 2) { // if it's not possible to squish us, then this will hurt if(collision_squished(player)) - return CONTINUE; + return ABORT_MOVE; } player.kill(Player::SHRINK); diff --git a/src/badguy/stalactite.cpp b/src/badguy/stalactite.cpp index ab4fc4dc3..a058c186e 100644 --- a/src/badguy/stalactite.cpp +++ b/src/badguy/stalactite.cpp @@ -76,7 +76,7 @@ Stalactite::collision_solid(GameObject& , const CollisionHit& hit) if(state != STALACTITE_FALLING && state != STALACTITE_SQUISHED) return FORCE_MOVE; - if(fabsf(hit.normal.y) > .5) { // hit floor or roof? + if(hit.normal.y < .9) { // hit floor? state = STALACTITE_SQUISHED; set_group(COLGROUP_MOVING_ONLY_STATIC); physic.set_velocity_y(0); diff --git a/src/collision.hpp b/src/collision.hpp index d32de1ba3..360f94d0a 100644 --- a/src/collision.hpp +++ b/src/collision.hpp @@ -41,7 +41,7 @@ public: * Returns true in case of a collision and fills in the hit structure then. */ static bool rectangle_aatriangle(CollisionHit& hit, const Rect& rect, - const Vector& movement, const AATriangle& triangle); + const Vector& movement, const AATriangle& triangle); }; #endif diff --git a/src/collision_hit.hpp b/src/collision_hit.hpp index 204460348..81547d8c6 100644 --- a/src/collision_hit.hpp +++ b/src/collision_hit.hpp @@ -33,7 +33,8 @@ enum HitResponse /// if this happens to often then the move will just be aborted CONTINUE, /// do the move ignoring the collision - FORCE_MOVE + FORCE_MOVE, + TEST }; /** diff --git a/src/game_session.cpp b/src/game_session.cpp index f495becf0..e96f8215f 100644 --- a/src/game_session.cpp +++ b/src/game_session.cpp @@ -721,19 +721,19 @@ GameSession::start_sequence(const std::string& sequencename) if(sequencename == "endsequence" || sequencename == "fireworks") { if(end_sequence) return; - + end_sequence = ENDSEQUENCE_RUNNING; - endsequence_timer.start(level->extro_length); + endsequence_timer.start(7.3); last_x_pos = -1; - sound_manager->play_music("music/" + level->extro_music, false); - currentsector->player->invincible_timer.start(level->extro_length); + sound_manager->play_music("music/leveldone.ogg", false); + currentsector->player->invincible_timer.start(7.3); // Stop all clocks. for(std::vector::iterator i = currentsector->gameobjects.begin(); i != currentsector->gameobjects.end(); ++i) { GameObject* obj = *i; - + LevelTime* lt = dynamic_cast (obj); if(lt) lt->stop(); diff --git a/src/level.cpp b/src/level.cpp index f589380d4..57bc4a7f2 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -52,7 +52,7 @@ using namespace std; Level::Level() - : name("noname"), author("Mr. X"), extro_music("leveldone.ogg"), extro_length(7.0) + : name("noname"), author("Mr. X") { } @@ -86,17 +86,6 @@ Level::load(const std::string& filepath) iter.value()->get(name); } else if(token == "author") { iter.value()->get(author); - } else if(token == "extro") { - const lisp::Lisp* ext = iter.lisp(); - lisp::ListIterator ext_iter(ext); - while(ext_iter.next()) { - const std::string& ext_token = ext_iter.item(); - if(ext_token == "music") { - ext_iter.value()->get(extro_music); - } else if(ext_token == "length") { - ext_iter.value()->get(extro_length); - } - } } else if(token == "sector") { Sector* sector = new Sector; sector->parse(*(iter.lisp())); diff --git a/src/level.hpp b/src/level.hpp index 2175b3cd9..18d180312 100644 --- a/src/level.hpp +++ b/src/level.hpp @@ -35,8 +35,6 @@ class Level public: std::string name; std::string author; - std::string extro_music; - float extro_length; typedef std::vector Sectors; Sectors sectors; diff --git a/src/math/vector.hpp b/src/math/vector.hpp index 38c120426..6882cf160 100644 --- a/src/math/vector.hpp +++ b/src/math/vector.hpp @@ -82,6 +82,13 @@ public: return *this; } + const Vector& operator -=(const Vector& other) + { + x -= other.x; + y -= other.y; + return *this; + } + const Vector& operator *=(float val) { x *= val; diff --git a/src/moving_object.hpp b/src/moving_object.hpp index 79e415bb2..a58bc7527 100644 --- a/src/moving_object.hpp +++ b/src/moving_object.hpp @@ -110,6 +110,10 @@ protected: Vector movement; /** The collision group */ CollisionGroup group; + +private: + // this is only here for internal collision detection use + Rect dest; }; #endif diff --git a/src/object/camera.cpp b/src/object/camera.cpp index 8a4a9c01a..c1077cc43 100644 --- a/src/object/camera.cpp +++ b/src/object/camera.cpp @@ -33,6 +33,8 @@ #include "main.hpp" #include "object_factory.hpp" #include "msg.hpp" +#include "path.hpp" +#include "path_walker.hpp" Camera::Camera(Sector* newsector) : sector(newsector), do_backscrolling(true), scrollchange(NONE) @@ -63,15 +65,14 @@ Camera::parse(const lisp::Lisp& reader) reader.get("backscrolling", do_backscrolling); } else if(modename == "autoscroll") { mode = AUTOSCROLL; - std::string use_path; - - if (!reader.get("path", use_path)) throw std::runtime_error("No path specified in autoscroll camera."); - autoscrollPath = Path::GetByName(use_path); - if (autoscrollPath == NULL) { - msg_warning("Path for autoscroll camera not found! Make sure that the name is spelled correctly and that the path is initialized before the platform in the level file!"); - } + const lisp::Lisp* pathLisp = reader.get_lisp("path"); + if(pathLisp == NULL) + throw std::runtime_error("No path specified in autoscroll camera."); + autoscroll_path.reset(new Path()); + autoscroll_path->read(*pathLisp); + autoscroll_walker.reset(new PathWalker(autoscroll_path.get())); } else if(modename == "manual") { mode = MANUAL; } else { @@ -91,7 +92,7 @@ Camera::write(lisp::Writer& writer) writer.write_bool("backscrolling", do_backscrolling); } else if(mode == AUTOSCROLL) { writer.write_string("mode", "autoscroll"); - writer.write_string("path", autoscrollPath->GetName()); + autoscroll_path->write(writer); } else if(mode == MANUAL) { writer.write_string("mode", "manual"); } @@ -141,7 +142,7 @@ Camera::update(float elapsed_time) update_scroll_normal(elapsed_time); break; case AUTOSCROLL: - update_scroll_autoscroll(); + update_scroll_autoscroll(elapsed_time); break; case SCROLLTO: update_scroll_to(elapsed_time); @@ -269,14 +270,13 @@ Camera::update_scroll_normal(float elapsed_time) } void -Camera::update_scroll_autoscroll() +Camera::update_scroll_autoscroll(float elapsed_time) { - Player* player = sector->player; - + Player* player = sector->player; if(player->is_dying()) return; - translation = autoscrollPath->GetPosition(); + translation += autoscroll_walker->advance(elapsed_time); keep_in_bounds(translation); shake(); diff --git a/src/object/camera.hpp b/src/object/camera.hpp index b310822a7..0be750e92 100644 --- a/src/object/camera.hpp +++ b/src/object/camera.hpp @@ -21,19 +21,21 @@ #include #include +#include #include "math/vector.hpp" #include "game_object.hpp" #include "video/drawing_context.hpp" #include "serializable.hpp" #include "timer.hpp" -#include "object/path.hpp" namespace lisp { class Lisp; } class Sector; +class Path; +class PathWalker; class Camera : public GameObject, public Serializable { @@ -81,7 +83,7 @@ public: private: void update_scroll_normal(float elapsed_time); - void update_scroll_autoscroll(); + void update_scroll_autoscroll(float elapsed_time); void update_scroll_to(float elapsed_time); void keep_in_bounds(Vector& vector); void shake(); @@ -100,7 +102,8 @@ private: LeftRightScrollChange scrollchange; // autoscroll mode - Path* autoscrollPath; + std::auto_ptr autoscroll_path; + std::auto_ptr autoscroll_walker; // shaking Timer shaketimer; diff --git a/src/object/path.cpp b/src/object/path.cpp index c16f1deea..e4c415ec4 100644 --- a/src/object/path.cpp +++ b/src/object/path.cpp @@ -3,6 +3,7 @@ // SuperTux Path // Copyright (C) 2005 Philipp // Copyright (C) 2006 Christoph Sommer +// Copyright (C) 2006 Matthias Braun // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -18,6 +19,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. +#include #include "path.hpp" @@ -29,28 +31,42 @@ #include #include #include +#include -// snap to destination if within EPSILON pixels -#define EPSILON 1.5 - -Path::Path(const lisp::Lisp& reader) +Path::Path() { - circular = true; - forward = true; - - if (!reader.get("name", name)) throw std::runtime_error("Path without name"); - reader.get("circular", circular); - reader.get("forward", forward); - - const lisp::Lisp* nodes_lisp = reader.get_lisp("nodes"); - if(!nodes_lisp) throw std::runtime_error("Path without nodes"); +} - lisp::ListIterator iter(nodes_lisp); +Path::~Path() +{ +} - PathNode node; - node.time = 1; +void +Path::read(const lisp::Lisp& reader) +{ + lisp::ListIterator iter(&reader); + mode = CIRCULAR; while(iter.next()) { + if(iter.item() == "mode") { + std::string mode_string; + if(!iter.value()->get(mode_string)) + throw new std::runtime_error("Pathmode not a string"); + + if(mode_string == "oneshot") + mode = ONE_SHOT; + else if(mode_string == "pingpong") + mode = PING_PONG; + else if(mode_string == "circular") + mode = CIRCULAR; + else { + std::ostringstream msg; + msg << "Unknown pathmode '" << mode_string << "' found"; + throw new std::runtime_error(msg.str()); + } + continue; + } + if(iter.item() != "node") { msg_warning("unknown token '" << iter.item() << "' in Path nodes list. Ignored."); continue; @@ -58,108 +74,21 @@ Path::Path(const lisp::Lisp& reader) const lisp::Lisp* node_lisp = iter.lisp(); // each new node will inherit all values from the last one - node_lisp->get("x", node.position.x); - node_lisp->get("y", node.position.y); + Node node; + node.time = 1; + if( (!node_lisp->get("x", node.position.x) || + !node_lisp->get("y", node.position.y))) + throw new std::runtime_error("Path node without x and y coordinate specified"); node_lisp->get("time", node.time); - if(node.time <= 0) throw std::runtime_error("Path node with non-positive time"); + if(node.time <= 0) + throw std::runtime_error("Path node with non-positive time"); - pathNodes.push_back(node); - } - - if (pathNodes.size() < 1) throw std::runtime_error("Path with zero nodes"); - - // initial position and velocity will be set with the first update, as timeToGo is initialized to 0. - destinationNode = 0; - - // register this path for lookup: - registry[name] = this; -} - -Path::~Path() -{ - registry.erase(name); -} - - void -Path::update(float elapsed_time) -{ - - // TODO: carry excess time over to next node? This is how it was done in camera.cpp: - /* - if(auto_t - elapsed_time >= 0) { - translation += current_dir * elapsed_time; - auto_t -= elapsed_time; - } else { - // do the rest of the old movement - translation += current_dir * auto_t; - elapsed_time -= auto_t; - auto_t = 0; - - // construct path for next point - if(auto_idx+1 >= scrollpoints.size()) { - keep_in_bounds(translation); - return; - } - Vector distance = scrollpoints[auto_idx+1].position - - scrollpoints[auto_idx].position; - current_dir = distance.unit() * scrollpoints[auto_idx].speed; - auto_t = distance.norm() / scrollpoints[auto_idx].speed; - - // do movement for the remaining time - translation += current_dir * elapsed_time; - auto_t -= elapsed_time; - auto_idx++; - } - */ - - // advance to next node at scheduled time - if (timeToGo <= 0) { - position = pathNodes[destinationNode].position; - - // set destinationNode to next node - if (forward) { - destinationNode++; - if (destinationNode >= (int)pathNodes.size()) { - if (circular) { - destinationNode = 0; - } else { - destinationNode = (int)pathNodes.size()-1; - } - } - } else { - destinationNode--; - if (destinationNode < 0) { - if (circular) { - destinationNode = (int)pathNodes.size()-1; - } else { - destinationNode = 0; - } - } - } - - PathNode dn = pathNodes[destinationNode]; - timeToGo = dn.time; - velocity = (dn.position - position) / timeToGo; - } - - // move according to stored velocity - last_movement = velocity * elapsed_time; - position += last_movement; - timeToGo -= elapsed_time; - - // stop when we arrive at our destination - PathNode dn = pathNodes[destinationNode]; - if ((position - dn.position).norm() < EPSILON) { - velocity = Vector(0,0); + nodes.push_back(node); } -} - -void -Path::draw(DrawingContext& ) -{ - // TODO: Add a visible flag, draw the path if true + if (nodes.empty()) + throw std::runtime_error("Path with zero nodes"); } void @@ -167,12 +96,23 @@ Path::write(lisp::Writer& writer) { writer.start_list("path"); - writer.write_string("name", name); - writer.write_bool("circular", circular); - writer.write_bool("forward", forward); + switch(mode) { + case ONE_SHOT: + writer.write_string("mode", "oneshot"); + break; + case PING_PONG: + writer.write_string("mode", "pingpong"); + break; + case CIRCULAR: + writer.write_string("mode", "circular"); + break; + default: + msg_warning("Don't know how to write mode " << (int) mode << " ?!?"); + break; + } - for (int i=0; i < (int)pathNodes.size(); i++) { - PathNode node = pathNodes[i]; + for (size_t i=0; i < nodes.size(); i++) { + const Node& node = nodes[i]; writer.start_list("node"); writer.write_float("x", node.position.x); @@ -185,29 +125,12 @@ Path::write(lisp::Writer& writer) writer.end_list("path"); } -const Vector& -Path::GetPosition() { - return position; -} - -const Vector& -Path::GetLastMovement() { - return last_movement; -} - -const std::string -Path::GetName() { - return name; -} - -////////////////////////////////////////////////////////////////////////////// -// static stuff - -std::map Path::registry; - -Path* -Path::GetByName(const std::string& name) { - return registry[name]; +Vector +Path::get_base() const +{ + if(nodes.empty()) + return Vector(0, 0); + + return nodes[0].position; } -IMPLEMENT_FACTORY(Path, "path"); diff --git a/src/object/path.hpp b/src/object/path.hpp index f04623bc0..60812ecfb 100644 --- a/src/object/path.hpp +++ b/src/object/path.hpp @@ -3,6 +3,7 @@ // SuperTux Path // Copyright (C) 2005 Philipp // Copyright (C) 2006 Christoph Sommer +// Copyright (C) 2006 Matthias Braun // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -21,63 +22,48 @@ #ifndef __PATH_HPP__ #define __PATH_HPP__ -#include -#include -#include - +#include #include "math/vector.hpp" -#include "game_object.hpp" #include "lisp/lisp.hpp" #include "serializable.hpp" - -/** - * Helper class that stores an individual node of a Path - */ -class PathNode -{ -public: - Vector position; /**< position (in pixels) of this node */ - float time; /**< time (in seconds) to get to this node */ -}; - - -/** - * Path an object can travel along. Made up of multiple nodes of type PathNode. - */ -class Path : public GameObject, public Serializable +class Path : public Serializable { public: - Path(const lisp::Lisp& reader); + Path(); ~Path(); - virtual void update(float elapsed_time); - virtual void draw(DrawingContext& context); + void read(const lisp::Lisp& reader); + void write(lisp::Writer& writer); - virtual void write(lisp::Writer& writer); - - const Vector& GetPosition(); - const Vector& GetLastMovement(); - - const std::string GetName(); - - // WARNING: returns NULL if not found ! - static Path* GetByName(const std::string& name); + Vector get_base() const; private: - std::string name; /**< name this path can be referenced with, stored in PathRegistry */ - bool circular; /**< true: start with the first node once the last one has been reached. false: path will stop at last node */ - bool forward; /**< true: travel to nodes in the order they were defined. false: inverse order */ - std::vector pathNodes; /**< list of nodes that make up this path */ - - Vector position; /**< current position */ - Vector velocity; /**< current velocity */ - Vector last_movement; /**< amount of pixels we moved in the last call to update */ - - int destinationNode; /**< current destination Node */ - float timeToGo; /**< seconds until we arrive at the destination */ - - static std::map registry; + friend class PathWalker; + + enum WalkMode { + // moves from first to last path node and stops + ONE_SHOT, + // moves from first to last node then in reverse order back to first + PING_PONG, + // moves from last node back to the first node + CIRCULAR + }; + + /** + * Helper class that stores an individual node of a Path + */ + class Node + { + public: + Vector position; /**< the position of this node */ + float time; /**< time (in seconds) to get from this node to next node */ + }; + + std::vector nodes; + + WalkMode mode; }; #endif + diff --git a/src/object/platform.cpp b/src/object/platform.cpp index a28ec87a5..cbe01888a 100644 --- a/src/object/platform.cpp +++ b/src/object/platform.cpp @@ -21,41 +21,41 @@ #include "platform.hpp" +#include #include "msg.hpp" #include "video/drawing_context.hpp" #include "resources.hpp" #include "player.hpp" +#include "path.hpp" +#include "path_walker.hpp" #include "sprite/sprite_manager.hpp" #include "lisp/lisp.hpp" #include "object_factory.hpp" Platform::Platform(const lisp::Lisp& reader) { - std::string use_path; - std::string type; + std::string sprite_name; + reader.get("sprite", sprite_name); + if(sprite_name == "") + throw new std::runtime_error("No sprite specified in platform object"); + sprite.reset(sprite_manager->create(sprite_name)); - reader.get("x", bbox.p1.x); - reader.get("y", bbox.p1.y); - reader.get("type", type); - reader.get("path", use_path); - sprite = sprite_manager->create("images/objects/flying_platform/platform.sprite"); - sprite->set_action(type); - bbox.set_size(sprite->get_width(), sprite->get_height()); + const lisp::Lisp* pathLisp = reader.get_lisp("path"); + if(pathLisp == NULL) + throw new std::runtime_error("No path specified for platform"); + path.reset(new Path()); + path->read(*pathLisp); + walker.reset(new PathWalker(path.get())); + bbox.p1 = path->get_base(); + bbox.set_size(sprite->get_width(), sprite->get_height()); + + set_group(COLGROUP_STATIC); flags |= FLAG_SOLID; - - path = Path::GetByName(use_path); - - if (path == NULL) { - msg_warning("Path \"" << use_path << "\" for moving platform not found! Make sure that the name is spelled correctly and that the path is initialized before the platform in the level file!"); - } - - path_offset = bbox.p1; } Platform::~Platform() { - delete sprite; } //TODO: Squish Tux when standing between platform and solid tile/object @@ -65,24 +65,25 @@ HitResponse Platform::collision(GameObject& other, const CollisionHit& hit) { if (typeid(other) == typeid(Player)) { - Player* player = (Player*) &other; - if ((hit.normal.x == 0) && (hit.normal.y == 1)) { + if (hit.normal.y >= 0.9) { //Tux is standing on the platform - player->movement += path->GetLastMovement(); + //Player* player = (Player*) &other; + //player->add_velocity(speed * 1.5); + return TEST; } } if(other.get_flags() & FLAG_SOLID) { //Collision with a solid tile - //does nothing, because the movement vector isn't used at the moment return ABORT_MOVE; } return FORCE_MOVE; } void -Platform::update(float ) +Platform::update(float elapsed_time) { - set_pos(path->GetPosition() + path_offset); + movement = walker->advance(elapsed_time); + speed = movement / elapsed_time; } void diff --git a/src/object/platform.hpp b/src/object/platform.hpp index c6286c1c0..82eff0bda 100644 --- a/src/object/platform.hpp +++ b/src/object/platform.hpp @@ -20,6 +20,7 @@ #ifndef __PLATFORM_H__ #define __PLATFORM_H__ +#include #include "moving_object.hpp" #include "sprite/sprite.hpp" #include "object/path.hpp" @@ -36,11 +37,16 @@ public: virtual HitResponse collision(GameObject& other, const CollisionHit& hit); virtual void update(float elapsed_time); virtual void draw(DrawingContext& context); + const Vector& get_speed() const + { + return speed; + } private: - Sprite* sprite; - Path* path; - Vector path_offset; + std::auto_ptr sprite; + std::auto_ptr path; + std::auto_ptr walker; + Vector speed; }; #endif diff --git a/src/object/player.cpp b/src/object/player.cpp index 628752e35..a27973992 100644 --- a/src/object/player.cpp +++ b/src/object/player.cpp @@ -42,6 +42,7 @@ #include "trigger/trigger_base.hpp" #include "control/joystickkeyboardcontroller.hpp" #include "main.hpp" +#include "platform.hpp" #include "badguy/badguy.hpp" #include "player_status.hpp" #include "msg.hpp" @@ -122,6 +123,7 @@ Player::init() bbox.set_size(31.8, 63.8); else bbox.set_size(31.8, 31.8); + adjust_height = 0; dir = RIGHT; old_dir = dir; @@ -156,21 +158,17 @@ Player::set_controller(Controller* controller) void Player::update(float elapsed_time) { - // do we need to enable gravity again? - if(on_ground_flag) { - Rect lower = bbox; - lower.move(Vector(0, 4.0)); - if(Sector::current()->is_free_space(lower)) { - physic.enable_gravity(true); - on_ground_flag = false; - } - } - if(dying && dying_timer.check()) { dead = true; return; } + if(adjust_height != 0) { + bbox.move(Vector(0, bbox.get_height() - adjust_height)); + bbox.set_height(adjust_height); + adjust_height = 0; + } + if(!controller->hold(Controller::ACTION) && grabbed_object) { // move the grabbed object a bit away from tux Vector pos = get_pos() + @@ -210,6 +208,8 @@ Player::update(float elapsed_time) bbox.get_height()*0.66666 - 32); grabbed_object->grab(*this, pos, dir); } + + on_ground_flag = false; } bool @@ -525,8 +525,7 @@ Player::set_bonus(BonusType type, bool animate) return; if(player_status->bonus == NO_BONUS) { - bbox.set_height(63.8); - bbox.move(Vector(0, -32)); + adjust_height = 63.8; if(animate) growing_timer.start(GROWING_TIME); } @@ -600,7 +599,7 @@ Player::draw(DrawingContext& context) else // dir == RIGHT tux_body->set_action("buttjump-right"); } - else if (physic.get_velocity_y() != 0) + else if (physic.get_velocity_y() != 0 && !on_ground()) { if(dir == LEFT) tux_body->set_action("jump-left"); @@ -731,6 +730,7 @@ Player::collision(GameObject& other, const CollisionHit& hit) if(hit.normal.y < 0) { // landed on floor? if(physic.get_velocity_y() < 0) physic.set_velocity_y(0); + on_ground_flag = true; // remember normal of this tile @@ -744,16 +744,41 @@ Player::collision(GameObject& other, const CollisionHit& hit) floor_normal.y = (floor_normal.y * 0.9) + (hit.normal.y * 0.1); } - // disable gravity - physic.enable_gravity(false); + // hack platforms so that we stand normally on them when going down... + Platform* platform = dynamic_cast (&other); + if(platform != NULL) { + if(platform->get_speed().y > 0) + physic.set_velocity_y(-platform->get_speed().y); + //physic.set_velocity_x(platform->get_speed().x); + } } else if(hit.normal.y > 0) { // bumped against the roof physic.set_velocity_y(.1); + + // hack platform so that we are not glued to it from below + Platform* platform = dynamic_cast (&other); + if(platform != NULL) { + physic.set_velocity_y(-platform->get_speed().y); + } } if(fabsf(hit.normal.x) > .9) { // hit on the side? physic.set_velocity_x(0); } + MovingObject* omov = dynamic_cast (&other); + if(omov != NULL) { + Vector mov = movement - omov->get_movement(); + /* + printf("W %p - HITN: %3.1f %3.1f D:%3.1f TM: %3.1f %3.1f TD: %3.1f %3.1f PM: %3.2f %3.1f\n", + omov, + hit.normal.x, hit.normal.y, + hit.depth, + movement.x, movement.y, + dest.p1.x, dest.p1.y, + omov->get_movement().x, omov->get_movement().y); + */ + } + return CONTINUE; } @@ -817,7 +842,7 @@ Player::kill(HurtMode mode) { growing_timer.start(GROWING_TIME); safe_timer.start(TUX_SAFE_TIME + GROWING_TIME); - bbox.set_height(31.8); + adjust_height = 31.8; duck = false; player_status->bonus = NO_BONUS; } @@ -898,6 +923,12 @@ Player::check_bounds(Camera* camera) } void +Player::add_velocity(const Vector& velocity) +{ + physic.set_velocity(physic.get_velocity() + velocity); +} + +void Player::bounce(BadGuy& ) { if(controller->hold(Controller::JUMP)) diff --git a/src/object/player.hpp b/src/object/player.hpp index 880337275..add9a09d0 100644 --- a/src/object/player.hpp +++ b/src/object/player.hpp @@ -92,8 +92,8 @@ private: bool dying; bool backflipping; int backflip_direction; + public: - Direction dir; Direction old_dir; @@ -104,7 +104,7 @@ public: bool jumping; bool can_jump; bool butt_jump; - + Timer invincible_timer; Timer skidding_timer; Timer safe_timer; @@ -148,6 +148,11 @@ public: // set kick animation void kick(); + /** + * Adds velocity to the player (be carefull when using this) + */ + void add_velocity(const Vector& velocity); + void bounce(BadGuy& badguy); bool is_dead() const @@ -173,6 +178,8 @@ private: bool visible; + float adjust_height; + Portable* grabbed_object; Sprite* smalltux_gameover; diff --git a/src/object/powerup.cpp b/src/object/powerup.cpp index 3fce45b49..5f28bd7ea 100644 --- a/src/object/powerup.cpp +++ b/src/object/powerup.cpp @@ -57,8 +57,6 @@ PowerUp::collision(GameObject& other, const CollisionHit& hit) if(fabsf(hit.normal.y) > .5) { // roof or ground physic.set_velocity_y(0); } else { // bumped left or right - msg_debug("Normal: " << hit.normal.x << "," << hit.normal.y); - msg_debug("LRbounce, new speed: " << physic.get_velocity_x()); physic.set_velocity_x(-physic.get_velocity_x()); } diff --git a/src/object/rock.cpp b/src/object/rock.cpp index 5b022b5aa..2b17713af 100644 --- a/src/object/rock.cpp +++ b/src/object/rock.cpp @@ -35,6 +35,7 @@ Rock::Rock(const lisp::Lisp& reader) sprite = sprite_manager->create("images/objects/rock/rock.sprite"); grabbed = false; flags |= FLAG_SOLID | FLAG_PORTABLE; + set_group(COLGROUP_MOVING); } Rock::~Rock() @@ -73,16 +74,21 @@ Rock::update(float elapsed_time) } grabbed = false; + printf("%p - V %3.1f %3.1f - P %3.1f %3.1f\n", this, + physic.get_velocity().x, physic.get_velocity().y, + get_pos().x, get_pos().y); } HitResponse -Rock::collision(GameObject& object, const CollisionHit& ) +Rock::collision(GameObject& object, const CollisionHit& hit) { if(grabbed) { return FORCE_MOVE; } if(object.get_flags() & FLAG_SOLID) { + printf("%p vs %p - %3.1f %3.1f D %3.1f\n", this, &object, + hit.normal.x, hit.normal.y, hit.depth); physic.set_velocity(0, 0); return CONTINUE; } diff --git a/src/physic.cpp b/src/physic.cpp index e9fe94d97..329418a6e 100644 --- a/src/physic.cpp +++ b/src/physic.cpp @@ -56,28 +56,41 @@ Physic::set_velocity(float nvx, float nvy) vy = -nvy; } +void +Physic::set_velocity(const Vector& vector) +{ + vx = vector.x; + vy = vector.y; +} + void Physic::inverse_velocity_x() { -vx = -vx; + vx = -vx; } void Physic::inverse_velocity_y() { -vy = -vy; + vy = -vy; } float -Physic::get_velocity_x() +Physic::get_velocity_x() const { return vx; } float -Physic::get_velocity_y() +Physic::get_velocity_y() const { return -vy; } +Vector +Physic::get_velocity() const +{ + return Vector(vx, -vy); +} + void Physic::set_acceleration_x(float nax) { @@ -93,20 +106,26 @@ Physic::set_acceleration_y(float nay) void Physic::set_acceleration(float nax, float nay) { - ax = nax; - ay = -nay; + ax = nax; + ay = -nay; } float -Physic::get_acceleration_x() +Physic::get_acceleration_x() const { - return ax; + return ax; } float -Physic::get_acceleration_y() +Physic::get_acceleration_y() const +{ + return -ay; +} + +Vector +Physic::get_acceleration() const { - return -ay; + return Vector(ax, -ay); } void diff --git a/src/physic.hpp b/src/physic.hpp index 828b1e105..da44f9b7f 100644 --- a/src/physic.hpp +++ b/src/physic.hpp @@ -37,6 +37,7 @@ public: /// Sets velocity to a fixed value. void set_velocity(float vx, float vy); + void set_velocity(const Vector& vector); void set_velocity_x(float vx); void set_velocity_y(float vy); @@ -45,8 +46,9 @@ public: void inverse_velocity_x(); void inverse_velocity_y(); - float get_velocity_x(); - float get_velocity_y(); + Vector get_velocity() const; + float get_velocity_x() const; + float get_velocity_y() const; /// Set acceleration. /** Sets acceleration applied to the object. (Note that gravity is @@ -57,8 +59,9 @@ public: void set_acceleration_x(float ax); void set_acceleration_y(float ay); - float get_acceleration_x(); - float get_acceleration_y(); + Vector get_acceleration() const; + float get_acceleration_x() const; + float get_acceleration_y() const; /// Enables or disables handling of gravity. void enable_gravity(bool gravity_enabled); diff --git a/src/sector.cpp b/src/sector.cpp index 7ea513a1c..071e059c2 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -575,25 +575,14 @@ Sector::draw(DrawingContext& context) static const float DELTA = .001; void -Sector::collision_tilemap(MovingObject* object, CollisionHit& hit) const +Sector::collision_tilemap(const Rect& dest, const Vector& movement, + CollisionHit& hit) const { // calculate rectangle where the object will move - float x1, x2; - if(object->get_movement().x >= 0) { - x1 = object->get_bbox().p1.x; - x2 = object->get_bbox().p2.x + object->get_movement().x; - } else { - x1 = object->get_bbox().p1.x + object->get_movement().x; - x2 = object->get_bbox().p2.x; - } - float y1, y2; - if(object->get_movement().y >= 0) { - y1 = object->get_bbox().p1.y; - y2 = object->get_bbox().p2.y + object->get_movement().y; - } else { - y1 = object->get_bbox().p1.y + object->get_movement().y; - y2 = object->get_bbox().p2.y; - } + float x1 = dest.get_left(); + float x2 = dest.get_right(); + float y1 = dest.get_top(); + float y2 = dest.get_bottom(); // test with all tiles in this rectangle int starttilex = int(x1) / 32; @@ -603,8 +592,6 @@ Sector::collision_tilemap(MovingObject* object, CollisionHit& hit) const int max_y = int(y2+1); CollisionHit temphit; - Rect dest = object->get_bbox(); - dest.move(object->movement); for(int x = starttilex; x*32 < max_x; ++x) { for(int y = starttiley; y*32 < max_y; ++y) { const Tile* tile = solids->get_tile(x, y); @@ -616,7 +603,7 @@ Sector::collision_tilemap(MovingObject* object, CollisionHit& hit) const // only handle unisolid when the player is falling down and when he was // above the tile before if(tile->getAttributes() & Tile::UNISOLID) { - if(object->movement.y < 0 || object->get_bbox().p2.y > y*32) + if(movement.y < 0 || dest.get_top() - movement.y > y*32) continue; } @@ -626,7 +613,7 @@ Sector::collision_tilemap(MovingObject* object, CollisionHit& hit) const Vector p2((x+1)*32, (y+1)*32); triangle = AATriangle(p1, p2, tile->getData()); - if(Collision::rectangle_aatriangle(temphit, dest, object->movement, + if(Collision::rectangle_aatriangle(temphit, dest, movement, triangle)) { if(temphit.time > hit.time && (tile->getAttributes() & Tile::SOLID)) { hit = temphit; @@ -634,8 +621,7 @@ Sector::collision_tilemap(MovingObject* object, CollisionHit& hit) const } } else { // normal rectangular tile Rect rect(x*32, y*32, (x+1)*32, (y+1)*32); - if(Collision::rectangle_rectangle(temphit, dest, - object->movement, rect)) { + if(Collision::rectangle_rectangle(temphit, dest, movement, rect)) { if(temphit.time > hit.time && (tile->getAttributes() & Tile::SOLID)) { hit = temphit; } @@ -646,14 +632,15 @@ Sector::collision_tilemap(MovingObject* object, CollisionHit& hit) const } uint32_t -Sector::collision_tile_attributes(MovingObject* object) const +Sector::collision_tile_attributes(const Rect& dest) const { /** XXX This function doesn't work correctly as it will check all tiles * in the bounding box of the object movement, this might include tiles * that have actually never been touched by the object * (though this only occures for very fast objects...) */ - + +#if 0 // calculate rectangle where the object will move float x1, x2; if(object->get_movement().x >= 0) { @@ -671,6 +658,11 @@ Sector::collision_tile_attributes(MovingObject* object) const y1 = object->get_bbox().p1.y + object->get_movement().y; y2 = object->get_bbox().p2.y; } +#endif + float x1 = dest.p1.x; + float y1 = dest.p1.y; + float x2 = dest.p2.x; + float y2 = dest.p2.y; // test with all tiles in this rectangle int starttilex = int(x1-1) / 32; @@ -695,37 +687,109 @@ void Sector::collision_object(MovingObject* object1, MovingObject* object2) const { CollisionHit hit; - Rect dest1 = object1->get_bbox(); - dest1.move(object1->get_movement()); - Rect dest2 = object2->get_bbox(); - dest2.move(object2->get_movement()); Vector movement = object1->get_movement() - object2->get_movement(); - if(Collision::rectangle_rectangle(hit, dest1, movement, dest2)) { + if(Collision::rectangle_rectangle(hit, object1->dest, movement, object2->dest)) { HitResponse response1 = object1->collision(*object2, hit); hit.normal *= -1; HitResponse response2 = object2->collision(*object1, hit); if(response1 != CONTINUE) { if(response1 == ABORT_MOVE) - object1->movement = Vector(0, 0); + object1->dest = object1->get_bbox(); if(response2 == CONTINUE) - object2->movement += hit.normal * (hit.depth + DELTA); + object2->dest.move(hit.normal * (hit.depth + DELTA)); } else if(response2 != CONTINUE) { if(response2 == ABORT_MOVE) - object2->movement = Vector(0, 0); + object2->dest = object2->get_bbox(); if(response1 == CONTINUE) - object1->movement += -hit.normal * (hit.depth + DELTA); + object1->dest.move(-hit.normal * (hit.depth + DELTA)); } else { - object1->movement += -hit.normal * (hit.depth/2 + DELTA); - object2->movement += hit.normal * (hit.depth/2 + DELTA); + object1->dest.move(-hit.normal * (hit.depth/2 + DELTA)); + object2->dest.move(hit.normal * (hit.depth/2 + DELTA)); + } + } +} + +bool +Sector::collision_static(MovingObject* object, const Vector& movement) +{ + GameObject* collided_with = solids; + CollisionHit hit; + hit.time = -1; + + collision_tilemap(object->dest, movement, hit); + + // collision with other (static) objects + CollisionHit temphit; + for(MovingObjects::iterator i2 = moving_objects.begin(); + i2 != moving_objects.end(); ++i2) { + MovingObject* moving_object_2 = *i2; + if(moving_object_2->get_group() != COLGROUP_STATIC + || !moving_object_2->is_valid()) + continue; + + Rect dest2 = moving_object_2->get_bbox(); + // We're using the old position of the object here, + // this might seem a bit wrong but improves some situations + // like stacked boxes and badguys alot + // + dest2.move(moving_object_2->get_movement()); + Vector rel_movement + = movement - moving_object_2->get_movement(); + //Vector movement = + + if(Collision::rectangle_rectangle(temphit, object->dest, rel_movement, dest2) + && temphit.time > hit.time) { + hit = temphit; + collided_with = moving_object_2; + } + } + + if(hit.time < 0) + return true; + + HitResponse response = object->collision(*collided_with, hit); + hit.normal *= -1; + if(collided_with != solids) { + MovingObject* moving_object = (MovingObject*) collided_with; + HitResponse other_response = moving_object->collision(*object, hit); + if(other_response == ABORT_MOVE) { + moving_object->dest = moving_object->get_bbox(); + } else if(other_response == FORCE_MOVE) { + // the static object "wins" move tux out of the collision + object->dest.move(-hit.normal * (hit.depth + DELTA)); + return false; + } else if(other_response == TEST) { + object->dest.move(moving_object->get_movement()); + //object->movement += moving_object->get_movement(); } } + + if(response == CONTINUE) { + object->dest.move(-hit.normal * (hit.depth + DELTA)); + return false; + } else if(response == ABORT_MOVE) { + object->dest = object->get_bbox(); + return true; + } + + // force move + return false; } void Sector::handle_collisions() { + // calculate destination positions of the objects + for(MovingObjects::iterator i = moving_objects.begin(); + i != moving_objects.end(); ++i) { + MovingObject* moving_object = *i; + + moving_object->dest = moving_object->get_bbox(); + moving_object->dest.move(moving_object->get_movement()); + } + // part1: COLGROUP_MOVING vs COLGROUP_STATIC and tilemap // we do this up to 4 times and have to sort all results for the smallest // one before we can continue here @@ -737,59 +801,39 @@ Sector::handle_collisions() || !moving_object->is_valid()) continue; - // up to 4 tries - for(int t = 0; t < 4; ++t) { - CollisionHit hit; - hit.time = -1; - MovingObject* collided_with = NULL; - - // collision with tilemap - collision_tilemap(moving_object, hit); - - // collision with other objects - Rect dest1 = moving_object->get_bbox(); - dest1.move(moving_object->get_movement()); - CollisionHit temphit; - - for(MovingObjects::iterator i2 = moving_objects.begin(); - i2 != moving_objects.end(); ++i2) { - MovingObject* moving_object_2 = *i2; - if(moving_object_2->get_group() != COLGROUP_STATIC - || !moving_object_2->is_valid()) - continue; - - Rect dest2 = moving_object_2->get_bbox(); - dest2.move(moving_object_2->get_movement()); - Vector movement - = moving_object->get_movement() - moving_object_2->get_movement(); - if(Collision::rectangle_rectangle(temphit, dest1, movement, dest2) - && temphit.time > hit.time) { - hit = temphit; - collided_with = moving_object_2; - } - } + Vector movement = moving_object->get_movement(); - if(hit.time < 0) - break; + // test if x or y movement is dominant + if(fabsf(moving_object->get_movement().x) > fabsf(moving_object->get_movement().y)) { - // call collision callbacks - HitResponse response; - if(collided_with != 0) { - response = moving_object->collision(*collided_with, hit); - hit.normal *= -1; - collided_with->collision(*moving_object, hit); - } else { - response = moving_object->collision(*solids, hit); - hit.normal *= -1; + // test in x direction first, then y direction + moving_object->dest.move(Vector(0, -movement.y)); + for(int i = 0; i < 2; ++i) { + bool res = collision_static(moving_object, /*Vector(movement.x, 0)*/ movement); + if(res) + break; + } + moving_object->dest.move(Vector(0, movement.y)); + for(int i = 0; i < 2; ++i) { + bool res = collision_static(moving_object, /*Vector(0, movement.y)*/ movement); + if(res) + break; + } + + } else { + + // test in y direction first, then x direction + moving_object->dest.move(Vector(-movement.x, 0)); + for(int i = 0; i < 2; ++i) { + bool res = collision_static(moving_object, movement/*Vector(0, movement.y)*/); + if(res) + break; } - - if(response == CONTINUE) { - moving_object->movement += -hit.normal * (hit.depth + DELTA); - } else if(response == ABORT_MOVE) { - moving_object->movement = Vector(0, 0); - break; - } else { // force move - break; + moving_object->dest.move(Vector(movement.x, 0)); + for(int i = 0; i < 2; ++i) { + bool res = collision_static(moving_object, movement /*Vector(movement.x, 0)*/); + if(res) + break; } } } @@ -803,7 +847,7 @@ Sector::handle_collisions() || !moving_object->is_valid()) continue; - uint32_t tile_attributes = collision_tile_attributes(moving_object); + uint32_t tile_attributes = collision_tile_attributes(moving_object->dest); if(tile_attributes > Tile::FIRST_INTERESTING_FLAG) { moving_object->collision_tile(tile_attributes); } @@ -853,7 +897,7 @@ Sector::handle_collisions() i != moving_objects.end(); ++i) { MovingObject* moving_object = *i; - moving_object->bbox.move(moving_object->get_movement()); + moving_object->bbox = moving_object->dest; moving_object->movement = Vector(0, 0); } } diff --git a/src/sector.hpp b/src/sector.hpp index 05d5af47a..5bf497a05 100644 --- a/src/sector.hpp +++ b/src/sector.hpp @@ -87,11 +87,6 @@ public: void play_music(MusicType musictype); MusicType get_music_type(); - /** Checks for all possible collisions. And calls the - collision_handlers, which the collision_objects provide for this - case (or not). */ - void handle_collisions(); - bool add_bullet(const Vector& pos, float xm, Direction dir); bool add_smoke_cloud(const Vector& pos); void add_floating_text(const Vector& pos, const std::string& text); @@ -103,8 +98,7 @@ public: /** Get total number of badguys */ int get_total_badguys(); - void collision_tilemap(MovingObject* object, CollisionHit& hit) const; - uint32_t collision_tile_attributes(MovingObject* object) const; + void collision_tilemap(const Rect& dest, const Vector& movement, CollisionHit& hit) const; /** Checks if at the specified rectangle are gameobjects with STATIC flag set * (or solid tiles from the tilemap) @@ -119,6 +113,15 @@ public: } private: + uint32_t collision_tile_attributes(const Rect& dest) const; + + bool collision_static(MovingObject* object, const Vector& movement); + + /** Checks for all possible collisions. And calls the + collision_handlers, which the collision_objects provide for this + case (or not). */ + void handle_collisions(); + void collision_object(MovingObject* object1, MovingObject* object2) const; GameObject* parse_object(const std::string& name, const lisp::Lisp& lisp); diff --git a/src/title.cpp b/src/title.cpp index b9577e291..f4d6ea084 100644 --- a/src/title.cpp +++ b/src/title.cpp @@ -381,16 +381,6 @@ void title() // Contrib Menu generate_contrib_menu(); break; -#if 0 - case MNID_LEVELEDITOR: { - LevelEdtiro* leveleditor = new LevelEditor(); - leveleditor->run(); - delete leveleditor; - Menu::set_current(main_menu); - resume_demo(); - break; - } -#endif case MNID_CREDITS: sound_manager->stop_music(); fadeout(500);