From 5fc7103425732403a0b8e6f092430a2996138488 Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 20:31:47 +0000 Subject: [PATCH 01/15] First attempt at pathfinding using boost::graph --- apps/openmw/mwmechanics/aitravel.cpp | 193 ++++++++++++++++++++++++++- apps/openmw/mwmechanics/aitravel.hpp | 7 +- 2 files changed, 196 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 897dd17480..b5e67e449b 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,8 +1,19 @@ #include "aitravel.hpp" #include +#include "character.hpp" + +#include "../mwworld/class.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "movement.hpp" + +#include +#include +#include "boost/tuple/tuple.hpp" + MWMechanics::AiTravel::AiTravel(float x, float y, float z) -: mX(x),mY(y),mZ(z) +: mX(x),mY(y),mZ(z),isPathConstructed(false) { } @@ -11,10 +22,186 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } +float distance(ESM::Pathgrid::Point point,float x,float y,float z) +{ + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); +} + +float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) +{ + return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); +} + +int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) +{ + if(!grid) throw std::exception("NULL PathGrid!"); + if(grid->mPoints.empty()) throw std::exception("empty PathGrid!"); + + float m = distance(grid->mPoints[0],x,y,z); + int i0 = 0; + + for(int i=1; imPoints.size();i++) + { + if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); + i0 = i; + } + } + + return i0; +} + +float sgn(float a) +{ + if(a>0) return 1.; + else return -1.; +} + +float getZAngle(float dX,float dY) +{ + float h = sqrt(dX*dX+dY*dY); + return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); +} + +struct Edge +{ + float distance; +}; + +typedef boost::adjacency_list,boost::property > PathGridGraph; +typedef boost::property_map::type WeightMap; +typedef PathGridGraph::vertex_descriptor PointID; +typedef PathGridGraph::edge_descriptor PointConnectionID; + +struct found_path {}; + +class goalVisited : public boost::default_astar_visitor +{ +public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } +private: + PointID mGoal; +}; + +class DistanceHeuristic : public boost::astar_heuristic +{ +public: + DistanceHeuristic(const PathGridGraph & l, PointID goal) + : mGraph(l), mGoal(goal) {} + + float operator()(PointID u) + { + const ESM::Pathgrid::Point & U = mGraph[u]; + const ESM::Pathgrid::Point & V = mGraph[mGoal]; + float dx = U.mX - V.mX; + float dy = U.mY - V.mY; + float dz = U.mZ - V.mZ; + return sqrt(dx * dx + dy * dy + dz * dz); + } +private: + const PathGridGraph & mGraph; + PointID mGoal; +}; + +std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::vector p(boost::num_vertices(graph)); + std::vector d(boost::num_vertices(graph)); + std::list shortest_path; + + try { + boost::astar_search + ( + graph, + start, + DistanceHeuristic(graph,end), + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) + ); + + } catch(found_path fg) { + for(PointID v = end;; v = p[v]) { + shortest_path.push_front(graph[v]); + if(p[v] == v) + break; + } + } + return shortest_path; +} + +PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid) +{ + PathGridGraph graph; + + for(int i = 0;imPoints.size();i++) + { + PointID pID = boost::add_vertex(graph); + graph[pID] = pathgrid->mPoints[i]; + } + + for(int i = 0;imEdges.size();i++) + { + PointID u = pathgrid->mEdges[i].mV0; + PointID v = pathgrid->mEdges[i].mV1; + + PointConnectionID edge; + bool done; + boost::tie(edge,done) = boost::add_edge(u,v,graph); + WeightMap weightmap = boost::get(boost::edge_weight, graph); + weightmap[edge] = distance(graph[u],graph[v]); + + } + + return graph; +} + bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { - std::cout << "AiTravel completed.\n"; - return true; + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + ESM::Position pos = actor.getRefData().getPosition(); + + if(!isPathConstructed) + { + int start = getClosestPoint(pathgrid,pos.pos[0],pos.pos[1],pos.pos[2]); + int end = getClosestPoint(pathgrid,mX,mY,mZ); + + PathGridGraph graph = buildGraph(pathgrid); + + mPath = getPath(start,end,graph); + isPathConstructed = true; + } + if(mPath.empty()) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + if(distance(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) + { + mPath.pop_front(); + if(mPath.empty()) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + nextPoint = *mPath.begin(); + } + + float dX = nextPoint.mX - pos.pos[0]; + float dY = nextPoint.mY - pos.pos[1]; + + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + return false; + //return true; } int MWMechanics::AiTravel::getTypeId() const diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 1c6abbf279..a596f4c85d 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -1,7 +1,9 @@ #ifndef GAME_MWMECHANICS_AITRAVEL_H #define GAME_MWMECHANICS_AITRAVEL_H -#include "aipackage.hpp" +#include "aipackage.hpp" +#include "components\esm\loadpgrd.hpp" +#include namespace MWMechanics { @@ -21,6 +23,9 @@ namespace MWMechanics float mY; float mZ; + bool isPathConstructed; + std::list mPath; + }; } From 01908dbcc27f2202e13dce90fe24f77dc268c97c Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 21:17:33 +0000 Subject: [PATCH 02/15] little improvement --- apps/openmw/mwmechanics/aitravel.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b5e67e449b..9d41a080c7 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -22,6 +22,11 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } +float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) +{ + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); +} + float distance(ESM::Pathgrid::Point point,float x,float y,float z) { return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); @@ -64,11 +69,6 @@ float getZAngle(float dX,float dY) return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); } -struct Edge -{ - float distance; -}; - typedef boost::adjacency_list,boost::property > PathGridGraph; typedef boost::property_map::type WeightMap; @@ -176,6 +176,11 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) PathGridGraph graph = buildGraph(pathgrid); mPath = getPath(start,end,graph); + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + mPath.push_back(dest); isPathConstructed = true; } if(mPath.empty()) @@ -184,7 +189,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) return true; } ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distance(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) + if(distanceZCorrected(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) { mPath.pop_front(); if(mPath.empty()) From bbc4c23f7e184782eec35bface3e0d10df182dd1 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 10 Mar 2013 15:07:22 +0000 Subject: [PATCH 03/15] AITravel now works correctly on exterior cells. As long as NPC don't try to leave cell, it's ok. --- apps/openmw/mwmechanics/aitravel.cpp | 31 ++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 9d41a080c7..09b0efad9c 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -53,7 +53,7 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) i0 = i; } } - + std::cout << "distance:: " << m << "\n"; return i0; } @@ -135,14 +135,16 @@ std::list getPath(PointID start,PointID end,PathGridGraph return shortest_path; } -PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid) +PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; for(int i = 0;imPoints.size();i++) { PointID pID = boost::add_vertex(graph); - graph[pID] = pathgrid->mPoints[i]; + graph[pID].mX = pathgrid->mPoints[i].mX + xCell; + graph[pID].mY = pathgrid->mPoints[i].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[i].mZ; } for(int i = 0;imEdges.size();i++) @@ -165,17 +167,26 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - - ESM::Position pos = actor.getRefData().getPosition(); + ESM::Position pos = actor.getRefData().getPosition(); + //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } - PathGridGraph graph = buildGraph(pathgrid); + int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); + int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); + + PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); mPath = getPath(start,end,graph); + if(mPath.empty()) std::cout << "graph doesn't find any way..."; ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; @@ -185,6 +196,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(mPath.empty()) { + std::cout << "pathc empty"; MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } @@ -195,6 +207,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) if(mPath.empty()) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + std::cout << "emptypath!"; return true; } nextPoint = *mPath.begin(); @@ -205,8 +218,8 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + return false; - //return true; } int MWMechanics::AiTravel::getTypeId() const From f943580138209a27497e0613ab6914f5194a3589 Mon Sep 17 00:00:00 2001 From: gus Date: Tue, 12 Mar 2013 17:44:22 +0000 Subject: [PATCH 04/15] Somehow manages to get from one cell to another, but this looks wrong... And I don't know how morrowind do it, because aitravel is completly buggy --- apps/openmw/mwmechanics/aitravel.cpp | 6 +++++- apps/openmw/mwmechanics/aitravel.hpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 09b0efad9c..3c2e29743a 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -169,9 +169,13 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + if(cellChange) std::cout << "cellChanged! \n"; //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; float yCell = 0; if (actor.getCell()->mCell->isExterior()) diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index a596f4c85d..3d220cb7e3 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -23,6 +23,9 @@ namespace MWMechanics float mY; float mZ; + int cellX; + int cellY; + bool isPathConstructed; std::list mPath; From 80804fac351fedcde4735753c7ae2db461a80628 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 14 Mar 2013 17:16:37 +0000 Subject: [PATCH 05/15] check if the NPC is close from a non loaded cell. If yes, AITravel is simply ended. --- apps/openmw/mwmechanics/aitravel.cpp | 31 +++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 3c2e29743a..57b9f66dde 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -7,6 +7,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "movement.hpp" +#include "../mwworld/player.hpp" #include #include @@ -167,13 +168,35 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - if(cellChange) std::cout << "cellChanged! \n"; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; @@ -190,7 +213,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); mPath = getPath(start,end,graph); - if(mPath.empty()) std::cout << "graph doesn't find any way..."; + ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; @@ -200,7 +223,6 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(mPath.empty()) { - std::cout << "pathc empty"; MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } @@ -211,7 +233,6 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) if(mPath.empty()) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - std::cout << "emptypath!"; return true; } nextPoint = *mPath.begin(); From 9efb073617cf41f66f774c9453574594fbcf2870 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 14 Mar 2013 18:05:00 +0000 Subject: [PATCH 06/15] clean up + correct a bug --- apps/openmw/mwmechanics/aitravel.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 57b9f66dde..94f6fd8928 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -40,8 +40,8 @@ float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) { - if(!grid) throw std::exception("NULL PathGrid!"); - if(grid->mPoints.empty()) throw std::exception("empty PathGrid!"); + if(!grid) return -1; + if(grid->mPoints.empty()) return -1; float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; @@ -54,7 +54,6 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) i0 = i; } } - std::cout << "distance:: " << m << "\n"; return i0; } @@ -175,7 +174,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) { - int sideX = sgn(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX); + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) { @@ -185,7 +184,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) { - int sideY = sgn(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY); + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) { @@ -193,10 +192,9 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) return true; } } - //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; @@ -210,9 +208,11 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); - PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); - - mPath = getPath(start,end,graph); + if(start != -1 && end != -1) + { + PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); + mPath = getPath(start,end,graph); + } ESM::Pathgrid::Point dest; dest.mX = mX; From efe6a3ebeec495a213a75ed3c072d9d2eb1c8c95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Mar 2013 18:01:01 +0100 Subject: [PATCH 07/15] Fix compile error & warnings --- apps/openmw/mwmechanics/aitravel.cpp | 6 +-- apps/openmw/mwmechanics/aitravel.hpp | 60 ++++++++++++++-------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 94f6fd8928..2c5260a625 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -46,7 +46,7 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; - for(int i=1; imPoints.size();i++) + for(unsigned int i=1; imPoints.size();++i) { if(distance(grid->mPoints[i],x,y,z)mPoints.size();i++) + for(unsigned int i = 0;imPoints.size();++i) { PointID pID = boost::add_vertex(graph); graph[pID].mX = pathgrid->mPoints[i].mX + xCell; @@ -147,7 +147,7 @@ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCe graph[pID].mZ = pathgrid->mPoints[i].mZ; } - for(int i = 0;imEdges.size();i++) + for(unsigned int i = 0;imEdges.size();++i) { PointID u = pathgrid->mEdges[i].mV0; PointID v = pathgrid->mEdges[i].mV1; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 3d220cb7e3..ef2359ba91 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -1,35 +1,35 @@ #ifndef GAME_MWMECHANICS_AITRAVEL_H #define GAME_MWMECHANICS_AITRAVEL_H - -#include "aipackage.hpp" -#include "components\esm\loadpgrd.hpp" -#include - -namespace MWMechanics -{ - class AiTravel : public AiPackage - { - public: - AiTravel(float x, float y, float z); - virtual AiTravel *clone() const; - - virtual bool execute (const MWWorld::Ptr& actor); - ///< \return Package completed? - - virtual int getTypeId() const; - - private: - float mX; - float mY; - float mZ; - - int cellX; - int cellY; - - bool isPathConstructed; - std::list mPath; - - }; + +#include "aipackage.hpp" +#include +#include + +namespace MWMechanics +{ + class AiTravel : public AiPackage + { + public: + AiTravel(float x, float y, float z); + virtual AiTravel *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + + virtual int getTypeId() const; + + private: + float mX; + float mY; + float mZ; + + int cellX; + int cellY; + + bool isPathConstructed; + std::list mPath; + + }; } #endif From 63424ade56fd9c7da96446d666e4c4e774f1c4c0 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 31 Mar 2013 17:30:03 +0000 Subject: [PATCH 08/15] refactoring --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aitravel.cpp | 177 ++------------------- apps/openmw/mwmechanics/aitravel.hpp | 8 +- apps/openmw/mwmechanics/pathfinding.cpp | 201 ++++++++++++++++++++++++ apps/openmw/mwmechanics/pathfinding.hpp | 26 +++ 5 files changed, 245 insertions(+), 169 deletions(-) create mode 100644 apps/openmw/mwmechanics/pathfinding.cpp create mode 100644 apps/openmw/mwmechanics/pathfinding.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 41599b35db..d29e0ff2e7 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -65,7 +65,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate repair + aiescort aiactivate repair pathfinding ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 2c5260a625..df6a38bb03 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -14,7 +14,7 @@ #include "boost/tuple/tuple.hpp" MWMechanics::AiTravel::AiTravel(float x, float y, float z) -: mX(x),mY(y),mZ(z),isPathConstructed(false) + : mX(x),mY(y),mZ(z),mPathFinder() { } @@ -23,151 +23,17 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } -float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) -{ - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); -} - -float distance(ESM::Pathgrid::Point point,float x,float y,float z) -{ - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); -} - -float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) -{ - return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); -} - -int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) -{ - if(!grid) return -1; - if(grid->mPoints.empty()) return -1; - - float m = distance(grid->mPoints[0],x,y,z); - int i0 = 0; - - for(unsigned int i=1; imPoints.size();++i) - { - if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); - i0 = i; - } - } - return i0; -} - float sgn(float a) { if(a>0) return 1.; else return -1.; } -float getZAngle(float dX,float dY) -{ - float h = sqrt(dX*dX+dY*dY); - return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); -} - -typedef boost::adjacency_list,boost::property > PathGridGraph; -typedef boost::property_map::type WeightMap; -typedef PathGridGraph::vertex_descriptor PointID; -typedef PathGridGraph::edge_descriptor PointConnectionID; - -struct found_path {}; - -class goalVisited : public boost::default_astar_visitor -{ -public: - goalVisited(PointID goal) : mGoal(goal) {} - - void examine_vertex(PointID u, const PathGridGraph g) - { - if(u == mGoal) - throw found_path(); - } -private: - PointID mGoal; -}; - -class DistanceHeuristic : public boost::astar_heuristic -{ -public: - DistanceHeuristic(const PathGridGraph & l, PointID goal) - : mGraph(l), mGoal(goal) {} - - float operator()(PointID u) - { - const ESM::Pathgrid::Point & U = mGraph[u]; - const ESM::Pathgrid::Point & V = mGraph[mGoal]; - float dx = U.mX - V.mX; - float dy = U.mY - V.mY; - float dz = U.mZ - V.mZ; - return sqrt(dx * dx + dy * dy + dz * dz); - } -private: - const PathGridGraph & mGraph; - PointID mGoal; -}; - -std::list getPath(PointID start,PointID end,PathGridGraph graph){ - std::vector p(boost::num_vertices(graph)); - std::vector d(boost::num_vertices(graph)); - std::list shortest_path; - - try { - boost::astar_search - ( - graph, - start, - DistanceHeuristic(graph,end), - boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) - ); - - } catch(found_path fg) { - for(PointID v = end;; v = p[v]) { - shortest_path.push_front(graph[v]); - if(p[v] == v) - break; - } - } - return shortest_path; -} - -PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) -{ - PathGridGraph graph; - - for(unsigned int i = 0;imPoints.size();++i) - { - PointID pID = boost::add_vertex(graph); - graph[pID].mX = pathgrid->mPoints[i].mX + xCell; - graph[pID].mY = pathgrid->mPoints[i].mY + yCell; - graph[pID].mZ = pathgrid->mPoints[i].mZ; - } - - for(unsigned int i = 0;imEdges.size();++i) - { - PointID u = pathgrid->mEdges[i].mV0; - PointID v = pathgrid->mEdges[i].mV1; - - PointConnectionID edge; - bool done; - boost::tie(edge,done) = boost::add_edge(u,v,graph); - WeightMap weightmap = boost::get(boost::edge_weight, graph); - weightmap[edge] = distance(graph[u],graph[v]); - - } - - return graph; -} - bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; @@ -193,7 +59,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } } - if(!isPathConstructed ||cellChange) + if(!mPathFinder.mIsPathConstructed ||cellChange) { cellX = actor.getCell()->mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; @@ -205,43 +71,26 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; } - int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); - int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); - - if(start != -1 && end != -1) - { - PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); - mPath = getPath(start,end,graph); - } - ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; dest.mZ = mZ; - mPath.push_back(dest); - isPathConstructed = true; + + ESM::Pathgrid::Point start; + dest.mX = pos.pos[0]; + dest.mY = pos.pos[1]; + dest.mZ = pos.pos[2]; + + mPathFinder.findPath(start,dest,pathgrid,xCell,yCell); } - if(mPath.empty()) + if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } - ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distanceZCorrected(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) - { - mPath.pop_front(); - if(mPath.empty()) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } - nextPoint = *mPath.begin(); - } - - float dX = nextPoint.mX - pos.pos[0]; - float dY = nextPoint.mY - pos.pos[1]; - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; return false; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index ef2359ba91..52b41850f1 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -2,8 +2,7 @@ #define GAME_MWMECHANICS_AITRAVEL_H #include "aipackage.hpp" -#include -#include +#include "pathfinding.hpp" namespace MWMechanics { @@ -26,8 +25,9 @@ namespace MWMechanics int cellX; int cellY; - bool isPathConstructed; - std::list mPath; + //bool isPathConstructed; + //std::list mPath; + PathFinder mPathFinder; }; } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp new file mode 100644 index 0000000000..9b76082b48 --- /dev/null +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -0,0 +1,201 @@ +#include "pathfinding.hpp" +#include +#include +#include "boost/tuple/tuple.hpp" +#include "OgreMath.h" + +namespace MWMechanics +{ + + //helpers functions + float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) + { + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); + } + + float distance(ESM::Pathgrid::Point point,float x,float y,float z) + { + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); + } + + float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) + { + return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); + } + + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } + + int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) + { + if(!grid) return -1; + if(grid->mPoints.empty()) return -1; + + float m = distance(grid->mPoints[0],x,y,z); + int i0 = 0; + + for(unsigned int i=1; imPoints.size();++i) + { + if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); + i0 = i; + } + } + return i0; + } + + typedef boost::adjacency_list,boost::property > PathGridGraph; + typedef boost::property_map::type WeightMap; + typedef PathGridGraph::vertex_descriptor PointID; + typedef PathGridGraph::edge_descriptor PointConnectionID; + + struct found_path {}; + + class goalVisited : public boost::default_astar_visitor + { + public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } + private: + PointID mGoal; + }; + + class DistanceHeuristic : public boost::astar_heuristic + { + public: + DistanceHeuristic(const PathGridGraph & l, PointID goal) + : mGraph(l), mGoal(goal) {} + + float operator()(PointID u) + { + const ESM::Pathgrid::Point & U = mGraph[u]; + const ESM::Pathgrid::Point & V = mGraph[mGoal]; + float dx = U.mX - V.mX; + float dy = U.mY - V.mY; + float dz = U.mZ - V.mZ; + return sqrt(dx * dx + dy * dy + dz * dz); + } + private: + const PathGridGraph & mGraph; + PointID mGoal; + }; + + PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) + { + PathGridGraph graph; + + for(unsigned int i = 0;imPoints.size();++i) + { + PointID pID = boost::add_vertex(graph); + graph[pID].mX = pathgrid->mPoints[i].mX + xCell; + graph[pID].mY = pathgrid->mPoints[i].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[i].mZ; + } + + for(unsigned int i = 0;imEdges.size();++i) + { + PointID u = pathgrid->mEdges[i].mV0; + PointID v = pathgrid->mEdges[i].mV1; + + PointConnectionID edge; + bool done; + boost::tie(edge,done) = boost::add_edge(u,v,graph); + WeightMap weightmap = boost::get(boost::edge_weight, graph); + weightmap[edge] = distance(graph[u],graph[v]); + + } + + return graph; + } + + std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::vector p(boost::num_vertices(graph)); + std::vector d(boost::num_vertices(graph)); + std::list shortest_path; + + try { + boost::astar_search + ( + graph, + start, + DistanceHeuristic(graph,end), + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) + ); + + } catch(found_path fg) { + for(PointID v = end;; v = p[v]) { + shortest_path.push_front(graph[v]); + if(p[v] == v) + break; + } + } + return shortest_path; + } + + //end of helpers functions + + PathFinder::PathFinder() + { + mIsPathConstructed = false; + } + + std::list PathFinder::findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid,float xCell,float yCell) + { + int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); + int end = getClosestPoint(pathGrid,endPoint.mX - xCell,endPoint.mY - yCell,endPoint.mZ); + + if(start != -1 && end != -1) + { + PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); + mPath = getPath(start,end,graph); + } + + mPath.push_back(endPoint); + mIsPathConstructed = true; + + return mPath; + } + + float PathFinder::getZAngleToNext(float x,float y,float z) + { + if(mPath.empty()) + { + return 0;/// shouldn't happen! + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + float dX = nextPoint.mX - x; + float dY = nextPoint.mY - y; + float h = sqrt(dX*dX+dY*dY); + return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); + } + + bool PathFinder::checkIfNextPointReached(float x,float y,float z) + { + if(mPath.empty()) + { + return true; + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + if(distanceZCorrected(nextPoint,x,y,z) < 20) + { + mPath.pop_front(); + if(mPath.empty()) + { + return true; + } + nextPoint = *mPath.begin(); + } + return false; + } +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp new file mode 100644 index 0000000000..200b191259 --- /dev/null +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -0,0 +1,26 @@ +#ifndef GAME_MWMECHANICS_PATHFINDING_H +#define GAME_MWMECHANICS_PATHFINDING_H + +#include +#include + +namespace MWMechanics +{ + class PathFinder + { + public: + PathFinder(); + + std::list findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); + + bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. + float getZAngleToNext(float x,float y,float z); + + + std::list mPath; + bool mIsPathConstructed; + }; +} + +#endif \ No newline at end of file From 47cc945ef47e646e29a2f49d997ec8b0ba274fd4 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 12:38:13 +0000 Subject: [PATCH 09/15] more refactoring --- apps/openmw/mwmechanics/aitravel.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 17 ++++++++++++----- apps/openmw/mwmechanics/pathfinding.hpp | 5 ++++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index df6a38bb03..b1a4cd0a69 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -59,7 +59,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } } - if(!mPathFinder.mIsPathConstructed ||cellChange) + if(!mPathFinder.isPathConstructed() ||cellChange) { cellX = actor.getCell()->mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; @@ -81,7 +81,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) dest.mY = pos.pos[1]; dest.mZ = pos.pos[2]; - mPathFinder.findPath(start,dest,pathgrid,xCell,yCell); + mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); } if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9b76082b48..fdac50ddac 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -118,7 +118,7 @@ namespace MWMechanics return graph; } - std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::list findPath(PointID start,PointID end,PathGridGraph graph){ std::vector p(boost::num_vertices(graph)); std::vector d(boost::num_vertices(graph)); std::list shortest_path; @@ -149,7 +149,7 @@ namespace MWMechanics mIsPathConstructed = false; } - std::list PathFinder::findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + void PathFinder::buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell,float yCell) { int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); @@ -158,13 +158,11 @@ namespace MWMechanics if(start != -1 && end != -1) { PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); - mPath = getPath(start,end,graph); + mPath = findPath(start,end,graph); } mPath.push_back(endPoint); mIsPathConstructed = true; - - return mPath; } float PathFinder::getZAngleToNext(float x,float y,float z) @@ -198,4 +196,13 @@ namespace MWMechanics } return false; } + + std::list PathFinder::getPath() + { + return mPath; + } + bool PathFinder::isPathConstructed() + { + return mIsPathConstructed; + } } \ No newline at end of file diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 200b191259..b1bbab37ab 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -11,13 +11,16 @@ namespace MWMechanics public: PathFinder(); - std::list findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. float getZAngleToNext(float x,float y,float z); + std::list getPath(); + bool isPathConstructed(); + private: std::list mPath; bool mIsPathConstructed; }; From 2be9405c96056fc6a12b2c5d4d048e0d74ca3d6d Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 15:44:08 +0000 Subject: [PATCH 10/15] the sgn function is no longer in the global namespace --- apps/openmw/mwmechanics/aitravel.cpp | 157 ++++++++++++++------------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b1a4cd0a69..4aca5f3d49 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,92 +13,95 @@ #include #include "boost/tuple/tuple.hpp" -MWMechanics::AiTravel::AiTravel(float x, float y, float z) - : mX(x),mY(y),mZ(z),mPathFinder() +namespace MWMechanics { -} -MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const -{ - return new AiTravel(*this); -} - -float sgn(float a) -{ - if(a>0) return 1.; - else return -1.; -} - -bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) -{ - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - - ESM::Position pos = actor.getRefData().getPosition(); - bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + AiTravel::AiTravel(float x, float y, float z) + : mX(x),mY(y),mZ(z),mPathFinder() { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + } + + AiTravel * AiTravel::clone() const + { + return new AiTravel(*this); + } + + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } + + bool AiTravel::execute (const MWWorld::Ptr& actor) + { + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + + if(!mPathFinder.isPathConstructed() ||cellChange) + { + cellX = actor.getCell()->mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; + float xCell = 0; + float yCell = 0; + if (actor.getCell()->mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } + + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + + ESM::Pathgrid::Point start; + dest.mX = pos.pos[0]; + dest.mY = pos.pos[1]; + dest.mZ = pos.pos[2]; + + mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); + } + if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } + + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + + return false; } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + + int AiTravel::getTypeId() const { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } + return 1; } - if(!mPathFinder.isPathConstructed() ||cellChange) - { - cellX = actor.getCell()->mCell->mData.mX; - cellY = actor.getCell()->mCell->mData.mY; - float xCell = 0; - float yCell = 0; - if (actor.getCell()->mCell->isExterior()) - { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; - } - - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; - - ESM::Pathgrid::Point start; - dest.mX = pos.pos[0]; - dest.mY = pos.pos[1]; - dest.mZ = pos.pos[2]; - - mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); - } - if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } - - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; - - return false; } - -int MWMechanics::AiTravel::getTypeId() const -{ - return 1; -} - - From 20af7d89a2550a9873dd0ab03d5240af25f3b0f7 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 17:30:40 +0000 Subject: [PATCH 11/15] post master-merge fixes. Looks a little odd. --- apps/openmw/mwmechanics/aitravel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 4aca5f3d49..dd769f91c4 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -47,7 +47,7 @@ namespace MWMechanics //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } } @@ -57,7 +57,7 @@ namespace MWMechanics //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } } @@ -88,13 +88,13 @@ namespace MWMechanics } if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; return false; } From 6a33170ca244db400d49651597ce3cc80d753723 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 17:44:06 +0000 Subject: [PATCH 12/15] More bugfix, but I don't like this one. --- apps/openmw/mwmechanics/aitravel.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index dd769f91c4..25efe8fff0 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -26,7 +26,7 @@ namespace MWMechanics return new AiTravel(*this); } - float sgn(float a) + static float sgn(float a) { if(a>0) return 1.; else return -1.; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index fdac50ddac..1d98674ef5 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -23,7 +23,7 @@ namespace MWMechanics return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); } - float sgn(float a) + static float sgn(float a) { if(a>0) return 1.; else return -1.; From 6934b20abd7c09ece9469f2be330512d91895982 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 17:57:58 +0100 Subject: [PATCH 13/15] actors are now updates every frame. This should not be the case, but this is a quickfix for AI. --- apps/openmw/mwmechanics/actors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 89671ee086..82e46ea463 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -210,7 +210,7 @@ namespace MWMechanics { mDuration += duration; - if (mDuration>=0.25) + //if (mDuration>=0.25) { float totalDuration = mDuration; mDuration = 0; From 0a187e56aa8331624163789059dee3ca85a25095 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 17:58:11 +0100 Subject: [PATCH 14/15] bugfix --- apps/openmw/mwmechanics/aitravel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 25efe8fff0..65d43749bc 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -80,9 +80,9 @@ namespace MWMechanics dest.mZ = mZ; ESM::Pathgrid::Point start; - dest.mX = pos.pos[0]; - dest.mY = pos.pos[1]; - dest.mZ = pos.pos[2]; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); } From 905cff2a9456406f1be91ca311ab219980e9840c Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 18:02:12 +0100 Subject: [PATCH 15/15] anonymous namespace --- apps/openmw/mwmechanics/aitravel.cpp | 15 +++++++++------ apps/openmw/mwmechanics/pathfinding.cpp | 8 +++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 65d43749bc..13ae2a592e 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,6 +13,15 @@ #include #include "boost/tuple/tuple.hpp" +namespace +{ + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } +} + namespace MWMechanics { @@ -26,12 +35,6 @@ namespace MWMechanics return new AiTravel(*this); } - static float sgn(float a) - { - if(a>0) return 1.; - else return -1.; - } - bool AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 1d98674ef5..7c22e54701 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -4,10 +4,9 @@ #include "boost/tuple/tuple.hpp" #include "OgreMath.h" -namespace MWMechanics +namespace { - - //helpers functions + //helpers functions float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) { return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); @@ -89,7 +88,10 @@ namespace MWMechanics const PathGridGraph & mGraph; PointID mGoal; }; +} +namespace MWMechanics +{ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph;