diff --git a/navMesh/walk/NavMeshWalkUnblockable.h b/navMesh/walk/NavMeshWalkUnblockable.h new file mode 100644 index 0000000..49de355 --- /dev/null +++ b/navMesh/walk/NavMeshWalkUnblockable.h @@ -0,0 +1,159 @@ +#ifndef NAVMESHWALKUNBLOCKABLE_H +#define NAVMESHWALKUNBLOCKABLE_H + +#include +#include +#include + +#include "../NavMesh.h" +#include "../NavMeshLocation.h" +#include "../../geo/Heading.h" + +#include "NavMeshSub.h" +#include "NavMeshWalkParams.h" +#include "NavMeshWalkEval.h" + +namespace NM { + + /** + * simple walker that gives particles a slight chance to walk + * thru walls depending upon a given delta + */ + template class NavMeshWalkUnblockable { + + private: + + const NavMesh& mesh; + + std::vector*> evals; + Distribution::Uniform distNewOne = Distribution::Uniform(0,1); + + int hits = 0; + int misses = 0; + int walls = 0; + int noTria = 0; + + public: + + + /** single result */ + struct ResultEntry { + NavMeshLocation location; + Heading heading; + double probability; + ResultEntry() : heading(0) {;} + }; + + /** list of results */ + using ResultList = std::vector; + + public: + + /** ctor */ + NavMeshWalkUnblockable(const NavMesh& mesh) : mesh(mesh) { + + } + + /** add a new evaluator to the walker */ + void addEvaluator(NavMeshWalkEval* eval) { + this->evals.push_back(eval); + } + + ResultEntry getOne(const NavMeshWalkParams& params, const double delta) { + + // sanity checks + params.check(); + + ResultEntry re; + + // to-be-walked distance; + const float toBeWalkedDist = params.getToBeWalkedDistance(); + const float toBeWalkedDistSafe = 0.75 + toBeWalkedDist * 1.1; + + // construct reachable region + NavMeshSub reachable(params.start, toBeWalkedDistSafe); + + // get the to-be-reached destination's position (using start+distance+heading) + const Point2 dir = params.heading.asVector(); + const Point2 dst = params.start.pos.xy() + (dir * toBeWalkedDist); + + //3D Destination for finding the location within the complete mesh + //TODO: better solution for z? seems to be a hack on stairs + const Point2 dsttt = params.start.pos.xy() + (dir * (toBeWalkedDistSafe + 0.6)); + const Point3 dst3D = Point3(dsttt.x, dsttt.y, params.start.pos.z); + + const Tria* dstTria = reachable.getContainingTriangle(dst); + + // is above destination reachable? + if (dstTria) { + + re.heading = params.heading; // heading was OK -> keep + re.location.pos = dstTria->toPoint3(dst); // new destination position + re.location.tria = dstTria; // new destination triangle + ++hits; + } + //give the particle a slight chance to walk thru the wall + else if(distNewOne.draw() < delta){ + + try{ + //check if there is a triangle for dst behind the wall + const Tria* dstTriaBehindWall = mesh.getLocation(dst3D).tria; + re.heading = params.heading; + re.location.pos = dst3D; + re.location.tria = dstTriaBehindWall; + ++walls; + ++misses; + + } catch (...) { + NavMeshRandom rnd = reachable.getRandom(); // random-helper + re.location = rnd.draw(); // get a random destination + re.heading = Heading(params.start.pos.xy(), re.location.pos.xy()); // update the heading + ++noTria; + ++misses; + } + + ++misses; + } else { + + NavMeshRandom rnd = reachable.getRandom(); // random-helper + re.location = rnd.draw(); // get a random destianation + re.heading = Heading(params.start.pos.xy(), re.location.pos.xy()); // update the heading + + ++misses; + } + + const int total = (hits + misses); + const int totalWalls = (walls + noTria); + if (total % 10000 == 0) { + std::cout << "hits: " << (hits*100/total) << "%" << std::endl; + std::cout << "walls: " << (walls*100/totalWalls) << "%" << std::endl; + } + + // calculate probability + const NavMeshPotentialWalk pwalk(params, re.location); + re.probability = 1.0; + for (const NavMeshWalkEval* eval : evals) { + const double p1 = eval->getProbability(pwalk); + re.probability *= p1; + } + + // done + return re; + + } + + ResultList getMany(const NavMeshWalkParams& params) { + + // sanity checks + params.check(); + + return {getOne(params)}; + + } + + + }; + +} + +#endif // NAVMESHWALKUNBLOCKABLE_H