4296315a41f50d3f354aa9bb2c2862975765458d
[supertux.git] / src / object / path.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2005 Philipp <balinor@pnxs.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 // 
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20
21 #include "path.hpp"
22
23 #include "lisp/lisp.hpp"
24 #include "lisp/list_iterator.hpp"
25 #include "object_factory.hpp"
26
27 #include <assert.h>
28
29
30 // some constants
31 #define DEFAULT_PIXELS_PER_SECOND       50
32 #define EPSILON                         1.5
33
34 Path::Path(const lisp::Lisp& reader)
35 {
36   forward = true;
37   float x,y;
38
39   lisp::ListIterator iter(&reader);
40
41   assert (iter.next());
42   std::string token = iter.item();
43   assert(token == "name");
44   iter.value()->get(name);
45
46   circular = true;
47   assert (iter.next());
48   token = iter.item();
49   assert(token == "circular");
50   iter.value()->get(circular);
51
52   pixels_per_second = DEFAULT_PIXELS_PER_SECOND;
53   assert (iter.next());
54   token = iter.item();
55   if (token == "speed") {
56     iter.value()->get(pixels_per_second);
57     iter.next();
58   }
59   do {
60     token = iter.item();
61     if(token == "x") {
62       iter.value()->get(x);
63     } else if(token == "y") {
64       iter.value()->get(y);
65       points.push_back(Vector(x,y));
66     }
67   } while(iter.next());
68
69   next_target = points.begin();
70   pos = *next_target;
71
72   calc_next_velocity();
73
74   // register this path for lookup:
75   registry[name] = this;
76 }
77
78 Path::~Path()
79 {
80   registry.erase(name);
81 }
82
83 void
84 Path::update(float elapsed_time)
85 {
86   last_movement = velocity * elapsed_time;
87   pos += last_movement;
88   if ((pos - *next_target).norm() < EPSILON) {
89     pos = *next_target;
90     calc_next_velocity();
91   }
92 }
93
94 void
95 Path::draw(DrawingContext& context)
96 {
97    // TODO: Add a visible flag, draw the path if true
98 }
99
100 const Vector&
101 Path::GetPosition() {
102   return pos;
103 }
104
105 const Vector&
106 Path::GetStart() {
107   return *(points.begin());
108 }
109
110 const Vector&
111 Path::GetLastMovement() {
112   return last_movement;
113 }
114
115 void
116 Path::calc_next_velocity()
117 {
118   Vector distance;
119
120   if (circular) {
121     ++next_target;
122     if (next_target == points.end()) {
123       next_target = points.begin();
124     }
125   }
126   else if (forward) {
127     ++next_target;
128     if (next_target == points.end()) {
129       forward = false;
130     }
131   }
132   else {
133     //FIXME: Implement going backwards on the list
134     //       I have no f***ing idea how this is done in C++
135   }
136
137   distance = *next_target - pos;
138   velocity = distance.unit() * pixels_per_second;
139 }
140
141 //////////////////////////////////////////////////////////////////////////////
142 // static stuff
143
144 PathRegistry Path::registry;
145
146 Path*
147 Path::GetByName(const std::string& name) {
148   return registry[name];
149 }
150
151 IMPLEMENT_FACTORY(Path, "path");