00001 // SuperTux 00002 // Copyright (C) 2006 Matthias Braun <matze@braunis.de> 00003 // 00004 // This program is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 00017 #include "object/path_walker.hpp" 00018 00019 #include <math.h> 00020 #include <assert.h> 00021 00022 PathWalker::PathWalker(const Path* path, bool running) : 00023 path(path), 00024 running(running), 00025 current_node_nr(0), 00026 next_node_nr(0), 00027 stop_at_node_nr(running?-1:0), 00028 node_time(0), 00029 node_mult(), 00030 walking_speed(1.0) 00031 { 00032 node_mult = 1 / path->nodes[0].time; 00033 next_node_nr = path->nodes.size() > 1 ? 1 : 0; 00034 } 00035 00036 PathWalker::~PathWalker() 00037 { 00038 } 00039 00040 Vector 00041 PathWalker::advance(float elapsed_time) 00042 { 00043 if (!running) return path->nodes[current_node_nr].position; 00044 00045 assert(elapsed_time >= 0); 00046 00047 elapsed_time *= fabsf(walking_speed); 00048 00049 const Path::Node* current_node = & (path->nodes[current_node_nr]); 00050 while(node_time + elapsed_time * node_mult >= 1) { 00051 elapsed_time -= (1 - node_time) / node_mult; 00052 00053 if(walking_speed > 0) { 00054 advance_node(); 00055 } else if(walking_speed < 0) { 00056 goback_node(); 00057 } 00058 00059 current_node = & (path->nodes[current_node_nr]); 00060 node_time = 0; 00061 if(walking_speed > 0) { 00062 node_mult = 1 / current_node->time; 00063 } else { 00064 node_mult = 1 / path->nodes[next_node_nr].time; 00065 } 00066 } 00067 00068 node_time += elapsed_time * node_mult; 00069 00070 return get_pos(); 00071 } 00072 00073 Vector 00074 PathWalker::get_pos() 00075 { 00076 const Path::Node* current_node = & (path->nodes[current_node_nr]); 00077 const Path::Node* next_node = & (path->nodes[next_node_nr]); 00078 Vector new_pos = current_node->position + 00079 (next_node->position - current_node->position) * node_time; 00080 00081 return new_pos; 00082 } 00083 00084 void 00085 PathWalker::goto_node(int node_no) 00086 { 00087 if (node_no == stop_at_node_nr) return; 00088 running = true; 00089 stop_at_node_nr = node_no; 00090 } 00091 00092 void 00093 PathWalker::start_moving() 00094 { 00095 running = true; 00096 stop_at_node_nr = -1; 00097 } 00098 00099 void 00100 PathWalker::stop_moving() 00101 { 00102 stop_at_node_nr = next_node_nr; 00103 } 00104 00105 void 00106 PathWalker::advance_node() 00107 { 00108 current_node_nr = next_node_nr; 00109 if (static_cast<int>(current_node_nr) == stop_at_node_nr) running = false; 00110 00111 if(next_node_nr + 1 < path->nodes.size()) { 00112 next_node_nr++; 00113 return; 00114 } 00115 00116 switch(path->mode) { 00117 case Path::ONE_SHOT: 00118 next_node_nr = path->nodes.size() - 1; 00119 walking_speed = 0; 00120 return; 00121 00122 case Path::PING_PONG: 00123 walking_speed = -walking_speed; 00124 next_node_nr = path->nodes.size() > 1 ? path->nodes.size() - 2 : 0; 00125 return; 00126 00127 case Path::CIRCULAR: 00128 next_node_nr = 0; 00129 return; 00130 } 00131 00132 // we shouldn't get here 00133 assert(false); 00134 next_node_nr = path->nodes.size() - 1; 00135 walking_speed = 0; 00136 } 00137 00138 void 00139 PathWalker::goback_node() 00140 { 00141 current_node_nr = next_node_nr; 00142 00143 if(next_node_nr > 0) { 00144 next_node_nr--; 00145 return; 00146 } 00147 00148 switch(path->mode) { 00149 case Path::PING_PONG: 00150 walking_speed = -walking_speed; 00151 next_node_nr = path->nodes.size() > 1 ? 1 : 0; 00152 return; 00153 default: 00154 break; 00155 } 00156 00157 assert(false); 00158 next_node_nr = 0; 00159 walking_speed = 0; 00160 } 00161 00162 /* EOF */