From: Christoph Sommer Date: Tue, 21 Mar 2006 21:04:24 +0000 (+0000) Subject: New Path based on time intervals; see levels/test/platform.stl X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=38515dd2d87530d28a45151e6463d1ac91a6519c;p=supertux.git New Path based on time intervals; see levels/test/platform.stl SVN-Revision: 3110 --- diff --git a/data/levels/test/platform.stl b/data/levels/test/platform.stl index 62594af82..d6fb14a27 100644 --- a/data/levels/test/platform.stl +++ b/data/levels/test/platform.stl @@ -128,18 +128,68 @@ (image "images/background/arctis.jpg") (speed 0.500000) ) - (path (name "path1") (circular #t) (speed 100) (x 0) (y 0) (x 0) (y -100) (x 100) (y -100) (x 100) (y 0)) - (path (name "path2") (circular #t) (speed 100) (x 0) (y 0) (x 0) (y 100) (x 100) (y 100) (x 100) (y 0)) + + (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)) + ) + ) + (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)) + ) + ) + (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)) + ) + ) + (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)) + ) + ) + (path + (name "path5") + (circular #f) + (nodes + (node) + (node (y -100)) + (node (x 100)) + (node (y 0)) + (node (x 0)) + ) + ) + (platform (use_path "path1") (x 200) (y 850) (type "block1")) - (platform (use_path "path1") (x 232) (y 850) (type "block2")) - (platform (use_path "path2") (x 264) (y 650) (type "block2")) - (platform (use_path "path2") (x 296) (y 650) (type "block2")) - (platform (use_path "path1") (x 328) (y 850) (type "block2")) - (platform (use_path "path1") (x 360) (y 850) (type "block2")) - (platform (use_path "path2") (x 392) (y 650) (type "block2")) - (platform (use_path "path2") (x 424) (y 650) (type "block2")) - (platform (use_path "path1") (x 456) (y 850) (type "block2")) - (platform (use_path "path1") (x 488) (y 850) (type "block3")) + (platform (use_path "path1") (x 232) (y 850) (type "block3")) + (platform (use_path "path2") (x 264) (y 850) (type "block1")) + (platform (use_path "path2") (x 296) (y 850) (type "block3")) + (platform (use_path "path3") (x 328) (y 850) (type "block1")) + (platform (use_path "path3") (x 360) (y 850) (type "block3")) + (platform (use_path "path4") (x 392) (y 850) (type "block1")) + (platform (use_path "path4") (x 424) (y 850) (type "block3")) + (platform (use_path "path5") (x 456) (y 850) (type "block1")) + (platform (use_path "path5") (x 488) (y 850) (type "block3")) (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/src/object/path.cpp b/src/object/path.cpp index 251afd029..bf7fefc78 100644 --- a/src/object/path.cpp +++ b/src/object/path.cpp @@ -1,7 +1,8 @@ // $Id$ // -// SuperTux +// SuperTux Path // Copyright (C) 2005 Philipp +// 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 @@ -25,53 +26,50 @@ #include "object_factory.hpp" #include +#include +#include - -// some constants -#define DEFAULT_PIXELS_PER_SECOND 50 -#define EPSILON 1.5 +// snap to destination if within EPSILON pixels +#define EPSILON 1.5 Path::Path(const lisp::Lisp& reader) { + circular = true; forward = true; - float x = 0, y = 0; - lisp::ListIterator iter(&reader); + if (!reader.get("name", name)) throw std::runtime_error("Path without name"); + reader.get("circular", circular); + reader.get("forward", forward); - assert (iter.next()); - std::string token = iter.item(); - assert(token == "name"); - iter.value()->get(name); + const lisp::Lisp* nodes_lisp = reader.get_lisp("nodes"); + if(!nodes_lisp) throw std::runtime_error("Path without nodes"); - circular = true; - assert (iter.next()); - token = iter.item(); - if (token == "circular") { - iter.value()->get(circular); - iter.next(); - } + lisp::ListIterator iter(nodes_lisp); - pixels_per_second = DEFAULT_PIXELS_PER_SECOND; - assert (iter.next()); - token = iter.item(); - if (token == "speed") { - iter.value()->get(pixels_per_second); - iter.next(); - } - do { - token = iter.item(); - if(token == "x") { - iter.value()->get(x); - } else if(token == "y") { - iter.value()->get(y); - points.push_back(Vector(x,y)); + PathNode node; + node.time = 1; + + while(iter.next()) { + if(iter.item() != "node") { + std::cerr << "Warning: unknown token '" << iter.item() << "' in Path nodes list. Ignored." << std::endl; + continue; } - } while(iter.next()); + 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_lisp->get("time", node.time); + + if(node.time <= 0) throw std::runtime_error("Path node with non-positive time"); - next_target = points.begin(); - pos = *next_target; + pathNodes.push_back(node); + } + + if (pathNodes.size() < 1) throw std::runtime_error("Path with zero nodes"); - calc_next_velocity(); + // 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; @@ -82,31 +80,62 @@ Path::~Path() registry.erase(name); } -void + void Path::update(float elapsed_time) { + + // 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; - pos += last_movement; - if ((pos - *next_target).norm() < EPSILON) { - pos = *next_target; - calc_next_velocity(); + 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); } + } void Path::draw(DrawingContext& ) { - // TODO: Add a visible flag, draw the path if true + // TODO: Add a visible flag, draw the path if true } const Vector& Path::GetPosition() { - return pos; -} - -const Vector& -Path::GetStart() { - return *(points.begin()); + return position; } const Vector& @@ -114,36 +143,11 @@ Path::GetLastMovement() { return last_movement; } -void -Path::calc_next_velocity() -{ - Vector distance; - - if (circular) { - ++next_target; - if (next_target == points.end()) { - next_target = points.begin(); - } - } - else if (forward) { - ++next_target; - if (next_target == points.end()) { - forward = false; - } - } - else { - //FIXME: Implement going backwards on the list - // I have no f***ing idea how this is done in C++ - } - - distance = *next_target - pos; - velocity = distance.unit() * pixels_per_second; -} ////////////////////////////////////////////////////////////////////////////// // static stuff -PathRegistry Path::registry; +std::map Path::registry; Path* Path::GetByName(const std::string& name) { diff --git a/src/object/path.hpp b/src/object/path.hpp index 97f21abe3..452e942fa 100644 --- a/src/object/path.hpp +++ b/src/object/path.hpp @@ -1,7 +1,8 @@ // $Id$ // -// SuperTux +// SuperTux Path // Copyright (C) 2005 Philipp +// 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 @@ -29,14 +30,20 @@ #include "lisp/lisp.hpp" -class Path; -typedef std::map PathRegistry; - - -typedef std::list PathPoints; -typedef std::list::const_iterator PathPointIter; +/** + * 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: @@ -47,27 +54,25 @@ public: virtual void draw(DrawingContext& context); const Vector& GetPosition(); - const Vector& GetStart(); const Vector& GetLastMovement(); // WARNING: returns NULL if not found ! static Path* GetByName(const std::string& name); private: - std::string name; - float pixels_per_second; - PathPoints points; - PathPointIter next_target; - Vector pos; - Vector velocity; - Vector last_movement; + 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 */ - bool circular; - bool forward; + Vector position; /**< current position */ + Vector velocity; /**< current velocity */ + Vector last_movement; /**< amount of pixels we moved in the last call to update */ - void calc_next_velocity(); + int destinationNode; /**< current destination Node */ + float timeToGo; /**< seconds until we arrive at the destination */ - static PathRegistry registry; + static std::map registry; }; #endif diff --git a/src/object/platform.cpp b/src/object/platform.cpp index 374a4ee8b..8d1a8f385 100644 --- a/src/object/platform.cpp +++ b/src/object/platform.cpp @@ -49,7 +49,7 @@ Platform::Platform(const lisp::Lisp& reader) std::cerr << "Warning: Path for moving platform not found! Make sure that the name is spelled correctly,\nand that the path is initialized before the platform in the level file!\n"; } - path_offset = bbox.p1 - path->GetStart(); + path_offset = bbox.p1; } Platform::~Platform()