1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-12-01 15:35:47 +00:00
Aquaria/Aquaria/PathFinding.cpp
2016-05-05 19:57:50 +02:00

252 lines
6.2 KiB
C++

/*
Copyright (C) 2007, 2010 - Bit-Blot
This file is part of Aquaria.
Aquaria is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <JPS.h>
#include "PathFinding.h"
#include "DSQ.h"
#include "Game.h"
class SearchGridRaw
{
public:
SearchGridRaw(ObsType blocking) : game(dsq->game), blockingObsBits(blocking) {}
inline bool operator()(unsigned x, unsigned y) const
{
return (game->getGridRaw(TileVector(x, y)) & blockingObsBits) == OT_EMPTY;
}
ObsType blockingObsBits;
const Game *game;
};
class PathFinding::State : public ScriptObject
{
public:
State(ObsType obs) : grid(obs), searcher(grid), result(JPS::NO_PATH) {}
SearchGridRaw grid;
JPS::Searcher<SearchGridRaw> searcher;
JPS::Result result;
};
static void generateVectorPath(const JPS::PathVector& rawpath, VectorPath& vp, int offx, int offy)
{
for(JPS::PathVector::const_iterator it = rawpath.begin(); it != rawpath.end(); ++it)
vp.addPathNode(Vector((it->x*TILE_SIZE)+TILE_SIZE/2+offx, (it->y*TILE_SIZE)+TILE_SIZE/2)+offy, 0);
}
void PathFinding::forceMinimumPath(VectorPath &path, const Vector &start, const Vector &dest)
{
if (path.getNumPathNodes() <= 2)
{
path.clear();
path.addPathNode(start, 0);
path.addPathNode(dest, 1);
}
}
void PathFinding::molestPath(VectorPath &path)
{
int sz=path.getNumPathNodes();
if(!sz)
return;
int i = 0;
// make normals
std::vector<Vector> normals;
normals.resize(sz);
for (i = 0; i < sz; i++)
{
Vector node = path.getPathNode(i)->value;
float dist;
int sample = 20;
float maxDist = sample * TILE_SIZE;
{
Vector n = dsq->game->getWallNormal(node, sample, &dist);
if (dist != -1 && (n.x != 0 || n.y != 0))
{
n.setLength2D(200);
TileVector test(node + n);
if (dsq->game->isObstructed(test))
{
n.setLength2D(100);
test = TileVector(node+n);
if (dsq->game->isObstructed(test))
{
n.setLength2D(50);
test = TileVector(node+n);
if (dsq->game->isObstructed(test))
{
n = Vector(0,0,0);
}
}
}
normals[i] = n;
}
}
}
// use wall normal to push out node a bit
std::vector<Vector> newNormals;
newNormals.resize(normals.size());
for (i = 1; i < normals.size()-1; i++)
newNormals[i] = (normals[i] + normals[i-1] + normals[i+1])/3.0f;
for (i = 1; i < sz-1; i++)
path.getPathNode(i)->value += newNormals[i];
// kill bowls
int start = 0;
int runs=0;
bool hadSuccess = false;
int lastSuccessNode = 0;
int adjust = 2;
sz=path.getNumPathNodes();
for (i = start; i < sz-1; i++)
{
runs++;
if (runs > 8000)
{
debugLog("kill bowls ran too much");
start = sz*100;
}
lastSuccessNode = 0;
hadSuccess = false;
Vector node = path.getPathNode(i)->value;
for (int j = sz-1; j >= i+adjust; j--)
{
Vector target = path.getPathNode(j)->value;
if (dsq->game->trace(node, target))
{
hadSuccess = true;
lastSuccessNode = j;
break;
}
}
if (hadSuccess)
{
// this code will only delete things that are bowl-ish
// (things that take you on detours)
++i;
path.removeNodes(i, lastSuccessNode-1);
hadSuccess = false;
}
sz = path.getNumPathNodes();
}
sz=path.getNumPathNodes();
// remove last node
//path.removeNodes(path.getNumPathNodes()-2, path.getNumPathNodes()-2);
path.realPercentageCalc();
}
void PathFinding::generatePath(RenderObject *ro, TileVector start, TileVector goal, int offx, int offy)
{
ro->position.ensureData();
VectorPath& vp = ro->position.data->path;
vp.clear();
SearchGridRaw grid(OT_BLOCKING);
JPS::PathVector path;
if(JPS::findPath(path, grid, start.x, start.y, goal.x, goal.y, 1))
{
vp.addPathNode(ro->position, 0);
generateVectorPath(path, vp, offx, offy);
}
}
bool PathFinding::generatePathSimple(VectorPath& path, const Vector& start, const Vector& end, unsigned int step /* = 0 */, unsigned int obs /* = 0 */)
{
if(obs == OT_EMPTY)
obs = OT_BLOCKING;
SearchGridRaw grid((ObsType)obs);
JPS::PathVector p;
TileVector tstart(start);
TileVector tend(end);
if(!JPS::findPath(p, grid, tstart.x, tstart.y, tend.x, tend.y, step))
return false;
generateVectorPath(p, path, 0, 0);
molestPath(path);
return true;
}
PathFinding::State *PathFinding::initFindPath()
{
State *state = new PathFinding::State(OT_BLOCKING);
return state;
}
void PathFinding::deleteFindPath(State *state)
{
delete state;
}
void PathFinding::beginFindPath(PathFinding::State *state, const Vector& start, const Vector& end, unsigned int obs /* = 0 */)
{
if(obs == OT_EMPTY)
obs = OT_BLOCKING;
state->grid.blockingObsBits = (ObsType)obs;
TileVector tstart(start);
TileVector tend(end);
JPS::Position istart = JPS::Pos(tstart.x, tstart.y);
JPS::Position iend = JPS::Pos(tend.x, tend.y);
state->result = state->searcher.findPathInit(istart, iend);
}
bool PathFinding::updateFindPath(PathFinding::State *state, int limit)
{
if(state->result == JPS::NEED_MORE_STEPS)
{
state->result = state->searcher.findPathStep(limit);
return state->result != JPS::NEED_MORE_STEPS;
}
return true; // done
}
bool PathFinding::finishFindPath(PathFinding::State *state, VectorPath& path, unsigned step /* = 0 */)
{
if(state->result != JPS::FOUND_PATH)
return state->result == JPS::EMPTY_PATH;
JPS::PathVector rawpath;
state->searcher.findPathFinish(rawpath, step);
generateVectorPath(rawpath, path, 0, 0);
molestPath(path);
return true;
}
void PathFinding::purgeFindPath(PathFinding::State *state)
{
state->searcher.freeMemory();
}
void PathFinding::getStats(PathFinding::State *state, unsigned& stepsDone, unsigned& nodesExpanded)
{
stepsDone = (unsigned)state->searcher.getStepsDone();
nodesExpanded = (unsigned)state->searcher.getNodesExpanded();
}