Fixed a bug. Modified "Whatever floats your boat" to use new scriptable paths
[supertux.git] / src / object / path_walker.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.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  02111-1307, USA.
19
20 #include <config.h>
21
22 #include <math.h>
23 #include <assert.h>
24 #include "path_walker.hpp"
25
26 PathWalker::PathWalker(const Path* path, bool running)
27   : path(path), running(running), current_node_nr(0), next_node_nr(0), stop_at_node_nr(running?-1:0), node_time(0),
28     walking_speed(1.0)
29 {
30   last_pos = path->nodes[0].position;
31   node_mult = 1 / path->nodes[0].time;
32   next_node_nr = path->nodes.size() > 1 ? 1 : 0;
33 }
34
35 PathWalker::~PathWalker()
36 {
37 }
38
39 Vector
40 PathWalker::advance(float elapsed_time)
41 {
42   if (!running) return Vector(0,0);
43
44   assert(elapsed_time >= 0);
45
46   elapsed_time *= fabsf(walking_speed);
47   
48   const Path::Node* current_node = & (path->nodes[current_node_nr]);
49   while(node_time + elapsed_time * node_mult >= 1) {
50     elapsed_time -= (1 - node_time) / node_mult;
51
52     if(walking_speed > 0) {
53       advance_node();
54     } else if(walking_speed < 0) {
55       goback_node();
56     }
57
58     current_node = & (path->nodes[current_node_nr]);
59     node_time = 0;
60     if(walking_speed > 0) {
61       node_mult = 1 / current_node->time;
62     } else {
63       node_mult = 1 / path->nodes[next_node_nr].time;
64     }
65   }
66   
67   const Path::Node* next_node = & (path->nodes[next_node_nr]);
68   node_time += elapsed_time * node_mult;
69  
70   Vector new_pos = current_node->position + 
71     (next_node->position - current_node->position) * node_time;
72     
73   Vector result = new_pos - last_pos;
74   last_pos = new_pos;
75   
76   return result;
77 }
78
79 void 
80 PathWalker::goto_node(int node_no)
81 {
82   if (node_no == stop_at_node_nr) return;
83   running = true;
84   stop_at_node_nr = node_no;
85 }
86
87 void 
88 PathWalker::start_moving()
89 {
90   running = true;
91   stop_at_node_nr = -1;
92 }
93
94 void 
95 PathWalker::stop_moving()
96 {
97   stop_at_node_nr = next_node_nr;
98 }
99
100
101 void
102 PathWalker::advance_node()
103 {
104   current_node_nr = next_node_nr;
105   if (static_cast<int>(current_node_nr) == stop_at_node_nr) running = false;
106
107   if(next_node_nr + 1 < path->nodes.size()) {
108     next_node_nr++;
109     return;
110   }
111
112   switch(path->mode) {
113     case Path::ONE_SHOT:
114       next_node_nr = path->nodes.size() - 1;
115       walking_speed = 0;
116       return;
117
118     case Path::PING_PONG:
119       walking_speed = -walking_speed;
120       next_node_nr = path->nodes.size() > 1 ? path->nodes.size() - 2 : 0;
121       return;
122
123     case Path::CIRCULAR:
124       next_node_nr = 0;
125       return;
126   }
127
128   // we shouldn't get here
129   assert(false);
130   next_node_nr = path->nodes.size() - 1;
131   walking_speed = 0;
132 }
133
134 void
135 PathWalker::goback_node()
136 {
137   current_node_nr = next_node_nr;
138
139   if(next_node_nr > 0) {
140     next_node_nr--;
141     return;
142   }
143
144   switch(path->mode) {
145     case Path::PING_PONG:
146       walking_speed = -walking_speed;
147       next_node_nr = path->nodes.size() > 1 ? 1 : 0;
148       return;
149     default:
150       break;
151   }
152
153   assert(false);
154   next_node_nr = 0;
155   walking_speed = 0;
156 }