some cleanups and changes to miniswig and scripting code
[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   if (token == "circular") {
50     iter.value()->get(circular);
51     iter.next();
52   }
53
54   pixels_per_second = DEFAULT_PIXELS_PER_SECOND;
55   assert (iter.next());
56   token = iter.item();
57   if (token == "speed") {
58     iter.value()->get(pixels_per_second);
59     iter.next();
60   }
61   do {
62     token = iter.item();
63     if(token == "x") {
64       iter.value()->get(x);
65     } else if(token == "y") {
66       iter.value()->get(y);
67       points.push_back(Vector(x,y));
68     }
69   } while(iter.next());
70
71   next_target = points.begin();
72   pos = *next_target;
73
74   calc_next_velocity();
75
76   // register this path for lookup:
77   registry[name] = this;
78 }
79
80 Path::~Path()
81 {
82   registry.erase(name);
83 }
84
85 void
86 Path::update(float elapsed_time)
87 {
88   last_movement = velocity * elapsed_time;
89   pos += last_movement;
90   if ((pos - *next_target).norm() < EPSILON) {
91     pos = *next_target;
92     calc_next_velocity();
93   }
94 }
95
96 void
97 Path::draw(DrawingContext& )
98 {
99    // TODO: Add a visible flag, draw the path if true
100 }
101
102 const Vector&
103 Path::GetPosition() {
104   return pos;
105 }
106
107 const Vector&
108 Path::GetStart() {
109   return *(points.begin());
110 }
111
112 const Vector&
113 Path::GetLastMovement() {
114   return last_movement;
115 }
116
117 void
118 Path::calc_next_velocity()
119 {
120   Vector distance;
121
122   if (circular) {
123     ++next_target;
124     if (next_target == points.end()) {
125       next_target = points.begin();
126     }
127   }
128   else if (forward) {
129     ++next_target;
130     if (next_target == points.end()) {
131       forward = false;
132     }
133   }
134   else {
135     //FIXME: Implement going backwards on the list
136     //       I have no f***ing idea how this is done in C++
137   }
138
139   distance = *next_target - pos;
140   velocity = distance.unit() * pixels_per_second;
141 }
142
143 //////////////////////////////////////////////////////////////////////////////
144 // static stuff
145
146 PathRegistry Path::registry;
147
148 Path*
149 Path::GetByName(const std::string& name) {
150   return registry[name];
151 }
152
153 IMPLEMENT_FACTORY(Path, "path");