NLS Engine  v0.1
The Next Logical Step in game engine design.
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines
ASTARMap.cpp
Go to the documentation of this file.
00001 
00012 #include "ASTARMap.h"
00013 
00014 // System Library Includes
00015 
00016 // Application Library Includes
00017 #include <EngineConfig.h>
00018 
00019 // Local Includes
00020 #include "../../sharedbase/ComponentInterface.h"
00021 #include "../../sharedbase/Entity.h"
00022 #include "../../sharedbase/MessageRouter.h"
00023 #include "../../sharedbase/Envelope.h"
00024 
00025 // Forward Declarations
00026 
00027 // Typedefs and data structures
00028 
00029 // Constants
00030 
00031 // Class methods
00032 namespace Physics {
00033 #define SUBSCRIBE_BASIC(msgid, handler)   {std::shared_ptr<Subscriber> handler_sptr(new Subscriber(boost::bind((&handler), this, _1))); this->msgrouter->Subscribe((msgid), handler_sptr);}
00034 #define UNSUBSCRIBE_BASIC(msgid, handler) {std::shared_ptr<Subscriber> handler_sptr(new Subscriber(boost::bind((&handler), this, _1))); this->c->Unsubscribe((msgid), handler_sptr);}
00035 #define SUBSCRIBE_DIRECTED(msgid, handler)   {std::shared_ptr<DirectedSubscriber> handler_sptr(new DirectedSubscriber(boost::bind((&handler), this, _1))); this->msgrouter->SubscribeDirected((msgid), handler_sptr);}
00036 #define UNSUBSCRIBE_DIRECTED(msgid, handler) {std::shared_ptr<DirectedSubscriber> handler_sptr(new DirectedSubscriber(boost::bind((&handler), this, _1))); this->msgrouter->UnsubscribeDirected((msgid), handler_sptr);}
00037 
00038   ASTARMap::ASTARMap( EntitySPTR owner, ModuleInterface* module, MessageRouter* msgrtr ) : ComponentInterface(owner, module), msgrouter(msgrtr) {
00039     SUBSCRIBE_DIRECTED(3103, ASTARMap::MouseClickonPoint);
00040     SUBSCRIBE_DIRECTED(3104, ASTARMap::UpdateIfPathBlocked);
00041   }
00042 
00043   ASTARMap::~ASTARMap() {
00044 
00045   }
00046 
00047   bool ASTARMap::LoadMapData( EnvelopeSPTR data ) {
00048     EnvelopeSPTR layersEnv(data.get()->GetDataEnvelopeSPTR(0)); // First envelope is layers
00049     for (unsigned int i = 0; i < layersEnv.get()->GetCount(); ++i) { // Loop through each layer
00050       EnvelopeSPTR layer(layersEnv.get()->GetDataEnvelopeSPTR(i)); // Get each layer
00051       for (unsigned int n = 0; n < layer.get()->GetCount(); n = n + 3) { // Loop through each tile
00052         unsigned int r = layer.get()->GetDataUInt(n);     // 0 - row
00053         unsigned int c = layer.get()->GetDataUInt(n + 1);   // 1 - column
00054         unsigned int tileid = layer.get()->GetDataUInt(n + 2);  // 2 - tileid
00055         if (tileid != 0) {
00056           Point cor;
00057           cor.x = c;
00058           cor.y = r;
00059           this->grid[cor] = STATE::FREE;
00060         }
00061       }
00062     }
00063     
00064     return true;
00065   }
00066   bool ASTARMap::LoadObjectData( EnvelopeSPTR data ) {
00067     for (unsigned int n = 0; n < data.get()->GetCount(); ++n) { // Loop through each object
00068       EnvelopeSPTR objectEnv(data.get()->GetDataEnvelopeSPTR(n)); // Get each layer
00069       std::string name = objectEnv.get()->GetDataString(0); // 0 - object name
00070       int x = objectEnv.get()->GetDataInt(1);         // 1 - x
00071       int y = objectEnv.get()->GetDataInt(2);         // 2 - y
00072       int width = objectEnv.get()->GetDataInt(3);       // 3 - width
00073       int height = objectEnv.get()->GetDataInt(4);      // 4 - height
00074 
00075       if (name == "start") {
00076         Point c;
00077         c.x = x / 32;
00078         c.y = y / 32;
00079         this->start = c;
00080       } else  if (name == "goal") {
00081         Point c;
00082         c.x = x / 32;
00083         c.y = y / 32;
00084         this->goal = c;
00085       }
00086     }
00087 
00088     return true;
00089   }
00090 
00091 
00092 
00093   EnvelopeSPTR ASTARMap::MouseClickonPoint( EnvelopeSPTR env ) {
00094     Point p;
00095     p.x = env->GetDataUInt(0);
00096     p.y = env->GetDataUInt(1);
00097     EntitySPTR obstacle(env->GetDataEntityP(2));
00098 
00099     EnvelopeSPTR retenv(new Envelope());
00100     retenv->msgid = 3103;
00101     if (GetState(p) == STATE::FREE) {
00102       SetState(p, STATE::SOLID);
00103       obstacle->location.x = (float)p.x * 32;
00104       obstacle->location.y = (float)p.y * 32;
00105 
00106       // Send an ACK about placing the obstacle
00107       retenv->AddData<bool>(true);
00108       //UpdatePath();
00109     }
00110     else {
00111       retenv->AddData<bool>(false);
00112     }
00113     return retenv;
00114   }
00115 
00116 
00117   STATE ASTARMap::GetState( Point c ) {
00118     return this->grid[c];
00119   }
00120 
00121   void ASTARMap::SetState(Point c, STATE n) {
00122     this->grid[c] = n;
00123   }
00124 
00125   void ASTARMap::RemoveState(Point c) {
00126     SetState(c, FREE);
00127   }
00128 
00129   STATEGrid::iterator ASTARMap::begin() {
00130     return this->grid.begin();
00131   }
00132 
00133   STATEGrid::iterator ASTARMap::end() {
00134     return this->grid.begin();
00135   }
00136 
00137   void ASTARMap::FindPath(Point player) {
00138     this->openList.clear(); // Clear the old lists
00139     this->closedList.clear(); // Clear the old lists
00140     navPoint playerNode = {0,0,0, player, nullptr};
00141     navPoint targetNode;
00142     this->openList[player] = playerNode;
00143 
00144     while (this->openList.size() > 0) {
00145       // Find the lowest f cost in the this->openList,
00146       // set it as our loc node,
00147       // and move it to the this->closedList
00148       NavGrid::iterator lowest = this->openList.begin();
00149       for (NavGrid::iterator itr = this->openList.begin(); itr != this->openList.end(); ++itr) {
00150         if (itr->second.f < lowest->second.f) {
00151           lowest = itr;
00152         }
00153       }
00154       if (lowest == this->openList.end()) {
00155         return;
00156       }
00157       this->closedList.insert(*lowest);
00158       navPoint* curNode = &this->closedList[lowest->second.pos]; // grab the pointer to the closed list item as the one in open list will be removed
00159       this->openList.erase(lowest);
00160       if ((curNode->pos.x == goal.x) && (curNode->pos.y == goal.y)) {
00161         targetNode = *curNode;
00162         // We have reach out goal so lets store the path
00163         navPoint* parent = &targetNode;
00164         
00165         // Store the points in a container for reversing them into the point list
00166         std::vector<Point> reverseVector;
00167         while (parent != nullptr) {
00168           reverseVector.push_back(parent->pos);
00169           parent = parent->parent;
00170         }
00171 
00172         // Now we do the reversing
00173         for (std::vector<Point>::reverse_iterator itr = reverseVector.rbegin(); itr != reverseVector.rend(); ++itr) {
00174           this->points.AddPoint((*itr));
00175         }
00176 
00177         this->owner->properties.SetProperty("pointlist", &this->points);
00178         return;
00179       }
00180 
00181 
00182       // Get the surrounding nodes 
00183       navPoint temp;
00184       int cost;
00185       Point loc = player;
00186       for (int x = -1; x < 2; ++x) {
00187         for (int y = -1; y < 2; ++y) {
00188 
00189           // Diagonal check. Remove to allow diagonal movement.
00190           if ((x != 0) && (y != 0)) {
00191             continue;
00192           }
00193           if ((x == 0) && (y == 0)) { // We don't need to check the current node
00194             continue;
00195           } else if ((x == 0) || (y == 0)) { // Straight movement
00196             cost = 10;
00197           } else { // Diagonal
00198             cost = 14;
00199           }
00200           loc.x = curNode->pos.x + x;
00201           loc.y = curNode->pos.y + y;
00202           if (this->grid.find(loc) != this->grid.end()) { // Node at coords exists
00203             if ((this->openList.find(loc) == this->openList.end()) && (this->closedList.find(loc) == this->closedList.end())) { // Not on open or closed list
00204               if (this->grid[loc] == FREE) {
00205                 temp.g = cost + curNode->g;
00206                 temp.h = cost * (abs(curNode->pos.x - this->goal.x) + abs(curNode->pos.y - this->goal.y));
00207                 temp.f = (int)((float)temp.g + temp.h);
00208                 temp.pos = loc;
00209                 temp.parent = curNode;
00210                 this->openList[loc] = temp;
00211               }
00212             } else if (this->openList.find(loc) != this->openList.end()) {
00213               if (this->openList[loc].g > (curNode->g + cost)) {
00214                 this->openList[loc].parent = curNode;
00215                 this->openList[loc].g = (curNode->g + cost);
00216                 this->openList[loc].f = (int)((float)this->openList[loc].g + this->openList[loc].h);
00217               }
00218             }
00219           }
00220         }
00221       }
00222     }
00223   }
00224 
00225   void ASTARMap::UpdatePath() {
00226     // Do some housework to find the new path
00227     Point curr = this->points.CurrentPoint(); // Save the current point
00228     this->points.Clear(); // Clear the points
00229     FindPath(curr); // Find the new path starting at curr
00230     this->points.GotoPoint(curr); // Go back to the current point in the list
00231   }
00232 
00233 
00234   void ASTARMap::SetGoal(int x, int y) {
00235     this->goal.x = x;
00236     this->goal.y = y;
00237   }
00238 
00239   PointList* ASTARMap::GetPoints() {
00240     return &this->points;
00241   }
00242 
00243   EnvelopeSPTR ASTARMap::UpdateIfPathBlocked(EnvelopeSPTR env) {
00244     EnvelopeSPTR retenv(new Envelope());
00245     retenv->msgid = 3104;
00246 
00247     Point p = this->points.PeekNextPoint();
00248     if (GetState(p) == STATE::SOLID) {
00249       UpdatePath();
00250 
00251       retenv->AddData<bool>(true);
00252     }
00253 
00254     retenv->AddData<bool>(false);
00255 
00256     return retenv;
00257   }
00258 
00259 }