2011-08-03 22:05:33 +02:00
|
|
|
/*
|
|
|
|
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 "PathFinding.h"
|
|
|
|
#include "DSQ.h"
|
|
|
|
#include "Game.h"
|
|
|
|
|
|
|
|
|
|
|
|
const int divs = 6;
|
|
|
|
const int MAX_ZONES=1000;
|
|
|
|
const int MAX_STEPS = 5000;
|
|
|
|
const int cutOff = int((divs*divs)*0.75f);
|
|
|
|
|
|
|
|
namespace PathFindingGlobals
|
|
|
|
{
|
|
|
|
// This isn't used by the current code, so I've commented it out to
|
|
|
|
// save 4MB of RAM. --achurch
|
|
|
|
//int zones[MAX_ZONES][MAX_ZONES];
|
|
|
|
|
|
|
|
MapSearchNode node_goal;
|
|
|
|
MapSearchNode node_start;
|
|
|
|
RenderObject *render_object;
|
|
|
|
bool hate_diagonals;
|
|
|
|
}
|
|
|
|
|
|
|
|
float MapSearchNode::GoalDistanceEstimate( MapSearchNode &nodeGoal )
|
|
|
|
{
|
|
|
|
float xd = float( ( (float)x - (float)nodeGoal.x ) );
|
|
|
|
float yd = float( ( (float)y - (float)nodeGoal.y) );
|
|
|
|
|
|
|
|
return ((xd*xd) + (yd*yd));
|
|
|
|
//return 0;
|
|
|
|
/*
|
|
|
|
int r = 10;
|
|
|
|
float c = 0;
|
|
|
|
for (int x = -r; x < r; x+=2)
|
|
|
|
{
|
|
|
|
for (int y = -r; y < r; y+=2)
|
|
|
|
{
|
|
|
|
if (dsq->game->getGrid(TileVector(this->x+x, this->y+y)))
|
|
|
|
{
|
|
|
|
//c+= r*TILE_SIZE
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ((xd*xd) + (yd*yd)) + c * (2*TILE_SIZE);
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
float xd = float( ( (float)x - (float)nodeGoal.x ) );
|
|
|
|
float yd = float( ( (float)y - (float)nodeGoal.y) );
|
|
|
|
int dist = ((xd*xd) + (yd*yd));
|
|
|
|
return (int(dist/80)*80);
|
|
|
|
*/
|
|
|
|
|
|
|
|
//return ((xd*xd) + (yd*yd));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// + c; //+ c * (2*TILE_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MapSearchNode::IsGoal( MapSearchNode &nodeGoal )
|
|
|
|
{
|
|
|
|
Vector v(x, y);
|
|
|
|
Vector g(nodeGoal.x, nodeGoal.y);
|
|
|
|
if (divs > 1)
|
|
|
|
{
|
|
|
|
if ((v - g).getSquaredLength2D() <= sqr(divs+1))
|
|
|
|
{
|
|
|
|
// HACK: remember this
|
|
|
|
//debugLog ("really close to the goal!");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( int(x/divs) == int(nodeGoal.x/divs) && int(y/divs) == int(nodeGoal.y/divs))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This generates the successors to the given Node. It uses a helper function called
|
|
|
|
// AddSuccessor to give the successors to the AStar class. The A* specific initialisation
|
|
|
|
// is done for each node internally, so here you just set the state information that
|
|
|
|
// is specific to the application
|
|
|
|
bool MapSearchNode::GetSuccessors( AStarSearch *astarsearch, MapSearchNode *parent_node )
|
|
|
|
{
|
|
|
|
|
|
|
|
int parent_x = -1;
|
|
|
|
int parent_y = -1;
|
|
|
|
|
|
|
|
if( parent_node )
|
|
|
|
{
|
|
|
|
parent_x = parent_node->x;
|
|
|
|
parent_y = parent_node->y;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MapSearchNode NewNode;
|
|
|
|
|
|
|
|
int i = divs;
|
|
|
|
// push each possible move except allowing the search to go backwards
|
|
|
|
if ((GetMap (x-i, y) <= 0) && !((parent_x == x-i) && (parent_y == y)))
|
|
|
|
{
|
|
|
|
NewNode = MapSearchNode( x-i, y );
|
|
|
|
astarsearch->AddSuccessor( NewNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((GetMap (x, y-i) <= 0) && !((parent_x == x) && (parent_y == y-i)))
|
|
|
|
{
|
|
|
|
NewNode = MapSearchNode( x, y-i );
|
|
|
|
astarsearch->AddSuccessor( NewNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((GetMap (x+i, y) <= 0) && !((parent_x == x+i) && (parent_y == y)))
|
|
|
|
{
|
|
|
|
NewNode = MapSearchNode( x+i, y );
|
|
|
|
astarsearch->AddSuccessor( NewNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((GetMap (x, y+i) <= 0) && !((parent_x == x) && (parent_y == y+i)))
|
|
|
|
{
|
|
|
|
NewNode = MapSearchNode( x, y+i );
|
|
|
|
astarsearch->AddSuccessor( NewNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!PathFindingGlobals::hate_diagonals)
|
|
|
|
{
|
|
|
|
if ((GetMap (x-i, y-i) < 1) && !((parent_x == x-i) && (parent_y == y-i)))
|
|
|
|
{
|
|
|
|
NewNode = MapSearchNode( x-i, y-i );
|
|
|
|
astarsearch->AddSuccessor( NewNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((GetMap (x-i, y+i) < 1) && !((parent_x == x-i) && (parent_y == y+i)))
|
|
|
|
{
|
|
|
|
NewNode = MapSearchNode( x-i, y+i );
|
|
|
|
astarsearch->AddSuccessor( NewNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((GetMap (x+i, y+i) <1) && !((parent_x == x+i) && (parent_y == y+i)))
|
|
|
|
{
|
|
|
|
NewNode = MapSearchNode( x+i, y+i );
|
|
|
|
astarsearch->AddSuccessor( NewNode );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((GetMap (x+i, y-i) < 1) && !((parent_x == x+i) && (parent_y == y-i)))
|
|
|
|
{
|
|
|
|
NewNode = MapSearchNode( x+i, y-i );
|
|
|
|
astarsearch->AddSuccessor( NewNode );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// given this node, what does it cost to move to successor. In the case
|
|
|
|
// of our map the answer is the map terrain value at this node since that is
|
|
|
|
// conceptually where we're moving
|
|
|
|
float MapSearchNode::GetCost( MapSearchNode &successor )
|
|
|
|
{
|
|
|
|
float cost = 1;
|
|
|
|
/*
|
|
|
|
if (PathFindingGlobals::hate_diagonals)
|
|
|
|
{
|
|
|
|
if (successor.x != x && successor.y != y)
|
|
|
|
{
|
|
|
|
cost = 0.1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
//Vector p(x, y);
|
|
|
|
//penalize moving towards obstructions
|
|
|
|
/*
|
|
|
|
int r = 20;
|
|
|
|
float costy=0;
|
|
|
|
int c = 0;
|
|
|
|
float v = 0;
|
|
|
|
float dist = sqr(r*TILE_SIZE);
|
|
|
|
TileVector tme(this->x, this->y);
|
|
|
|
for (int x = -r; x < r; x++)
|
|
|
|
{
|
|
|
|
for (int y = -r; y < r; y++)
|
|
|
|
{
|
|
|
|
TileVector t(this->x + x, this->y + y);
|
|
|
|
if (dsq->game->isObstructed(t))
|
|
|
|
{
|
|
|
|
|
|
|
|
Vector diff = t.worldVector() - tme.worldVector();
|
|
|
|
int d = diff.getSquaredLength2D();
|
|
|
|
if (d < dist)
|
|
|
|
{
|
|
|
|
costy += 0.1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//TileVector tme(this->x, this->y);
|
|
|
|
//Vector diff = t.worldVector() - tme.worldVector();
|
|
|
|
//int d = diff.getSquaredLength2D();
|
|
|
|
//if (d < dist)
|
|
|
|
//{
|
|
|
|
// v += dist-diff.getSquaredLength2D();
|
|
|
|
//}
|
|
|
|
|
|
|
|
}
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cost += costy;
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
if (v > 0)
|
|
|
|
{
|
|
|
|
v /= float(c);
|
|
|
|
v /= float(dist);
|
|
|
|
cost += v*TILE_SIZE*10;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//penalize changing direction to tempt computer into moving in "straighter" paths
|
|
|
|
/*
|
|
|
|
if (successor.y != y && (dir == LEFT || dir == RIGHT))
|
|
|
|
cost +=39;
|
|
|
|
if (successor.x != x && (dir == UP || dir == DOWN))
|
|
|
|
cost +=39;
|
|
|
|
*/
|
|
|
|
|
|
|
|
return cost;
|
|
|
|
}
|
|
|
|
|
|
|
|
int MapSearchNode::GetMap (int tx, int ty)
|
|
|
|
{
|
|
|
|
//return 0;
|
|
|
|
//return PathFindingGlobals::zones[int(tx/divs)][int(ty/divs)] > cutOff;
|
|
|
|
int v = dsq->game->getGrid(TileVector(tx,ty));
|
|
|
|
/*
|
|
|
|
if (v != 0 && v != 1)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "v: " << v;
|
|
|
|
debugLog(os.str());
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
return v;
|
|
|
|
/*
|
|
|
|
if (dsq->game->getGrid(TileVector(x,y))
|
|
|
|
|| dsq->game->getGrid(TileVector(x+1,y))
|
|
|
|
|| dsq->game->getGrid(TileVector(x-1,y))
|
|
|
|
|| dsq->game->getGrid(TileVector(x+2,y))
|
|
|
|
|| dsq->game->getGrid(TileVector(x-2,y))
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
int r = 3;
|
|
|
|
for (int x = -r; x < r; x++)
|
|
|
|
{
|
|
|
|
for (int y = -r; y < r; y++)
|
|
|
|
{
|
|
|
|
if (dsq->game->getGrid(TileVector(tx+x, ty+y)))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
// ignore the start node
|
|
|
|
if (x == KittyTown::instance->nodeStart->x && y == KittyTown::instance->nodeStart->y)
|
|
|
|
{
|
|
|
|
obs = -1;
|
|
|
|
}
|
|
|
|
return obs;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
// same state in a maze search is simply when (x,y) are the same
|
|
|
|
bool MapSearchNode::IsSameState( MapSearchNode &rhs )
|
|
|
|
{
|
|
|
|
if( (int(x/divs) == int(rhs.x/divs)) && (int(y/divs) == int(rhs.y/divs)) )
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PathFinding::generateZones()
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
for (int x = 0; x < MAX_ZONES; x++)
|
|
|
|
{
|
|
|
|
for (int y = 0; y < MAX_ZONES; y++)
|
|
|
|
{
|
|
|
|
PathFindingGlobals::zones[x][y] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int x = 0; x < MAX_GRID; x+=divs)
|
|
|
|
{
|
|
|
|
for (int y = 0; y < MAX_GRID; y+=divs)
|
|
|
|
{
|
|
|
|
for (int xx = x; xx < x + divs; xx++)
|
|
|
|
{
|
|
|
|
for (int yy = y; yy < y + divs; yy++)
|
|
|
|
{
|
|
|
|
if (dsq->game->getGrid(TileVector(xx,yy)) > 0)
|
|
|
|
{
|
|
|
|
PathFindingGlobals::zones[int(x/divs)][int(y/divs)]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void PathFinding::forceMinimumPath(VectorPath &path, const Vector &start, const Vector &dest)
|
|
|
|
{
|
|
|
|
if (path.getNumPathNodes() <= 2)
|
|
|
|
{
|
|
|
|
debugLog(" Path is <= 2 nodes... setting up simple path");
|
|
|
|
path.clear();
|
|
|
|
path.addPathNode(start, 0);
|
|
|
|
path.addPathNode(dest, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PathFinding::molestPath(VectorPath &path)
|
|
|
|
{
|
|
|
|
//path.cut(2);
|
|
|
|
|
|
|
|
int sz=path.getNumPathNodes();
|
|
|
|
|
|
|
|
/*
|
|
|
|
//normals.resize(sz);
|
|
|
|
|
|
|
|
*/
|
|
|
|
//float maxDist = 15155;
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
/*
|
|
|
|
float coverage = dsq->game->getCoverage(node, 100);
|
|
|
|
int sample = 10;
|
|
|
|
if (coverage > 0.4f)
|
|
|
|
sample = 5;
|
|
|
|
*/
|
|
|
|
int sample = 20;
|
|
|
|
float maxDist = sample * TILE_SIZE;
|
|
|
|
//sqrtf(sqr(sample*TILE_SIZE)+sqr(sample*TILE_SIZE));
|
|
|
|
|
|
|
|
//if (coverage < 0.6f)
|
|
|
|
{
|
|
|
|
Vector n = dsq->game->getWallNormal(node, sample, &dist);
|
|
|
|
if (dist != -1 && (n.x != 0 || n.y != 0))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
if (dist > maxDist)
|
|
|
|
maxDist = dist;
|
|
|
|
n *= (maxDist-dist); // *(1.0f-coverage);
|
|
|
|
*/
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-08-28 04:33:12 +02:00
|
|
|
/*std::ostringstream os;
|
2011-08-03 22:05:33 +02:00
|
|
|
os << "pushing node [" << i << "] out by (" << n.x << ", " << n.y << ") - dist: " << dist << " maxDist: " << maxDist;
|
2013-08-28 04:33:12 +02:00
|
|
|
debugLog(os.str());*/
|
2011-08-03 22:05:33 +02:00
|
|
|
//path.getPathNode(i)->value += n;
|
|
|
|
normals[i] = n;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "largest maxDist: " << maxDist;
|
|
|
|
debugLog(os.str());
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Vector> newNormals;
|
|
|
|
newNormals.resize(normals.size());
|
|
|
|
for (i = 1; i < normals.size()-1; i++)
|
|
|
|
{
|
|
|
|
|
|
|
|
// not doing smoothing!
|
|
|
|
Vector thisOne = normals[i];
|
|
|
|
|
|
|
|
Vector lastOne = normals[i-1];
|
|
|
|
Vector nextOne = normals[i+1];
|
|
|
|
newNormals[i] = (thisOne + lastOne + nextOne)/3.0f;
|
|
|
|
|
|
|
|
//newNormals[i] = thisOne;
|
|
|
|
}
|
|
|
|
for (i = 1; i < sz-1; i++)
|
|
|
|
{
|
|
|
|
path.getPathNode(i)->value += newNormals[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// kill bowls
|
|
|
|
int start = 0;
|
|
|
|
//int minDist = 150;
|
|
|
|
int runs=0;
|
|
|
|
bool hadSuccess = false;
|
|
|
|
int lastSuccessNode = 0;
|
|
|
|
//int adjust = int(minDist/float(TILE_SIZE*8));
|
|
|
|
int adjust = 2; // 1
|
|
|
|
//bowl_loop:
|
|
|
|
sz=path.getNumPathNodes();
|
|
|
|
|
2013-08-28 04:33:12 +02:00
|
|
|
/*std::ostringstream os;
|
2011-08-03 22:05:33 +02:00
|
|
|
os << "kill bowls # " << runs;
|
2013-08-28 04:33:12 +02:00
|
|
|
debugLog(os.str());*/
|
2011-08-03 22:05:33 +02:00
|
|
|
|
|
|
|
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-3; j >= i+adjust; j--)
|
|
|
|
//for (int j = i+adjust; j < sz-1; j++)
|
|
|
|
{
|
|
|
|
Vector target = path.getPathNode(j)->value;
|
|
|
|
//if ((target-node).getSquaredLength2D() >= sqr(minDist))
|
|
|
|
{
|
|
|
|
if (dsq->game->trace(node, target))
|
|
|
|
{
|
|
|
|
hadSuccess = true;
|
|
|
|
lastSuccessNode = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
else if (hadSuccess)
|
|
|
|
{
|
|
|
|
//break;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (hadSuccess)
|
|
|
|
{
|
|
|
|
// only do this if
|
|
|
|
//VectorPath copy = path.copySection(i,lastSuccessNode);
|
|
|
|
/*
|
|
|
|
// this code will only delete things that are bowl-ish
|
|
|
|
// (things that take you on detours)
|
|
|
|
float len = path.getSubSectionLength(i, lastSuccessNode);
|
|
|
|
float shortCut = (path.getPathNode(lastSuccessNode)->value - path.getPathNode(i)->value).getLength2D();
|
|
|
|
|
|
|
|
if (len > shortCut+TILE_SIZE*4)
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
path.removeNodes(i+1, lastSuccessNode-1);
|
2013-08-28 04:33:12 +02:00
|
|
|
/*std::ostringstream os;
|
2011-08-03 22:05:33 +02:00
|
|
|
os << "killing bowl: " << i+1 << " - " << lastSuccessNode-1;
|
2013-08-28 04:33:12 +02:00
|
|
|
debugLog(os.str());*/
|
2011-08-03 22:05:33 +02:00
|
|
|
//start = lastSuccessNode - (lastSuccessNode-i);
|
|
|
|
//start = i+1;
|
|
|
|
//i = i+1;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
hadSuccess = false;
|
|
|
|
//start += 2;
|
|
|
|
//goto bowl_loop;
|
|
|
|
}
|
|
|
|
sz = path.getNumPathNodes();
|
|
|
|
}
|
2013-08-28 04:33:12 +02:00
|
|
|
//debugLog("kill bowls done");
|
2011-08-03 22:05:33 +02:00
|
|
|
sz=path.getNumPathNodes();
|
|
|
|
|
|
|
|
// remove last node
|
|
|
|
path.removeNodes(path.getNumPathNodes()-2, path.getNumPathNodes()-2);
|
|
|
|
|
|
|
|
/*
|
|
|
|
loop:
|
|
|
|
for (int i = 0; i < sz-2; i++)
|
|
|
|
{
|
|
|
|
Vector node = path.getPathNode(i)->value;
|
|
|
|
Vector next = path.getPathNode(i+1)->value;
|
|
|
|
Vector next2 = path.getPathNode(i+2)->value;
|
|
|
|
int dist1 = (next - node).getSquaredLength2D() + (next2 - next).getSquaredLength2D();
|
|
|
|
int dist2 = (next2 - node).getSquaredLength2D();
|
|
|
|
if (dist2 <= dist1)
|
|
|
|
{
|
|
|
|
// remove next
|
|
|
|
path.removeNode(i+1);
|
|
|
|
goto loop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
path.realPercentageCalc();
|
|
|
|
//path.calculatePercentages();
|
|
|
|
/*
|
|
|
|
int sz=path.getNumPathNodes();
|
|
|
|
std::vector<Vector> normals;
|
|
|
|
normals.resize(sz);
|
|
|
|
for (int i = 1; i < sz-1; i++)
|
|
|
|
{
|
|
|
|
Vector node = path.getPathNode(i)->value;
|
|
|
|
Vector normal = dsq->game->getWallNormal(node, 10);
|
|
|
|
if (normal.x != 0 && normal.y != 0)
|
|
|
|
{
|
|
|
|
normal = normal*TILE_SIZE*10;
|
|
|
|
}
|
|
|
|
normals[i] = normal;
|
|
|
|
//path.getPathNode(i)->value = node;
|
|
|
|
}
|
|
|
|
for (int i = 1; i < sz-1; i++)
|
|
|
|
{
|
|
|
|
Vector normal = normals[i];
|
|
|
|
Vector lastNormal = normals[i-1];
|
|
|
|
|
|
|
|
//Vector node = path.getPathNode(i)->value;
|
|
|
|
//// average with the
|
|
|
|
//Vector prev = path.getPathNode(i-1)->value;
|
|
|
|
//Vector next = path.getPathNode(i+1)->value;
|
|
|
|
|
|
|
|
//node = (node + prev)/2.0f;
|
|
|
|
|
|
|
|
normal = (normal + lastNormal)/2.0f;
|
|
|
|
path.getPathNode(i)->value += normal;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
for (int i = 1; i < sz; i++)
|
|
|
|
{
|
|
|
|
Vector node = path.getPathNode(i)->value;
|
|
|
|
Vector p0 = path.getPathNode(i-1)->value;
|
|
|
|
Vector p1 = path.getPathNode(i)->value;
|
|
|
|
Vector p = p1 - p0;
|
|
|
|
if (i < sz-1)
|
|
|
|
{
|
|
|
|
p += path.getPathNode(i+1)->value - path.getPathNode(i)->value;
|
|
|
|
p /= 2.0f;
|
|
|
|
}
|
|
|
|
Vector pl = p.getPerpendicularLeft();
|
|
|
|
Vector pr = p.getPerpendicularRight();
|
|
|
|
pl.normalize2D();
|
|
|
|
pr.normalize2D();
|
|
|
|
TileVector tl(node), tr(node);
|
|
|
|
int left, right;
|
|
|
|
int maxCheck = 40;
|
|
|
|
for (left = 0; left < maxCheck; left++)
|
|
|
|
{
|
|
|
|
if (dsq->game->isObstructed(tl))
|
|
|
|
break;
|
|
|
|
tl.x += pl.x;
|
|
|
|
tl.y += pl.y;
|
|
|
|
}
|
|
|
|
for (right = 0; right < maxCheck; right++)
|
|
|
|
{
|
|
|
|
if (dsq->game->isObstructed(tr))
|
|
|
|
break;
|
|
|
|
tr.x += pr.x;
|
|
|
|
tr.y += pr.y;
|
|
|
|
}
|
|
|
|
if (left == maxCheck && right == maxCheck)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (left != 0 || right != 0)
|
|
|
|
{
|
|
|
|
//Vector normal = dsq->game->getWallNormal(node);
|
|
|
|
//if (normal.x != 0 && normal.y != 0)
|
|
|
|
//{
|
|
|
|
// if (left < right)
|
|
|
|
// path.getPathNode(i)->value += normal * (right-left)*TILE_SIZE;
|
|
|
|
// if (right > left)
|
|
|
|
// path.getPathNode(i)->value += normal * (left-right)*TILE_SIZE;
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
//int leftSz = left * TILE_SIZE;
|
|
|
|
////if (leftSz <= 0) leftSz = 1;
|
|
|
|
//int rightSz = right * TILE_SIZE;
|
|
|
|
////if (rightSz <= 0) rightSz = 1;
|
|
|
|
//pl |= leftSz;
|
|
|
|
//pr |= rightSz;
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
path.getPathNode(i)->value = (tr.worldVector() + tl.worldVector())/2.0f;
|
|
|
|
|
|
|
|
//path.getPathNode(i)->value = tl.worldVector() + (tr.worldVector() - tl.worldVector())/2.0f;//(node + pl) + (pr-pl)/2.0f;
|
|
|
|
path.getPathNode(i)->value.z = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
for (int i = 1; i < sz; i++)
|
|
|
|
{
|
|
|
|
Vector node = path.getPathNode(i)->value;
|
|
|
|
Vector pl = p.getPerpendicularLeft();
|
|
|
|
Vector pr = p.getPerpendicularRight();
|
|
|
|
pl.normalize2D();
|
|
|
|
pr.normalize2D();
|
|
|
|
TileVector tl(node), tr(node);
|
|
|
|
int left, right;
|
|
|
|
int maxCheck = 40;
|
|
|
|
for (int i = 0; i < maxCheck; i++)
|
|
|
|
{
|
|
|
|
dsq->game->position
|
|
|
|
}
|
|
|
|
if (left == maxCheck && right == maxCheck)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (left != 0 || right != 0)
|
|
|
|
{
|
|
|
|
//Vector normal = dsq->game->getWallNormal(node);
|
|
|
|
//if (normal.x != 0 && normal.y != 0)
|
|
|
|
//{
|
|
|
|
// if (left < right)
|
|
|
|
// path.getPathNode(i)->value += normal * (right-left)*TILE_SIZE;
|
|
|
|
// if (right > left)
|
|
|
|
// path.getPathNode(i)->value += normal * (left-right)*TILE_SIZE;
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
//int leftSz = left * TILE_SIZE;
|
|
|
|
////if (leftSz <= 0) leftSz = 1;
|
|
|
|
//int rightSz = right * TILE_SIZE;
|
|
|
|
////if (rightSz <= 0) rightSz = 1;
|
|
|
|
//pl |= leftSz;
|
|
|
|
//pr |= rightSz;
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
path.getPathNode(i)->value = (tr.worldVector() + tl.worldVector())/2.0f;
|
|
|
|
|
|
|
|
//path.getPathNode(i)->value = tl.worldVector() + (tr.worldVector() - tl.worldVector())/2.0f;//(node + pl) + (pr-pl)/2.0f;
|
|
|
|
path.getPathNode(i)->value.z = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void PathFinding::generatePath(RenderObject *ro, TileVector start, TileVector goal, int offx, int offy, bool hate_diagonals)
|
|
|
|
{
|
|
|
|
//return;
|
|
|
|
|
|
|
|
int sx = start.x;
|
|
|
|
int sy = start.y;
|
|
|
|
int gx = goal.x;
|
|
|
|
int gy = goal.y;
|
|
|
|
|
|
|
|
|
|
|
|
PathFindingGlobals::hate_diagonals = hate_diagonals;
|
|
|
|
/*
|
|
|
|
if (offx >= TILE_SIZE/2-1)
|
|
|
|
offx--;
|
|
|
|
if (offy >= TILE_SIZE/2-1)
|
|
|
|
offy--;
|
|
|
|
if (offx <= TILE_SIZE/2+1)
|
|
|
|
offx++;
|
|
|
|
if (offy <= TILE_SIZE/2+1)
|
|
|
|
offy++;
|
|
|
|
*/
|
|
|
|
ro->position.ensureData();
|
|
|
|
ro->position.data->path.clear();
|
|
|
|
|
|
|
|
PathFindingGlobals::render_object = ro;
|
|
|
|
AStarSearch astarsearch;
|
|
|
|
|
|
|
|
// Create a start state
|
|
|
|
MapSearchNode nodeStart;
|
|
|
|
nodeStart.x = sx;
|
|
|
|
nodeStart.y = sy;
|
|
|
|
PathFindingGlobals::node_start = nodeStart;
|
|
|
|
|
|
|
|
if (nodeStart.GetMap(gx, gy) > 0)
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "goal (" << gx << ", " << gy << ") blocked";
|
|
|
|
debugLog (os.str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Define the goal state
|
|
|
|
|
|
|
|
MapSearchNode nodeEnd;
|
|
|
|
nodeEnd.x = gx;
|
|
|
|
nodeEnd.y = gy;
|
|
|
|
|
|
|
|
PathFindingGlobals::node_goal = nodeEnd;
|
|
|
|
|
|
|
|
// Set Start and goal states
|
|
|
|
|
|
|
|
astarsearch.SetStartAndGoalStates( nodeStart, nodeEnd );
|
|
|
|
|
|
|
|
unsigned int SearchState;
|
|
|
|
unsigned int SearchSteps = 0;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
SearchState = astarsearch.SearchStep();
|
|
|
|
|
|
|
|
if (SearchState != AStarSearch::SEARCH_STATE_SEARCHING)
|
|
|
|
break;
|
|
|
|
|
|
|
|
SearchSteps++;
|
|
|
|
|
|
|
|
if (SearchSteps > MAX_STEPS) break;
|
|
|
|
}
|
|
|
|
while( SearchState == AStarSearch::SEARCH_STATE_SEARCHING );
|
|
|
|
|
|
|
|
if( SearchState == AStarSearch::SEARCH_STATE_SUCCEEDED )
|
|
|
|
{
|
|
|
|
//errorLog ("Search found goal state",0);
|
|
|
|
|
|
|
|
MapSearchNode *node = astarsearch.GetSolutionStart();
|
|
|
|
int steps = 0;
|
|
|
|
|
|
|
|
//node->PrintNodeInfo();
|
|
|
|
ro->position.data->path.addPathNode(Vector((node->x*TILE_SIZE)+TILE_SIZE/2+offx, (node->y*TILE_SIZE)+TILE_SIZE/2)+offy, 0);
|
|
|
|
for( ;; )
|
|
|
|
{
|
|
|
|
node = astarsearch.GetSolutionNext();
|
|
|
|
|
|
|
|
if( !node )
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//node->PrintNodeInfo();
|
|
|
|
ro->position.data->path.addPathNode(Vector((node->x*TILE_SIZE)+TILE_SIZE/2+offx, (node->y*TILE_SIZE)+TILE_SIZE/2)+offy, steps);
|
|
|
|
steps ++;
|
|
|
|
};
|
|
|
|
//ro->position.path.addPathNode(Vector(goal.x*TILE_SIZE, goal.y*TILE_SIZE), steps);
|
|
|
|
/*
|
|
|
|
std::ostringstream os;
|
|
|
|
os << "Solution steps " << steps;
|
|
|
|
msg(os.str());
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Once you're done with the solution you can free the nodes up
|
|
|
|
astarsearch.FreeSolutionNodes();
|
|
|
|
}
|
|
|
|
else if( SearchState == AStarSearch::SEARCH_STATE_FAILED )
|
|
|
|
{
|
|
|
|
debugLog("Search terminated. Did not find goal state");
|
|
|
|
|
|
|
|
//astarsearch.FreeSolutionNodes();
|
|
|
|
astarsearch.FreeStartAndGoalNodes();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// exceeded count
|
|
|
|
debugLog("Path too long");
|
|
|
|
|
|
|
|
astarsearch.FreeAllNodes();
|
|
|
|
astarsearch.FreeStartAndGoalNodes();
|
|
|
|
//astarsearch.FreeSolutionNodes();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (astarsearch.m_AllocateNodeCount != astarsearch.m_FreeNodeCount)
|
|
|
|
{
|
|
|
|
debugLog("astar memory leak");
|
|
|
|
}
|
|
|
|
//return path_vector;
|
|
|
|
}
|
|
|
|
|
|
|
|
|