From 64e8b9b2b9d9334f79fc6473a54867314e84d541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zieli=C5=84ski?= Date: Fri, 23 Jun 2023 21:43:12 +0200 Subject: [PATCH] Smarter scaling for forces between zones. --- lib/rmg/CZonePlacer.cpp | 63 +++++++++++++++++++++++++++++------------ lib/rmg/CZonePlacer.h | 1 + 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/lib/rmg/CZonePlacer.cpp b/lib/rmg/CZonePlacer.cpp index c82502cdb..77f8ff0d0 100644 --- a/lib/rmg/CZonePlacer.cpp +++ b/lib/rmg/CZonePlacer.cpp @@ -75,9 +75,9 @@ void CZonePlacer::findPathsBetweenZones() for (auto & connection : connectedZoneIds) { - //TODO: Access information about connection type if (connection.getConnectionType() == EConnectionType::EConnectionType::REPULSIVE) { + //Do not consider virtual connections for graph distance continue; } auto neighbor = connection.getOtherZoneId(current); @@ -225,16 +225,7 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand) localDistance = -potentialPos.dist2d(int3(existingX, existingY, 0)); } - //Spread apart player starting zones - if (zone->getOwner() && existingZone->getOwner()) //Players participate in game - { - int firstPlayer = zone->getOwner().value(); - int secondPlayer = existingZone->getOwner().value(); - - //Players with lower indexes (especially 1 and 2) will be placed further apart - - localDistance *= (1.0f + (2.0f / (firstPlayer * secondPlayer))); - } + localDistance *= scaleForceBetweenZones(zone, existingZone); distance += localDistance; } @@ -292,6 +283,23 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand) } } +float CZonePlacer::scaleForceBetweenZones(const std::shared_ptr zoneA, const std::shared_ptr zoneB) const +{ + if (zoneA->getOwner() && zoneB->getOwner()) //Players participate in game + { + int firstPlayer = zoneA->getOwner().value(); + int secondPlayer = zoneB->getOwner().value(); + + //Players with lower indexes (especially 1 and 2) will be placed further apart + + return (1.0f + (2.0f / (firstPlayer * secondPlayer))); + } + else + { + return 1; + } +} + void CZonePlacer::placeZones(CRandomGenerator * rand) { logGlobal->info("Starting zone placement"); @@ -537,7 +545,7 @@ void CZonePlacer::attractConnectedZones(TZoneMap & zones, TForceVector & forces, float3 otherZoneCenter = otherZone->getCenter(); auto distance = static_cast(pos.dist2d(otherZoneCenter)); - forceVector += (otherZoneCenter - pos) * distance * gravityConstant; //positive value + forceVector += (otherZoneCenter - pos) * distance * gravityConstant * scaleForceBetweenZones(zone.second, otherZone); //positive value //Attract zone centers always @@ -579,6 +587,7 @@ void CZonePlacer::separateOverlappingZones(TZoneMap &zones, TForceVector &forces { float3 localForce = (((otherZoneCenter - pos)*(minDistance / (distance ? distance : 1e-3f))) / getDistance(distance)) * stifness; //negative value + localForce *= scaleForceBetweenZones(zone.second, otherZone.second); forceVector -= localForce * (distancesBetweenZones[zone.second->getId()][otherZone.second->getId()] / 2.0f); overlap += (minDistance - distance); //overlapping of small zones hurts us more } @@ -625,7 +634,8 @@ void CZonePlacer::separateOverlappingZones(TZoneMap &zones, TForceVector &forces auto distance = static_cast(pos.dist2d(otherZoneCenter)); float minDistance = (zone.second->getSize() + otherZone->getSize()) / mapSize; float3 localForce = (((otherZoneCenter - pos)*(minDistance / (distance ? distance : 1e-3f))) / getDistance(distance)) * stifness; - forceVector -= localForce * (distancesBetweenZones[zone.second->getId()][otherZone->getId()]); + localForce *= (distancesBetweenZones[zone.second->getId()][otherZone->getId()]); + forceVector -= localForce * scaleForceBetweenZones(zone.second, otherZone); } } @@ -637,7 +647,9 @@ void CZonePlacer::separateOverlappingZones(TZoneMap &zones, TForceVector &forces void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDistanceVector& distances, TDistanceVector& overlaps) { - const int maxDistanceMovementRatio = zones.size() * zones.size(); //The more zones, the greater total distance expected + //The more zones, the greater total distance expected + //Also, higher stiffness make expected movement lower + const int maxDistanceMovementRatio = zones.size() * zones.size() * (stiffnessConstant / stifness); typedef std::pair> Misplacement; std::vector misplacedZones; @@ -666,7 +678,7 @@ void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDista boost::sort(misplacedZones, [](const Misplacement& lhs, Misplacement& rhs) { - return lhs.first > rhs.first; //Biggest first + return lhs.first > rhs.first; //Largest dispalcement first }); logGlobal->trace("Worst misplacement/movement ratio: %3.2f", misplacedZones.front().first); @@ -677,14 +689,24 @@ void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDista auto firstZone = misplacedZones.front().second; std::shared_ptr secondZone; + std::set connectedZones; + for (const auto& connection : firstZone->getConnections()) + { + //FIXME: Should we also exclude fictive connections? + if (connection.getConnectionType() != EConnectionType::EConnectionType::REPULSIVE) + { + connectedZones.insert(connection.getOtherZoneId(firstZone->getId())); + } + } auto level = firstZone->getCenter().z; for (size_t i = 1; i < misplacedZones.size(); i++) { //Only swap zones on the same level //Don't swap zones that should be connected (Jebus) + if (misplacedZones[i].second->getCenter().z == level && - !vstd::contains(firstZone->getConnectedZoneIds(), misplacedZones[i].second->getId())) + !vstd::contains(connectedZones, misplacedZones[i].second->getId())) { secondZone = misplacedZones[i].second; break; @@ -716,9 +738,14 @@ void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDista //Move one zone towards most distant zone to reduce distance float maxDistance = 0; - for (auto con : misplacedZone->getConnectedZoneIds()) + for (auto con : misplacedZone->getConnections()) { - auto otherZone = zones[con]; + if (con.getConnectionType() == EConnectionType::EConnectionType::REPULSIVE) + { + continue; + } + + auto otherZone = zones[con.getOtherZoneId(misplacedZone->getId())]; float distance = static_cast(otherZone->getCenter().dist2dSQ(ourCenter)); if (distance > maxDistance) { diff --git a/lib/rmg/CZonePlacer.h b/lib/rmg/CZonePlacer.h index 28c195509..90b77b8f2 100644 --- a/lib/rmg/CZonePlacer.h +++ b/lib/rmg/CZonePlacer.h @@ -40,6 +40,7 @@ public: void placeZones(CRandomGenerator * rand); void findPathsBetweenZones(); void placeOnGrid(CRandomGenerator* rand); + float scaleForceBetweenZones(const std::shared_ptr zoneA, const std::shared_ptr zoneB) const; void assignZones(CRandomGenerator * rand); const TDistanceMap & getDistanceMap();