|
ORTS
|
00001 #ifndef ST_FORCEFIELD_H 00002 #define ST_FORCEFIELD_H 00003 00004 //Comments coming soon, sorry... 00005 // This is an ORTS file 00006 // (c) Michael Buro, Sami Wagiaalla, David Deutscher, Nick Wiebe 00007 // licensed under the GPL 00008 00009 // Local Pathfinder using ForceFields to execute paths, 00010 // and interface to global (simple a*) pathfinder. 00011 00012 00013 #include "TerrainBasicImp.H" 00014 #include "Random.H" 00015 #include "Coord.H" 00016 #include "SimpleTerrain.H" 00017 00018 #include "boost/shared_ptr.hpp" 00019 00020 namespace SimpleTerrain{ 00021 00022 typedef TerrainBase::Loc Loc; 00023 typedef TerrainBase::Segment Segment; 00024 typedef TerrainBase::Task Task; 00025 00026 /** Structure to keep data associated to a path 00027 fixme: right now this inherits from UnitPath, from SimpleTerrain, 00028 but that doesn't make much sense. This was done primarily for convenience. 00029 */ 00030 struct UnitPath_FF : public UnitPath 00031 { 00032 /// Path data 00033 //@{ 00034 //const Object *obj; 00035 //Vector<Loc> path; 00036 //Loc goal; 00037 //int current_target; // index of current way point in path vector 00038 //bool no_orders_yet; // true at the beginning, before the first move command is issued 00039 //@} 00040 00041 /// Collision avoidance and resolution 00042 //@{ 00043 // If adding fields - check ST_Task::set_path for needed updates. 00044 //bool stopped_to_avoid_collision; // true if the object was stopped temporarily to avoid a collision 00045 //int collision_step; // this is incremented while solving unexpected stops 00046 //uint4 wakeup; // if SDL_GetTicks() >= wakeup then this UnitPath is not 00047 // sleeping ie not to be skipped over. 00048 //Loc spot; // spot of the last unexpected collision 00049 //@} 00050 00051 bool replanned; 00052 00053 UnitPath_FF(const Object *obj_, const Vector<Loc> &path_) : UnitPath(obj_, path_), replanned(false){}; 00054 ~UnitPath_FF() {}; 00055 00056 //void mark_spot(const Loc &p) { spot = p; }; 00057 //void sleep(int time) { wakeup = SDL_GetTicks() + time; }; 00058 //bool sleeping() const { return wakeup > SDL_GetTicks(); }; 00059 00060 //bool is_intersect(const Segment &) const; 00061 }; 00062 00063 00064 /** Functor that allows Locations to be put into sets*/ 00065 class Loc_less : public std::binary_function<Loc, Loc, bool>{ 00066 public: 00067 bool operator() (Loc a, Loc b) const; 00068 }; 00069 00070 /** Two Dimensional Vector */ 00071 class Vec_2D{ 00072 public: 00073 sint4 x;/// x-coord 00074 sint4 y;/// y-coord 00075 Vec_2D(sint4 x_=0, sint4 y_=0) : x(x_), y(y_){}; 00076 Vec_2D(const Vec_2D &other) : x(other.x), y(other.y){}; 00077 Vec_2D(const Loc &a, const Loc &b) : x(b.x - a.x), y(b.y - a.y) {}; 00078 Vec_2D operator+(const Vec_2D &other) const; ///Vector addition 00079 Vec_2D operator-(const Vec_2D &other) const; ///Vector subtraction 00080 Vec_2D project_onto(const Vec_2D &other) const; /// Project the vector onto the line defined by the given vector 00081 sint4 dot_prod(const Vec_2D &other) const; 00082 real8 length() const; 00083 Vec_2D multiply(real8 k) const; 00084 bool operator==(const Vec_2D &other) const; 00085 bool operator!= (const Vec_2D &other) const; 00086 00087 inline static sint4 round(real8 real) { 00088 return (sint4)floor(real + 0.5); 00089 } 00090 }; 00091 00092 /// The internal data complementing Task data: 00093 struct FF_Task { 00094 Task task; 00095 bool isPending; 00096 bool isFailed; 00097 bool noPathFound; 00098 boost::shared_ptr<UnitPath_FF> path; // todo: replace with a cleaner implementation 00099 //Vector<const Object*> followers; 00100 uint4 replanned; 00101 //sint4 ticks; //used for automatic replanning when moving to a mobile object 00102 00103 FF_Task(const Task& task_) 00104 : task(task_), isPending(true), isFailed(false), noPathFound(false), replanned(0) {}; 00105 FF_Task(const FF_Task& other) 00106 : task(other.task), isPending(other.isPending), 00107 isFailed(other.isFailed), noPathFound(other.noPathFound), 00108 path(other.path), /*followers(other.followers),*/ replanned(other.replanned) {}; 00109 void set_path(const Object *obj_, const Vector<Loc> &path_); 00110 //void init_path(const Object *obj_, const Vector<Loc> &path_) { path=boost::shared_ptr<UnitPath>(new UnitPath(obj_, path_)); }; 00111 bool isValid() const { return !isPending && !isFailed && !noPathFound && path; }; 00112 private: 00113 FF_Task operator=(const FF_Task& other); 00114 }; 00115 00116 /// An implementation of the TerrainBase interface using forcefields for local 00117 /// pathfinding. 00118 class ST_ForceField : public TerrainBasicImp<FF_Task> 00119 { 00120 public: 00121 00122 ST_ForceField(); 00123 virtual ~ST_ForceField() {}; 00124 00125 /// add command-line options specific to this implementation, using static methods of class Options 00126 static void add_options(void); 00127 00128 //--------------------------------------------------------------------- 00129 /// \name Implementation of relevant parts of the TerrainBase interface 00130 //--------------------------------------------------------------------- 00131 //@{ 00132 virtual void init(sint4 tiles_x_, sint4 tiles_y_, sint4 tile_points_, sint4 client_pID_, sint4 neutral_pID); 00133 00134 virtual void add_obj(const Object *obj); 00135 virtual void update_obj(const Object *obj); 00136 virtual void remove_obj(const Object *obj); 00137 virtual void add_segments(const Vector<TerrainBase::Segment> &s); 00138 00139 virtual void cancel_task(const Object *obj); 00140 virtual void remove_task(TaskId tid); 00141 TaskId execute_task(const Task &task, const Path &path); 00142 00143 virtual void execute_tasks(Vector<MoveCmd> &cmds, Vector<StatusMsg> &msgs); 00144 virtual bool plan_tasks(uint4 max_time=0); 00145 00146 virtual real8 find_path(const Loc &l1, const Loc &l2, sint4 radius, Path *path, ConsiderObjects consider = CONSIDER_ALL); 00147 virtual real8 find_path(const Object *obj, const Goal &goal, Path *path, ConsiderObjects consider = CONSIDER_ALL); 00148 00149 //@} 00150 //--------------------------------------------------------------------- 00151 00152 // public to allow REGISTER_TYPEOF definitions 00153 typedef std::map<const Object*, Loc> Obj2LocMap; 00154 typedef std::map<Loc, bool, Loc_less> SegmentEndsMap; 00155 00156 private: 00157 00158 /** Perform PF for a single pending task, and insert results to data structures. 00159 Return true iff did some planning. */ 00160 bool plan_pending_task(uint4 stop_time); 00161 /** Perform PF for a single failed task, and insert results to data structures. 00162 Return true iff did some planning. */ 00163 bool plan_failed_task(uint4 stop_time); 00164 /** Accessory function for planning either a pending or a failed task. */ 00165 void plan_task(TIter tit, uint4 stop_time); 00166 /** Randomly choose a failed task. Return tasks.end() if no failed task exists. */ 00167 TIter get_random_failed_task(void); 00168 /** Invalidate existing paths that intersect a given new boundary. */ 00169 void invalidate_paths(const Vector<Segment> &segments); 00170 /** Test if the object is at the given location, 00171 accounting for a 1-tick look-ahead for moving objects. */ 00172 static bool is_at_location(const Object* obj, const Loc& target); 00173 /** Test if the distance from the object to the target is within the given range.*/ 00174 static bool is_near_location(const Object* obj, const Loc& target, sint4 range); 00175 /** Test if the object is at the goal of the given task, implementing 00176 (some) of the various definitions of 'goal'. */ 00177 bool is_at_goal(const Object* obj, const Task& task); 00178 /** Test if the object is within firing range */ 00179 static bool is_in_range(const Object* moving_obj, const Object *goal_obj); 00180 static bool is_in_range(const Object *moving_obj, const Loc goal_loc); 00181 00182 /** Add a move command to the Vector of commands, telling the object to 00183 move to the target location at maximum speed. 00184 Also, updates the location associated with the object for forcefield purposes 00185 */ 00186 void add_move_command(const Object *obj, Loc target, Vector<TerrainBase::MoveCmd> &cmds); 00187 /** Determines what team an object is on. 00188 If the team cannot be determined, returns -1 */ 00189 sint4 what_team(const Object *obj); 00190 00191 //--------------------------------------------------------------------- 00192 /// \name Force Field methods 00193 //--------------------------------------------------------------------- 00194 //@{ 00195 /** 00196 Calculates the direction that an object should move to, based on the path 00197 they are following and any obstacles in the vicinity. 00198 @param path Path data 00199 @param output reference to a location that in the direction that the object should 00200 move to. 00201 fixme: maybe a location should be returned, instead of the pass by reference 00202 */ 00203 void get_forcefield_target(UnitPath_FF &path, Loc &output); 00204 00205 /** 00206 @param object The object that is moving 00207 @param attractor The point that is attracting the object 00208 @param output reference to a location that is in the direction that the 00209 object should move to. 00210 */ 00211 void get_forcefield_target(const Object *obj, const Loc &attractor, Loc &output); 00212 00213 /** used for pushing, where there is no attractor*/ 00214 void get_push_target(const Object *obj, Loc &output); 00215 00216 00217 /** Adjusts the vector so that it is not directed more than 90 degrees on either side 00218 of the target vector.*/ 00219 void restrict_vector(const Vec_2D &target_vec, Vec_2D &vec); 00220 00221 /** Finds the location of point on a line that is closest to the given location*/ 00222 Loc find_point_on_line(Loc loc, Loc line_start, Loc line_end); 00223 00224 /** Calculates the repulsion caused by a point on an object and returns 00225 it as a vector*/ 00226 Vec_2D get_point_repulsion(const Object *moving_obj, const Loc &point, sint4 radius = 0); 00227 00228 /** Calculates the repulsion caused by a line on an object and returns 00229 it as a vector */ 00230 Vec_2D get_line_repulsion(const Object *moving_obj, const Segment &seg); 00231 00232 /** Calculates the position of the attractor along the path. 00233 The attractor is positioned a set distance ahead of the point closest to the 00234 object on the path. 00235 */ 00236 Loc get_attractor(UnitPath_FF &path); 00237 00238 //@} 00239 Obj2LocMap objects; ///< Used to calculate object repulsion 00240 Vector<Segment> segments; ///< Used to calculate wall repulsion 00241 SegmentEndsMap segment_ends; ///< Used to calculate repulsion from the ends of walls 00242 00243 boost::shared_ptr<ST_Terrain::PFEngine> pfEngine; ///< The internal Path Finding engine 00244 std::set<const Object*> objsToStop; ///< Objects for which we should set a stop-moving action 00245 Random rand; 00246 bool pushing_on; 00247 bool wp_attract; 00248 bool stop_to_plan; 00249 00250 /** This multiplied by the max speed of an object gives the range at which objects 00251 and walls will exert a force on the objec*/ 00252 static const sint4 FIELD_RANGE_MULTIPLIER = 2; 00253 00254 /** The strength of attractors (does not vary with distance)*/ 00255 static const sint4 ATTRACTOR_FORCE = 26; 00256 00257 /** This divided by the distance squared to the moving object gives the strength 00258 of the repulsors*/ 00259 static const sint4 REPULSOR_BASELINE = 200; 00260 00261 /** No longer used*/ 00262 static const sint4 WAYPOINT_PROX = 2; 00263 00264 /** this multiplied by the object max speed gives the distance 00265 ahead of the object on the path that the attractor will be set to*/ 00266 static const sint4 PATH_LOOK_AHEAD = 3; 00267 00268 //static const uint4 REPLAN_HARDCAP = 2; ///< Max number of replans for a task 00269 //static const sint4 REPLAN_TRIGGER = 5; ///< Number of occilation steps before a replan will be triggered 00270 //static const sint4 OCCILATION_TRIGGER = 15; ///< Number of occilation steps before a path movement failure will be passed 00271 00272 static const uint4 REPLAN_HARDCAP =2; ///< Max number of replans for a task 00273 static const sint4 REPLAN_TRIGGER = 5; ///< Number of occilation steps before a replan will be triggered 00274 static const sint4 OCCILATION_TRIGGER = 15; ///< Number of occilation steps before a path movement failure will be passed 00275 //GameStateModule &gms; 00276 00277 friend class SimpleTerrainWidget; 00278 friend class SimpleTerrainOverlay; 00279 friend class ST_Terrain::PFEngine; 00280 }; 00281 00282 } 00283 00284 REGISTER_TYPEOF(2601, SimpleTerrain::ST_ForceField::Obj2LocMap::iterator); 00285 REGISTER_TYPEOF(2602, SimpleTerrain::ST_ForceField::Obj2LocMap::const_iterator); 00286 REGISTER_TYPEOF(2603, SimpleTerrain::ST_ForceField::SegmentEndsMap::iterator); 00287 REGISTER_TYPEOF(2604, SimpleTerrain::ST_ForceField::SegmentEndsMap::const_iterator); 00288 REGISTER_TYPEOFS_TerrainBasicImp_ForEach(2605, SimpleTerrain::FF_Task); 00289 00290 #endif