stk-code_catmod/src/tracks/battle_graph.cpp
2015-12-19 16:23:18 +08:00

166 lines
5.8 KiB
C++

//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Joerg Henrichs
//
// This program 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 3
// 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, B
#include "tracks/battle_graph.hpp"
#include <IMesh.h>
#include <ICameraSceneNode.h>
#include <IMeshSceneNode.h>
#include "config/user_config.hpp"
#include "items/item_manager.hpp"
#include "tracks/navmesh.hpp"
#include "utils/log.hpp"
const int BattleGraph::UNKNOWN_POLY = -1;
BattleGraph * BattleGraph::m_battle_graph = NULL;
/** Constructor, Creates a navmesh, builds a graph from the navmesh and
* then runs shortest path algorithm to find and store paths to be used
* by the AI. */
BattleGraph::BattleGraph(const std::string &navmesh_file_name)
{
m_items_on_graph.clear();
NavMesh::create(navmesh_file_name);
m_navmesh_file = navmesh_file_name;
buildGraph(NavMesh::get());
computeFloydWarshall();
} // BattleGraph
// -----------------------------------------------------------------------------
/** Destructor, destroys NavMesh and the debug mesh if it exists */
BattleGraph::~BattleGraph(void)
{
NavMesh::destroy();
if(UserConfigParams::m_track_debug)
cleanupDebugMesh();
GraphStructure::destroyRTT();
} // ~BattleGraph
// -----------------------------------------------------------------------------
/** Builds a graph from an existing NavMesh. The graph is stored as an adjacency
* matrix. */
void BattleGraph::buildGraph(NavMesh* navmesh)
{
unsigned int n_polys = navmesh->getNumberOfPolys();
m_distance_matrix = std::vector< std::vector<float> > (n_polys, std::vector<float>(n_polys, 9999.9f));
for(unsigned int i=0; i<n_polys; i++)
{
NavPoly currentPoly = navmesh->getNavPoly(i);
std::vector<int> adjacents = navmesh->getAdjacentPolys(i);
for(unsigned int j=0; j<adjacents.size(); j++)
{
Vec3 adjacentPolyCenter = navmesh->getCenterOfPoly(adjacents[j]);
float distance = Vec3(adjacentPolyCenter - currentPoly.getCenter()).length_2d();
m_distance_matrix[i][adjacents[j]] = distance;
//m_distance_matrix[adjacents[j]][i] = distance;
}
m_distance_matrix[i][i] = 0.0f;
}
} // buildGraph
// -----------------------------------------------------------------------------
/** computeFloydWarshall() computes the shortest distance between any two nodes.
* At the end of the computation, m_distance_matrix[i][j] stores the shortest path
* distance from i to j and m_parent_poly[i][j] stores the last vertex visited on the
* shortest path from i to j before visiting j. Suppose the shortest path from i to j is
* i->......->k->j then m_parent_poly[i][j] = k
*/
void BattleGraph::computeFloydWarshall()
{
unsigned int n = getNumNodes();
// initialize m_parent_poly with unknown_poly so that if no path is found b/w i and j
// then m_parent_poly[i][j] = -1 (UNKNOWN_POLY)
// AI must check this
m_parent_poly = std::vector< std::vector<int> > (n, std::vector<int>(n,BattleGraph::UNKNOWN_POLY));
for(unsigned int i=0; i<n; i++)
{
for(unsigned int j=0; j<n; j++)
{
if(i == j || m_distance_matrix[i][j]>=9899.9f) m_parent_poly[i][j]=-1;
else m_parent_poly[i][j] = i;
}
}
for(unsigned int k=0; k<n; k++)
{
for(unsigned int i=0; i<n; i++)
{
for(unsigned int j=0; j<n; j++)
{
if( (m_distance_matrix[i][k] + m_distance_matrix[k][j]) < m_distance_matrix[i][j])
{
m_distance_matrix[i][j] = m_distance_matrix[i][k] + m_distance_matrix[k][j];
m_parent_poly[i][j] = m_parent_poly[k][j];
}
}
}
}
} // computeFloydWarshall
// -----------------------------------------------------------------------------
/** Maps items on battle graph */
void BattleGraph::findItemsOnGraphNodes()
{
const ItemManager* item_manager = ItemManager::get();
unsigned int item_count = item_manager->getNumberOfItems();
for (unsigned int i = 0; i < item_count; ++i)
{
const Item* item = item_manager->getItem(i);
Vec3 xyz = item->getXYZ();
int polygon = BattleGraph::UNKNOWN_POLY;
for (unsigned int j = 0; j < this->getNumNodes(); ++j)
{
if (NavMesh::get()->getNavPoly(j).pointInPoly(xyz))
{
float dist = xyz.getY() - NavMesh::get()->getCenterOfPoly(j).getY();
if (fabsf(dist) < 1.0f )
polygon = j;
}
}
if (polygon != BattleGraph::UNKNOWN_POLY)
{
m_items_on_graph.push_back(std::make_pair(item, polygon));
Log::debug("BattleGraph","item number %d is on polygon %d", i, polygon);
}
else
Log::debug("BattleGraph","Can't map item number %d with a suitable polygon", i);
}
}
// -----------------------------------------------------------------------------
const int & BattleGraph::getNextShortestPathPoly(int i, int j) const
{
if (i == BattleGraph::UNKNOWN_POLY || j == BattleGraph::UNKNOWN_POLY)
return BattleGraph::UNKNOWN_POLY;
return m_parent_poly[j][i];
}