- added a little extra logic for units when pathfinding. We keep temporary lists of bad cells of harvest resources where a unit simply cannot get to. This is kept for small periods of time and then the bad cell list is purged when data gets old. This tremendously helps units to be more active when getting stuck in challenging places on maps.

This commit is contained in:
Mark Vejvoda 2010-10-17 08:50:27 +00:00
parent 55b4f0bd2b
commit 3d4ccb460c
6 changed files with 153 additions and 42 deletions

View File

@ -173,10 +173,18 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos) {
throw runtime_error("unsupported or missing path finder detected!");
}
}
else if(ts == tsArrived) {
ts = aStar(unit, finalPos);
break;
}
}
}
}
unit->setInBailOutAttempt(false);
if(ts == tsArrived) {
ts = tsBlocked;
}
}
unit->setCurrSkill(scStop);
break;
@ -230,17 +238,20 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){
//if arrived
if(finalPos == unit->getPos()) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) {
string commandDesc = "none";
Command *command= unit->getCurrCommand();
if(command != NULL && command->getCommandType() != NULL) {
commandDesc = command->getCommandType()->toString();
Command *command= unit->getCurrCommand();
if(command == NULL || command->getPos() != unit->getPos()) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) {
string commandDesc = "none";
Command *command= unit->getCurrCommand();
if(command != NULL && command->getCommandType() != NULL) {
commandDesc = command->getCommandType()->toString();
}
char szBuf[1024]="";
sprintf(szBuf,"State: arrived#2 at pos: %s, command [%s]",targetPos.getString().c_str(),commandDesc.c_str());
unit->setCurrentUnitTitle(szBuf);
}
char szBuf[1024]="";
sprintf(szBuf,"State: arrived#2 at pos: %s, command [%s]",targetPos.getString().c_str(),commandDesc.c_str());
unit->setCurrentUnitTitle(szBuf);
return tsArrived;
}
return tsArrived;
}
//path find algorithm
@ -338,8 +349,10 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){
commandDesc = command->getCommandType()->toString();
}
std::pair<Vec2i,Chrono> lastHarvest = unit->getLastHarvestResourceTarget();
char szBuf[1024]="";
sprintf(szBuf,"State: blocked, cmd [%s] pos: %s, dest pos: %s, reason A= %d, B= %d, C= %d, D= %d, E= %d, F = %d",commandDesc.c_str(),unit->getPos().getString().c_str(), targetPos.getString().c_str(),pathFound,(lastNode == firstNode),path->getBlockCount(), path->isBlocked(), nodeLimitReached,path->isStuck());
sprintf(szBuf,"State: blocked, cmd [%s] pos: [%s], dest pos: [%s], lastHarvest = [%s - %lld], reason A= %d, B= %d, C= %d, D= %d, E= %d, F = %d",commandDesc.c_str(),unit->getPos().getString().c_str(), targetPos.getString().c_str(),lastHarvest.first.getString().c_str(),lastHarvest.second.getMillis(), pathFound,(lastNode == firstNode),path->getBlockCount(), path->isBlocked(), nodeLimitReached,path->isStuck());
unit->setCurrentUnitTitle(szBuf);
}

View File

@ -183,6 +183,7 @@ Unit::Unit(int id, UnitPathInterface *unitpath, const Vec2i &pos, const UnitType
this->retryCurrCommandCount=0;
this->screenPos = Vec3f(0.0);
this->inBailOutAttempt = false;
this->lastHarvestResourceTarget.first = Vec2i(0);
level= NULL;
loadType= NULL;
@ -245,6 +246,8 @@ Unit::Unit(int id, UnitPathInterface *unitpath, const Vec2i &pos, const UnitType
Unit::~Unit(){
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] delete unitid = %d\n",__FILE__,__FUNCTION__,__LINE__,id);
badHarvestPosList.clear();
//Just to be sure, should already be removed
if (livingUnits.erase(id)) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
@ -1678,6 +1681,75 @@ void Unit::logSynchData(string source) {
}
}
void Unit::addBadHarvestPos(const Vec2i &value) {
Chrono chron;
chron.start();
badHarvestPosList.push_back(std::pair<Vec2i,Chrono>(value,chron));
cleanupOldBadHarvestPos();
}
void Unit::removeBadHarvestPos(const Vec2i &value) {
for(int i = 0; i < badHarvestPosList.size(); ++i) {
const std::pair<Vec2i,Chrono> &item = badHarvestPosList[i];
if(item.first == value) {
badHarvestPosList.erase(badHarvestPosList.begin() + i);
break;
}
}
cleanupOldBadHarvestPos();
}
bool Unit::isBadHarvestPos(const Vec2i &value) {
cleanupOldBadHarvestPos();
bool result = false;
for(int i = 0; i < badHarvestPosList.size(); ++i) {
const std::pair<Vec2i,Chrono> &item = badHarvestPosList[i];
if(item.first == value) {
result = true;
break;
}
}
return result;
}
void Unit::cleanupOldBadHarvestPos() {
for(int i = badHarvestPosList.size() - 1; i >= 0; --i) {
const std::pair<Vec2i,Chrono> &item = badHarvestPosList[i];
// If this position has been is the list for longer than 120
// seconds remove it so the unit could potentially try it again
if(item.second.getMillis() >= 1200000) {
badHarvestPosList.erase(badHarvestPosList.begin() + i);
}
}
}
void Unit::setLastHarvestResourceTarget(const Vec2i *pos) {
if(pos == NULL) {
lastHarvestResourceTarget.first = Vec2i(0);
//lastHarvestResourceTarget.second = 0;
}
else {
const Vec2i resourceLocation = *pos;
if(resourceLocation != lastHarvestResourceTarget.first) {
lastHarvestResourceTarget.first = resourceLocation;
Chrono chron;
chron.start();
lastHarvestResourceTarget.second = chron;
}
else {
// If we cannot harvest for > 10 seconds tag the position
// as a bad one
if(lastHarvestResourceTarget.second.getMillis() > 10000) {
addBadHarvestPos(resourceLocation);
}
}
}
}
std::string Unit::toString() const {
std::string result = "";

View File

@ -18,9 +18,10 @@
#include "skill_type.h"
#include "game_constants.h"
#include <set>
#include "platform_common.h"
#include "leak_dumper.h"
namespace Glest{ namespace Game{
namespace Glest { namespace Game {
using Shared::Graphics::ParticleSystem;
using Shared::Graphics::UnitParticleSystem;
@ -29,6 +30,7 @@ using Shared::Graphics::Vec2f;
using Shared::Graphics::Vec3f;
using Shared::Graphics::Vec2i;
using Shared::Graphics::Model;
using Shared::PlatformCommon::Chrono;
using std::set;
@ -281,6 +283,13 @@ private:
string currentUnitTitle;
bool inBailOutAttempt;
// This buffer stores a list of bad harvest cells, along with the start
// time of when it was detected. Typically this may be due to a unit
// constantly getting blocked from getting to the resource so this
// list may be used to tell areas of the game to ignore those cells for a
// period of time
std::vector<std::pair<Vec2i,Chrono> > badHarvestPosList;
std::pair<Vec2i,Chrono> lastHarvestResourceTarget;
static Game *game;
@ -426,6 +435,16 @@ public:
bool getInBailOutAttempt() const { return inBailOutAttempt; }
void setInBailOutAttempt(bool value) { inBailOutAttempt = value; }
std::vector<std::pair<Vec2i,Chrono> > getBadHarvestPosList() const { return badHarvestPosList; }
void setBadHarvestPosList(std::vector<std::pair<Vec2i,Chrono> > value) { badHarvestPosList = value; }
void addBadHarvestPos(const Vec2i &value);
void removeBadHarvestPos(const Vec2i &value);
bool isBadHarvestPos(const Vec2i &value);
void cleanupOldBadHarvestPos();
void setLastHarvestResourceTarget(const Vec2i *pos);
std::pair<Vec2i,Chrono> getLastHarvestResourceTarget() const { return lastHarvestResourceTarget;}
std::string toString() const;
private:

View File

@ -249,15 +249,18 @@ bool Map::isInsideSurface(const Vec2i &sPos) const{
}
//returns if there is a resource next to a unit, in "resourcePos" is stored the relative position of the resource
bool Map::isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size) const{
for(int i=-1; i<=size; ++i){
for(int j=-1; j<=size; ++j){
if(isInside(pos.x+i, pos.y+j)){
Resource *r= getSurfaceCell(toSurfCoords(Vec2i(pos.x+i, pos.y+j)))->getResource();
if(r!=NULL){
if(r->getType()==rt){
bool Map::isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size, Unit *unit) const {
for(int i = -1; i <= size; ++i) {
for(int j = -1; j <= size; ++j) {
if(isInside(pos.x + i, pos.y + j)) {
Resource *r= getSurfaceCell(toSurfCoords(Vec2i(pos.x + i, pos.y + j)))->getResource();
if(r != NULL){
if(r->getType() == rt) {
resourcePos= pos + Vec2i(i,j);
return true;
if(unit == NULL || unit->isBadHarvestPos(resourcePos) == false) {
return true;
}
}
}
}

View File

@ -197,7 +197,7 @@ public:
bool isInside(const Vec2i &pos) const;
bool isInsideSurface(int sx, int sy) const;
bool isInsideSurface(const Vec2i &sPos) const;
bool isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size) const;
bool isResourceNear(const Vec2i &pos, const ResourceType *rt, Vec2i &resourcePos, int size, Unit *unit=NULL) const;
bool isResourceNear(const Vec2i &pos, int size, const ResourceType *rt, Vec2i &resourcePos) const;
//free cells

View File

@ -572,7 +572,7 @@ void UnitUpdater::updateBuild(Unit *unit) {
// ==================== updateHarvest ====================
void UnitUpdater::updateHarvest(Unit *unit){
void UnitUpdater::updateHarvest(Unit *unit) {
Chrono chrono;
chrono.start();
@ -585,17 +585,17 @@ void UnitUpdater::updateHarvest(Unit *unit){
if(unit->getCurrSkill()->getClass() != scHarvest) {
//if not working
if(unit->getLoadCount()==0){
if(unit->getLoadCount() == 0) {
//if not loaded go for resources
Resource *r= map->getSurfaceCell(Map::toSurfCoords(command->getPos()))->getResource();
if(r!=NULL && hct->canHarvest(r->getType())){
if(r != NULL && hct->canHarvest(r->getType())) {
//if can harvest dest. pos
bool canHarvestDestPos = false;
switch(this->game->getGameSettings()->getPathFinderType()) {
case pfBasic:
canHarvestDestPos = (unit->getPos().dist(command->getPos())<harvestDistance &&
map->isResourceNear(unit->getPos(), r->getType(), targetPos,unit->getType()->getSize()));
canHarvestDestPos = (unit->getPos().dist(command->getPos()) < harvestDistance &&
map->isResourceNear(unit->getPos(), r->getType(), targetPos,unit->getType()->getSize(),unit));
break;
case pfRoutePlanner:
canHarvestDestPos = map->isResourceNear(unit->getPos(), unit->getType()->getSize(), r->getType(), targetPos);
@ -605,22 +605,24 @@ void UnitUpdater::updateHarvest(Unit *unit){
}
if (canHarvestDestPos == true) {
//if it finds resources it starts harvesting
unit->setCurrSkill(hct->getHarvestSkillType());
unit->setTargetPos(targetPos);
command->setPos(targetPos);
unit->setLoadCount(0);
unit->setLastHarvestResourceTarget(&targetPos);
switch(this->game->getGameSettings()->getPathFinderType()) {
case pfBasic:
unit->setLoadType(map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->getResource()->getType());
break;
case pfRoutePlanner:
unit->setLoadType(r->getType());
break;
default:
throw runtime_error("detected unsupported pathfinder type!");
}
//if it finds resources it starts harvesting
unit->setCurrSkill(hct->getHarvestSkillType());
unit->setTargetPos(targetPos);
command->setPos(targetPos);
unit->setLoadCount(0);
switch(this->game->getGameSettings()->getPathFinderType()) {
case pfBasic:
unit->setLoadType(map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->getResource()->getType());
break;
case pfRoutePlanner:
unit->setLoadType(r->getType());
break;
default:
throw runtime_error("detected unsupported pathfinder type!");
}
}
else {
@ -652,7 +654,7 @@ void UnitUpdater::updateHarvest(Unit *unit){
}
}
}
else{
else {
//if loaded, return to store
Unit *store= world->nearestStore(unit->getPos(), unit->getFaction()->getIndex(), unit->getLoadType());
if(store!=NULL) {
@ -702,8 +704,10 @@ void UnitUpdater::updateHarvest(Unit *unit){
}
}
}
else{
else {
//if working
//unit->setLastHarvestResourceTarget(NULL);
SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()));
Resource *r= sc->getResource();