X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fobject%2Fpath.cpp;h=5f7cc094767159832ce7c79fea12040a83088dea;hb=113cdbf07f441329690714a53a436503ab1d4b35;hp=be234d7127c054b92922396f72af17763acfd888;hpb=6e5fcfe8493510de0950745163690819f2b2cd90;p=supertux.git diff --git a/src/object/path.cpp b/src/object/path.cpp index be234d712..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,177 +14,123 @@ // 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); +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 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") { - std::cerr << "Warning: unknown token '" << iter.item() << "' in Path nodes list. Ignored." << std::endl; + log_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 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); - 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); + nodes.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); + if (nodes.empty()) + throw std::runtime_error("Path with zero nodes"); } - void -Path::update(float elapsed_time) +void +Path::write(lisp::Writer& writer) { - - // 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++; + writer.start_list("path"); + + 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; } - */ - - // 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; - } + for (size_t i=0; i < nodes.size(); i++) { + const Node& node = nodes[i]; - // move according to stored velocity - last_movement = velocity * elapsed_time; - position += last_movement; - timeToGo -= elapsed_time; + writer.start_list("node"); + writer.write_float("x", node.position.x); + writer.write_float("y", node.position.y); + writer.write_float("time", node.time); - // stop when we arrive at our destination - PathNode dn = pathNodes[destinationNode]; - if ((position - dn.position).norm() < EPSILON) { - velocity = Vector(0,0); + writer.end_list("node"); } + writer.end_list("path"); } -void -Path::draw(DrawingContext& ) +Vector +Path::get_base() const { - // TODO: Add a visible flag, draw the path if true -} - -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]; + if(nodes.empty()) + return Vector(0, 0); + + return nodes[0].position; } -IMPLEMENT_FACTORY(Path, "path");