X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fobject%2Fpath.cpp;h=5f7cc094767159832ce7c79fea12040a83088dea;hb=113cdbf07f441329690714a53a436503ab1d4b35;hp=e98264775b0995f48d4fc45281a325b70c0d0059;hpb=7a3f75400c0518b72f04fe4209145301191ba151;p=supertux.git diff --git a/src/object/path.cpp b/src/object/path.cpp index e98264775..5f7cc0947 100644 --- a/src/object/path.cpp +++ b/src/object/path.cpp @@ -1,8 +1,9 @@ // $Id$ -// +// // 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 @@ -13,152 +14,81 @@ // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. +#include #include "path.hpp" #include "lisp/lisp.hpp" #include "lisp/list_iterator.hpp" #include "object_factory.hpp" +#include "log.hpp" #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); - - 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; - } - 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"); - - 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) +void +Path::read(const lisp::Lisp& reader) { + lisp::ListIterator iter(&reader); - // 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; - } + mode = CIRCULAR; + while(iter.next()) { + if(iter.item() == "mode") { + std::string mode_string; + if(!iter.value()->get(mode_string)) + throw 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 std::runtime_error(msg.str()); } + continue; + } + + if(iter.item() != "node") { + log_warning << "unknown token '" << iter.item() << "' in Path nodes list. Ignored." << std::endl; + continue; } + const lisp::Lisp* node_lisp = iter.lisp(); - PathNode dn = pathNodes[destinationNode]; - timeToGo = dn.time; - velocity = (dn.position - position) / timeToGo; - } + // each new node will inherit all values from the last one + Node node; + node.time = 1; + if( (!node_lisp->get("x", node.position.x) || + !node_lisp->get("y", node.position.y))) + throw std::runtime_error("Path node without x and y coordinate specified"); + node_lisp->get("time", node.time); - // move according to stored velocity - last_movement = velocity * elapsed_time; - position += last_movement; - timeToGo -= elapsed_time; + if(node.time <= 0) + throw std::runtime_error("Path node with non-positive 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 @@ -166,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: + log_warning << "Don't know how to write mode " << (int) mode << " ?!?" << std::endl; + 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); @@ -184,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");