Another round of fixes for squirrel
[supertux.git] / src / object / path_walker.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "object/path_walker.hpp"
18
19 #include <math.h>
20 #include <assert.h>
21
22 PathWalker::PathWalker(const Path* path_, bool running_) :
23   path(path_),
24   running(running_),
25   current_node_nr(0),
26   next_node_nr(0),
27   stop_at_node_nr(running?-1:0),
28   node_time(0),
29   node_mult(),
30   walking_speed(1.0)
31 {
32   node_mult = 1 / path->nodes[0].time;
33   next_node_nr = path->nodes.size() > 1 ? 1 : 0;
34 }
35
36 PathWalker::~PathWalker()
37 {
38 }
39
40 Vector
41 PathWalker::advance(float elapsed_time)
42 {
43   if (!running) return path->nodes[current_node_nr].position;
44
45   assert(elapsed_time >= 0);
46
47   elapsed_time *= fabsf(walking_speed);
48
49   const Path::Node* current_node = & (path->nodes[current_node_nr]);
50   while(node_time + elapsed_time * node_mult >= 1) {
51     elapsed_time -= (1 - node_time) / node_mult;
52
53     if(walking_speed > 0) {
54       advance_node();
55     } else if(walking_speed < 0) {
56       goback_node();
57     }
58
59     current_node = & (path->nodes[current_node_nr]);
60     node_time = 0;
61     if(walking_speed > 0) {
62       node_mult = 1 / current_node->time;
63     } else {
64       node_mult = 1 / path->nodes[next_node_nr].time;
65     }
66   }
67
68   node_time += elapsed_time * node_mult;
69
70   return get_pos();
71 }
72
73 Vector
74 PathWalker::get_pos()
75 {
76   const Path::Node* current_node = & (path->nodes[current_node_nr]);
77   const Path::Node* next_node = & (path->nodes[next_node_nr]);
78   Vector new_pos = current_node->position +
79     (next_node->position - current_node->position) * node_time;
80
81   return new_pos;
82 }
83
84 void
85 PathWalker::goto_node(int node_no)
86 {
87   if (node_no == stop_at_node_nr) return;
88   running = true;
89   stop_at_node_nr = node_no;
90 }
91
92 void
93 PathWalker::start_moving()
94 {
95   running = true;
96   stop_at_node_nr = -1;
97 }
98
99 void
100 PathWalker::stop_moving()
101 {
102   stop_at_node_nr = next_node_nr;
103 }
104
105 void
106 PathWalker::advance_node()
107 {
108   current_node_nr = next_node_nr;
109   if (static_cast<int>(current_node_nr) == stop_at_node_nr) running = false;
110
111   if(next_node_nr + 1 < path->nodes.size()) {
112     next_node_nr++;
113     return;
114   }
115
116   switch(path->mode) {
117     case Path::ONE_SHOT:
118       next_node_nr = path->nodes.size() - 1;
119       walking_speed = 0;
120       return;
121
122     case Path::PING_PONG:
123       walking_speed = -walking_speed;
124       next_node_nr = path->nodes.size() > 1 ? path->nodes.size() - 2 : 0;
125       return;
126
127     case Path::CIRCULAR:
128       next_node_nr = 0;
129       return;
130   }
131
132   // we shouldn't get here
133   assert(false);
134   next_node_nr = path->nodes.size() - 1;
135   walking_speed = 0;
136 }
137
138 void
139 PathWalker::goback_node()
140 {
141   current_node_nr = next_node_nr;
142
143   if(next_node_nr > 0) {
144     next_node_nr--;
145     return;
146   }
147
148   switch(path->mode) {
149     case Path::PING_PONG:
150       walking_speed = -walking_speed;
151       next_node_nr = path->nodes.size() > 1 ? 1 : 0;
152       return;
153     default:
154       break;
155   }
156
157   assert(false);
158   next_node_nr = 0;
159   walking_speed = 0;
160 }
161
162 /* EOF */