mirror of
https://github.com/glest/glest-source.git
synced 2025-02-25 12:12:25 +01:00
* some small changes to Unit, UnitType, Vec2<> & Map needed for the new path finder * compiles, but not hooked up yet, old PathFinder still in use
320 lines
8.8 KiB
C++
320 lines
8.8 KiB
C++
// ==============================================================
|
|
// This file is part of Glest (www.glest.org)
|
|
//
|
|
// Copyright (C) 2009 James McCulloch <silnarm at gmail>
|
|
//
|
|
// You can redistribute this code 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
|
|
// ==============================================================
|
|
|
|
#ifndef _GLEST_GAME_CLUSTER_MAP_H_
|
|
#define _GLEST_GAME_CLUSTER_MAP_H_
|
|
|
|
#include "util.h"
|
|
#include "game_constants.h"
|
|
#include "skill_type.h"
|
|
#include "math_util.h"
|
|
|
|
#include <map>
|
|
#include <set>
|
|
#include <list>
|
|
|
|
namespace Glest { namespace Game {
|
|
|
|
using std::set;
|
|
using std::map;
|
|
using std::list;
|
|
using Shared::Util::deleteValues;
|
|
|
|
class AnnotatedMap;
|
|
class Cartographer;
|
|
struct Transition;
|
|
|
|
/** uni-directional edge, is owned by the source transition, contains pointer to dest */
|
|
struct Edge {
|
|
private:
|
|
static int numEdges[fieldCount];
|
|
|
|
const Transition *dest;
|
|
vector<float> weights;
|
|
|
|
Field f; // for diagnostics... remove this one day
|
|
|
|
public:
|
|
Edge(const Transition *t, Field f) : f(f) {
|
|
dest = t;
|
|
++numEdges[f];
|
|
}
|
|
|
|
~Edge() {
|
|
--numEdges[f];
|
|
}
|
|
|
|
void addWeight(const float w) { weights.push_back(w); }
|
|
const Transition* transition() const { return dest; }
|
|
float cost(int size) const { return weights[size-1]; }
|
|
int maxClear() { return weights.size(); }
|
|
|
|
static int NumEdges(Field f) { return numEdges[f]; }
|
|
static void zeroCounters();
|
|
};
|
|
typedef list<Edge*> Edges;
|
|
|
|
/** */
|
|
struct Transition {
|
|
private:
|
|
static int numTransitions[fieldCount];
|
|
Field f;
|
|
|
|
public:
|
|
int clearance;
|
|
Vec2i nwPos;
|
|
bool vertical;
|
|
Edges edges;
|
|
|
|
Transition(Vec2i pos, int clear, bool vert, Field f)
|
|
: f(f), clearance(clear), nwPos(pos), vertical(vert) {
|
|
++numTransitions[f];
|
|
}
|
|
~Transition() {
|
|
deleteValues(edges.begin(), edges.end());
|
|
--numTransitions[f];
|
|
}
|
|
|
|
static int NumTransitions(Field f) { return numTransitions[f]; }
|
|
static void zeroCounters();
|
|
};
|
|
|
|
typedef vector<const Transition*> Transitions;
|
|
|
|
struct TransitionCollection {
|
|
Transition *transitions[GameConstants::clusterSize / 2];
|
|
unsigned n;
|
|
|
|
TransitionCollection() {
|
|
n = 0;
|
|
memset(transitions, 0, sizeof(Transition*) * GameConstants::clusterSize / 2);
|
|
}
|
|
|
|
void add(Transition *t) {
|
|
assert(n < GameConstants::clusterSize / 2);
|
|
transitions[n++] = t;
|
|
}
|
|
|
|
void clear() {
|
|
for (int i=0; i < n; ++i) {
|
|
delete transitions[i];
|
|
}
|
|
n = 0;
|
|
}
|
|
|
|
};
|
|
|
|
struct ClusterBorder {
|
|
TransitionCollection transitions[fieldCount];
|
|
|
|
~ClusterBorder() {
|
|
for (int f = 0; f < fieldCount; ++f) {
|
|
transitions[f].clear();
|
|
}
|
|
}
|
|
};
|
|
|
|
/** NeighbourFunc, describes abstract search space */
|
|
class TransitionNeighbours {
|
|
public:
|
|
void operator()(const Transition* pos, vector<const Transition*> &neighbours) const {
|
|
for (Edges::const_iterator it = pos->edges.begin(); it != pos->edges.end(); ++it) {
|
|
neighbours.push_back((*it)->transition());
|
|
}
|
|
}
|
|
};
|
|
|
|
/** cost function for searching cluster map */
|
|
class TransitionCost {
|
|
Field field;
|
|
int size;
|
|
|
|
public:
|
|
TransitionCost(Field f, int s) : field(f), size(s) {}
|
|
float operator()(const Transition *t, const Transition *t2) const {
|
|
Edges::const_iterator it = t->edges.begin();
|
|
for ( ; it != t->edges.end(); ++it) {
|
|
if ((*it)->transition() == t2) {
|
|
break;
|
|
}
|
|
}
|
|
if (it == t->edges.end()) {
|
|
throw runtime_error("bad connection in ClusterMap.");
|
|
}
|
|
if ((*it)->maxClear() >= size) {
|
|
return (*it)->cost(size);
|
|
}
|
|
return -1.f;
|
|
}
|
|
};
|
|
|
|
/** goal function for search on cluster map */
|
|
class TransitionGoal {
|
|
set<const Transition*> goals;
|
|
public:
|
|
TransitionGoal() {}
|
|
set<const Transition*>& goalTransitions() {return goals;}
|
|
bool operator()(const Transition *t, const float d) const {
|
|
return goals.find(t) != goals.end();
|
|
}
|
|
};
|
|
|
|
#define POS_X ((cluster.x + 1) * GameConstants::clusterSize - i - 1)
|
|
#define POS_Y ((cluster.y + 1) * GameConstants::clusterSize - i - 1)
|
|
|
|
class ClusterMap {
|
|
#if _GAE_DEBUG_EDITION_
|
|
friend class DebugRenderer;
|
|
#endif
|
|
private:
|
|
int w, h;
|
|
ClusterBorder *vertBorders, *horizBorders, sentinel;
|
|
Cartographer *carto;
|
|
AnnotatedMap *aMap;
|
|
|
|
set<Vec2i> dirtyClusters;
|
|
set<Vec2i> dirtyNorthBorders;
|
|
set<Vec2i> dirtyWestBorders;
|
|
bool dirty;
|
|
|
|
int eClear[GameConstants::clusterSize];
|
|
|
|
public:
|
|
ClusterMap(AnnotatedMap *aMap, Cartographer *carto);
|
|
~ClusterMap();
|
|
|
|
int getWidth() const { return w; }
|
|
int getHeight() const { return h; }
|
|
|
|
static Vec2i cellToCluster (const Vec2i &cellPos) {
|
|
return Vec2i(cellPos.x / GameConstants::clusterSize, cellPos.y / GameConstants::clusterSize);
|
|
}
|
|
// ClusterBorder getters
|
|
ClusterBorder* getNorthBorder(Vec2i cluster) {
|
|
return ( cluster.y == 0 ) ? &sentinel : &horizBorders[(cluster.y - 1) * w + cluster.x ];
|
|
}
|
|
ClusterBorder* getEastBorder(Vec2i cluster) {
|
|
return ( cluster.x == w - 1 ) ? &sentinel : &vertBorders[cluster.y * (w - 1) + cluster.x ];
|
|
}
|
|
ClusterBorder* getSouthBorder(Vec2i cluster) {
|
|
return ( cluster.y == h - 1 ) ? &sentinel : &horizBorders[cluster.y * w + cluster.x];
|
|
}
|
|
ClusterBorder* getWestBorder(Vec2i cluster) {
|
|
return ( cluster.x == 0 ) ? &sentinel : &vertBorders[cluster.y * (w - 1) + cluster.x - 1];
|
|
}
|
|
ClusterBorder* getBorder(Vec2i cluster, CardinalDir dir) {
|
|
switch (dir) {
|
|
case CardinalDir::NORTH:
|
|
return getNorthBorder(cluster);
|
|
case CardinalDir::EAST:
|
|
return getEastBorder(cluster);
|
|
case CardinalDir::SOUTH:
|
|
return getSouthBorder(cluster);
|
|
case CardinalDir::WEST:
|
|
return getWestBorder(cluster);
|
|
default:
|
|
throw runtime_error("ClusterMap::getBorder() passed dodgey direction");
|
|
}
|
|
return 0; // keep compiler quiet
|
|
}
|
|
void getTransitions(const Vec2i &cluster, Field f, Transitions &t);
|
|
|
|
bool isDirty() { return dirty; }
|
|
void update();
|
|
|
|
void setClusterDirty(const Vec2i &cluster) { dirty = true; dirtyClusters.insert(cluster); }
|
|
void setNorthBorderDirty(const Vec2i &cluster) { dirty = true; dirtyNorthBorders.insert(cluster); }
|
|
void setWestBorderDirty(const Vec2i &cluster) { dirty = true; dirtyWestBorders.insert(cluster); }
|
|
|
|
void assertValid();
|
|
|
|
private:
|
|
struct EntranceInfo {
|
|
ClusterBorder *cb;
|
|
Field f;
|
|
bool vert;
|
|
int pos, max_clear, startPos, endPos, run;
|
|
};
|
|
void addBorderTransition(EntranceInfo &info);
|
|
void initClusterBorder(const Vec2i &cluster, bool north);
|
|
|
|
/** initialise/re-initialise cluster (evaluates north and west borders) */
|
|
void initCluster(const Vec2i &cluster) {
|
|
initClusterBorder(cluster, true);
|
|
initClusterBorder(cluster, false);
|
|
}
|
|
|
|
void evalCluster(const Vec2i &cluster);
|
|
|
|
float linePathLength(Field f, int size, const Vec2i &start, const Vec2i &dest);
|
|
float aStarPathLength(Field f, int size, const Vec2i &start, const Vec2i &dest);
|
|
|
|
void disconnectCluster(const Vec2i &cluster);
|
|
};
|
|
|
|
struct TransitionAStarNode {
|
|
const Transition *pos, *prev;
|
|
float heuristic; /**< estimate of distance to goal */
|
|
float distToHere; /**< cost from origin to this node */
|
|
float est() const { /**< estimate, costToHere + heuristic */
|
|
return distToHere + heuristic;
|
|
}
|
|
};
|
|
|
|
// ========================================================
|
|
// class TransitionNodeStorage
|
|
// ========================================================
|
|
// NodeStorage template interface
|
|
class TransitionNodeStore {
|
|
private:
|
|
list<TransitionAStarNode*> openList;
|
|
set<const Transition*> open;
|
|
set<const Transition*> closed;
|
|
map<const Transition*, TransitionAStarNode*> listed;
|
|
|
|
int size, nodeCount;
|
|
TransitionAStarNode *stock;
|
|
|
|
TransitionAStarNode* getNode();
|
|
void insertIntoOpen(TransitionAStarNode *node);
|
|
bool assertOpen();
|
|
|
|
public:
|
|
TransitionNodeStore(int size) : size(size), stock(NULL) {
|
|
stock = new TransitionAStarNode[size];
|
|
reset();
|
|
}
|
|
~TransitionNodeStore() {
|
|
delete [] stock;
|
|
}
|
|
|
|
void reset() { nodeCount = 0; open.clear(); closed.clear(); openList.clear(); listed.clear(); }
|
|
void setMaxNodes(int limit) { }
|
|
|
|
bool isOpen(const Transition* pos) { return open.find(pos) != open.end(); }
|
|
bool isClosed(const Transition* pos) { return closed.find(pos) != closed.end(); }
|
|
|
|
bool setOpen(const Transition* pos, const Transition* prev, float h, float d);
|
|
void updateOpen(const Transition* pos, const Transition* &prev, const float cost);
|
|
const Transition* getBestCandidate();
|
|
Transition* getBestSeen();
|
|
|
|
float getHeuristicAt(const Transition* &pos) { return listed[pos]->heuristic; }
|
|
float getCostTo(const Transition* pos) { return listed[pos]->distToHere; }
|
|
float getEstimateFor(const Transition* pos) { return listed[pos]->est(); }
|
|
const Transition* getBestTo(const Transition* pos) { return listed[pos]->prev; }
|
|
};
|
|
|
|
|
|
}}
|
|
|
|
#endif
|