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"
32 // snap to destination if within EPSILON pixels
35 Path::Path(const lisp::Lisp& reader)
40 if (!reader.get("name", name)) throw std::runtime_error("Path without name");
41 reader.get("circular", circular);
42 reader.get("forward", forward);
44 const lisp::Lisp* nodes_lisp = reader.get_lisp("nodes");
45 if(!nodes_lisp) throw std::runtime_error("Path without nodes");
47 lisp::ListIterator iter(nodes_lisp);
53 if(iter.item() != "node") {
54 std::cerr << "Warning: unknown token '" << iter.item() << "' in Path nodes list. Ignored." << std::endl;
57 const lisp::Lisp* node_lisp = iter.lisp();
59 // each new node will inherit all values from the last one
60 node_lisp->get("x", node.position.x);
61 node_lisp->get("y", node.position.y);
62 node_lisp->get("time", node.time);
64 if(node.time <= 0) throw std::runtime_error("Path node with non-positive time");
66 pathNodes.push_back(node);
69 if (pathNodes.size() < 1) throw std::runtime_error("Path with zero nodes");
71 // initial position and velocity will be set with the first update, as timeToGo is initialized to 0.
74 // register this path for lookup:
75 registry[name] = this;
84 Path::update(float elapsed_time)
87 // TODO: carry excess time over to next node? This is how it was done in camera.cpp:
89 if(auto_t - elapsed_time >= 0) {
90 translation += current_dir * elapsed_time;
91 auto_t -= elapsed_time;
93 // do the rest of the old movement
94 translation += current_dir * auto_t;
95 elapsed_time -= auto_t;
98 // construct path for next point
99 if(auto_idx+1 >= scrollpoints.size()) {
100 keep_in_bounds(translation);
103 Vector distance = scrollpoints[auto_idx+1].position
104 - scrollpoints[auto_idx].position;
105 current_dir = distance.unit() * scrollpoints[auto_idx].speed;
106 auto_t = distance.norm() / scrollpoints[auto_idx].speed;
108 // do movement for the remaining time
109 translation += current_dir * elapsed_time;
110 auto_t -= elapsed_time;
115 // advance to next node at scheduled time
117 position = pathNodes[destinationNode].position;
119 // set destinationNode to next node
122 if (destinationNode >= (int)pathNodes.size()) {
126 destinationNode = (int)pathNodes.size()-1;
131 if (destinationNode < 0) {
133 destinationNode = (int)pathNodes.size()-1;
140 PathNode dn = pathNodes[destinationNode];
142 velocity = (dn.position - position) / timeToGo;
145 // move according to stored velocity
146 last_movement = velocity * elapsed_time;
147 position += last_movement;
148 timeToGo -= elapsed_time;
150 // stop when we arrive at our destination
151 PathNode dn = pathNodes[destinationNode];
152 if ((position - dn.position).norm() < EPSILON) {
153 velocity = Vector(0,0);
159 Path::draw(DrawingContext& )
161 // TODO: Add a visible flag, draw the path if true
165 Path::write(lisp::Writer& writer)
167 writer.start_list("path");
169 writer.write_string("name", name);
170 writer.write_bool("circular", circular);
171 writer.write_bool("forward", forward);
173 for (int i=0; i < (int)pathNodes.size(); i++) {
174 PathNode node = pathNodes[i];
176 writer.start_list("node");
177 writer.write_float("x", node.position.x);
178 writer.write_float("y", node.position.y);
179 writer.write_float("time", node.time);
181 writer.end_list("node");
184 writer.end_list("path");
188 Path::GetPosition() {
193 Path::GetLastMovement() {
194 return last_movement;
202 //////////////////////////////////////////////////////////////////////////////
205 std::map<std::string,Path*> Path::registry;
208 Path::GetByName(const std::string& name) {
209 return registry[name];
212 IMPLEMENT_FACTORY(Path, "path");