4 // Copyright (C) 2005 Philipp <balinor@pnxs.de>
5 // Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24 #include "lisp/lisp.hpp"
25 #include "lisp/list_iterator.hpp"
26 #include "object_factory.hpp"
33 // snap to destination if within EPSILON pixels
36 Path::Path(const lisp::Lisp& reader)
41 if (!reader.get("name", name)) throw std::runtime_error("Path without name");
42 reader.get("circular", circular);
43 reader.get("forward", forward);
45 const lisp::Lisp* nodes_lisp = reader.get_lisp("nodes");
46 if(!nodes_lisp) throw std::runtime_error("Path without nodes");
48 lisp::ListIterator iter(nodes_lisp);
54 if(iter.item() != "node") {
55 msg_warning("unknown token '" << iter.item() << "' in Path nodes list. Ignored.");
58 const lisp::Lisp* node_lisp = iter.lisp();
60 // each new node will inherit all values from the last one
61 node_lisp->get("x", node.position.x);
62 node_lisp->get("y", node.position.y);
63 node_lisp->get("time", node.time);
65 if(node.time <= 0) throw std::runtime_error("Path node with non-positive time");
67 pathNodes.push_back(node);
70 if (pathNodes.size() < 1) throw std::runtime_error("Path with zero nodes");
72 // initial position and velocity will be set with the first update, as timeToGo is initialized to 0.
75 // register this path for lookup:
76 registry[name] = this;
85 Path::update(float elapsed_time)
88 // TODO: carry excess time over to next node? This is how it was done in camera.cpp:
90 if(auto_t - elapsed_time >= 0) {
91 translation += current_dir * elapsed_time;
92 auto_t -= elapsed_time;
94 // do the rest of the old movement
95 translation += current_dir * auto_t;
96 elapsed_time -= auto_t;
99 // construct path for next point
100 if(auto_idx+1 >= scrollpoints.size()) {
101 keep_in_bounds(translation);
104 Vector distance = scrollpoints[auto_idx+1].position
105 - scrollpoints[auto_idx].position;
106 current_dir = distance.unit() * scrollpoints[auto_idx].speed;
107 auto_t = distance.norm() / scrollpoints[auto_idx].speed;
109 // do movement for the remaining time
110 translation += current_dir * elapsed_time;
111 auto_t -= elapsed_time;
116 // advance to next node at scheduled time
118 position = pathNodes[destinationNode].position;
120 // set destinationNode to next node
123 if (destinationNode >= (int)pathNodes.size()) {
127 destinationNode = (int)pathNodes.size()-1;
132 if (destinationNode < 0) {
134 destinationNode = (int)pathNodes.size()-1;
141 PathNode dn = pathNodes[destinationNode];
143 velocity = (dn.position - position) / timeToGo;
146 // move according to stored velocity
147 last_movement = velocity * elapsed_time;
148 position += last_movement;
149 timeToGo -= elapsed_time;
151 // stop when we arrive at our destination
152 PathNode dn = pathNodes[destinationNode];
153 if ((position - dn.position).norm() < EPSILON) {
154 velocity = Vector(0,0);
160 Path::draw(DrawingContext& )
162 // TODO: Add a visible flag, draw the path if true
166 Path::write(lisp::Writer& writer)
168 writer.start_list("path");
170 writer.write_string("name", name);
171 writer.write_bool("circular", circular);
172 writer.write_bool("forward", forward);
174 for (int i=0; i < (int)pathNodes.size(); i++) {
175 PathNode node = pathNodes[i];
177 writer.start_list("node");
178 writer.write_float("x", node.position.x);
179 writer.write_float("y", node.position.y);
180 writer.write_float("time", node.time);
182 writer.end_list("node");
185 writer.end_list("path");
189 Path::GetPosition() {
194 Path::GetLastMovement() {
195 return last_movement;
203 //////////////////////////////////////////////////////////////////////////////
206 std::map<std::string,Path*> Path::registry;
209 Path::GetByName(const std::string& name) {
210 return registry[name];
213 IMPLEMENT_FACTORY(Path, "path");