1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Significantly improved zone graph placement.

This commit is contained in:
DjWarmonger 2014-10-31 12:58:55 +01:00
parent 697e42dd24
commit 7ac3713d32
3 changed files with 64 additions and 7 deletions

View File

@ -473,11 +473,11 @@ int CMapGenerator::getNextMonlithIndex()
{
if (monolithIndex >= VLC->objtypeh->knownSubObjects(Obj::MONOLITH_TWO_WAY).size())
{
logGlobal->errorStream() << boost::to_string(boost::format("RMG Error! There is no Monolith Two Way with index %d available!") % monolithIndex);
monolithIndex++;
return VLC->objtypeh->knownSubObjects(Obj::MONOLITH_TWO_WAY).size() - 1;
//logGlobal->errorStream() << boost::to_string(boost::format("RMG Error! There is no Monolith Two Way with index %d available!") % monolithIndex);
//monolithIndex++;
//return VLC->objtypeh->knownSubObjects(Obj::MONOLITH_TWO_WAY).size() - 1;
//TODO: interrupt map generation and report error
//throw rmgException(boost::to_string(boost::format("There is no Monolith Two Way with index %d available!") % monolithIndex));
throw rmgException(boost::to_string(boost::format("There is no Monolith Two Way with index %d available!") % monolithIndex));
}
else
return monolithIndex++;

View File

@ -107,12 +107,14 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
};
std::map <CRmgTemplateZone *, float3> forces;
std::map <CRmgTemplateZone *, float> distances;
while (zoneScale < 1) //until zones reach their desired size and fill the map tightly
{
for (auto zone : zones)
{
float3 forceVector(0,0,0);
float3 pos = zone.second->getCenter();
float totalDistance = 0;
//attract connected zones
for (auto con : zone.second->getConnections())
@ -124,9 +126,11 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
if (distance > minDistance)
{
//WARNING: compiler used to 'optimize' that line so it never actually worked
forceVector += (((otherZoneCenter - pos) / getDistance(distance))); //positive value
forceVector += (((otherZoneCenter - pos)*(pos.z != otherZoneCenter.z ? (distance - minDistance) : 1)/ getDistance(distance))); //positive value
totalDistance += distance;
}
}
distances[zone.second] = totalDistance;
//separate overlaping zones
for (auto otherZone : zones)
{
@ -139,7 +143,7 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
float minDistance = (zone.second->getSize() + otherZone.second->getSize())/mapSize * zoneScale;
if (distance < minDistance)
{
forceVector -= (otherZoneCenter - pos) / getDistance(distance); //negative value
forceVector -= (((otherZoneCenter - pos)*(minDistance - distance)) / getDistance(distance)); //negative value
}
}
@ -178,7 +182,52 @@ void CZonePlacer::placeZones(const CMapGenOptions * mapGenOptions, CRandomGenera
{
zone.first->setCenter (zone.first->getCenter() + zone.second);
}
zoneScale *= inflateModifier; //increase size
//now perform drastic movement of zone that is completely not linked
float maxRatio = 0;
CRmgTemplateZone * distantZone = nullptr;
float totalDistance = 0;
for (auto zone : distances) //find most misplaced zone
{
totalDistance += zone.second;
float ratio = zone.second / forces[zone.first].mag(); //if distance to actual movement is long, the zone is misplaced
if (ratio > maxRatio)
{
maxRatio = ratio;
distantZone = zone.first;
}
}
logGlobal->traceStream() << boost::format("Total distance between zones in this iteration: %2.2f, Worst distance/movement ratio: %3.2f") % totalDistance % maxRatio;
if (maxRatio > 100) //TODO: scale?
{
//find most distant zone that should be attracted and move inside it
CRmgTemplateZone * targetZone = nullptr;
float maxDistance = 0;
float3 ourCenter = distantZone->getCenter();
for (auto con : distantZone->getConnections())
{
auto otherZone = zones[con];
float distance = otherZone->getCenter().dist2dSQ(ourCenter);
if (distance > maxDistance)
{
maxDistance = distance;
targetZone = otherZone;
}
}
float3 vec = targetZone->getCenter() - ourCenter;
float newDistanceBetweenZones = (std::max (distantZone->getSize(),targetZone->getSize())) * zoneScale / mapSize;
logGlobal->traceStream() << boost::format("Trying to move zone %d %s towards %d %s. Old distance %f") %
distantZone->getId() % ourCenter() % targetZone->getId() % targetZone->getCenter()() % maxDistance;
logGlobal->traceStream() << boost::format("direction is %s") % vec();
distantZone->setCenter(targetZone->getCenter() - vec.unitVector() * newDistanceBetweenZones); //zones should now overlap by half size
logGlobal->traceStream() << boost::format("New distance %f") % targetZone->getCenter().dist2d(distantZone->getCenter());
}
zoneScale *= inflateModifier; //increase size of zones so they
}
for (auto zone : zones) //finalize zone positions
{

View File

@ -47,6 +47,14 @@ public:
const double dy = (y - o.y);
return dx*dx + dy*dy;
}
double mag() const
{
return sqrt(x*x + y*y);
}
float3 unitVector() const
{
return float3(x, y, z) / mag();
}
// returns distance on Oxy plane (z coord is not used)
double dist2d(const float3 &other) const { return std::sqrt(dist2dSQ(other)); }