- 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:
parent
55b4f0bd2b
commit
3d4ccb460c
|
@ -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,6 +238,8 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){
|
|||
|
||||
//if arrived
|
||||
if(finalPos == unit->getPos()) {
|
||||
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();
|
||||
|
@ -242,6 +252,7 @@ TravelState PathFinder::aStar(Unit *unit, const Vec2i &targetPos){
|
|||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = "";
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -249,20 +249,23 @@ 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);
|
||||
|
||||
if(unit == NULL || unit->isBadHarvestPos(resourcePos) == false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,6 +605,8 @@ void UnitUpdater::updateHarvest(Unit *unit){
|
|||
}
|
||||
|
||||
if (canHarvestDestPos == true) {
|
||||
unit->setLastHarvestResourceTarget(&targetPos);
|
||||
|
||||
//if it finds resources it starts harvesting
|
||||
unit->setCurrSkill(hct->getHarvestSkillType());
|
||||
unit->setTargetPos(targetPos);
|
||||
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue