1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Smarter scaling for forces between zones.

This commit is contained in:
Tomasz Zieliński
2023-06-23 21:43:12 +02:00
parent 25707b6d5e
commit 64e8b9b2b9
2 changed files with 46 additions and 18 deletions

View File

@@ -75,9 +75,9 @@ void CZonePlacer::findPathsBetweenZones()
for (auto & connection : connectedZoneIds) for (auto & connection : connectedZoneIds)
{ {
//TODO: Access information about connection type
if (connection.getConnectionType() == EConnectionType::EConnectionType::REPULSIVE) if (connection.getConnectionType() == EConnectionType::EConnectionType::REPULSIVE)
{ {
//Do not consider virtual connections for graph distance
continue; continue;
} }
auto neighbor = connection.getOtherZoneId(current); auto neighbor = connection.getOtherZoneId(current);
@@ -225,16 +225,7 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
localDistance = -potentialPos.dist2d(int3(existingX, existingY, 0)); localDistance = -potentialPos.dist2d(int3(existingX, existingY, 0));
} }
//Spread apart player starting zones localDistance *= scaleForceBetweenZones(zone, existingZone);
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)));
}
distance += localDistance; distance += localDistance;
} }
@@ -292,6 +283,23 @@ void CZonePlacer::placeOnGrid(CRandomGenerator* rand)
} }
} }
float CZonePlacer::scaleForceBetweenZones(const std::shared_ptr<Zone> zoneA, const std::shared_ptr<Zone> 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) void CZonePlacer::placeZones(CRandomGenerator * rand)
{ {
logGlobal->info("Starting zone placement"); logGlobal->info("Starting zone placement");
@@ -537,7 +545,7 @@ void CZonePlacer::attractConnectedZones(TZoneMap & zones, TForceVector & forces,
float3 otherZoneCenter = otherZone->getCenter(); float3 otherZoneCenter = otherZone->getCenter();
auto distance = static_cast<float>(pos.dist2d(otherZoneCenter)); auto distance = static_cast<float>(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 //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; float3 localForce = (((otherZoneCenter - pos)*(minDistance / (distance ? distance : 1e-3f))) / getDistance(distance)) * stifness;
//negative value //negative value
localForce *= scaleForceBetweenZones(zone.second, otherZone.second);
forceVector -= localForce * (distancesBetweenZones[zone.second->getId()][otherZone.second->getId()] / 2.0f); forceVector -= localForce * (distancesBetweenZones[zone.second->getId()][otherZone.second->getId()] / 2.0f);
overlap += (minDistance - distance); //overlapping of small zones hurts us more 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<float>(pos.dist2d(otherZoneCenter)); auto distance = static_cast<float>(pos.dist2d(otherZoneCenter));
float minDistance = (zone.second->getSize() + otherZone->getSize()) / mapSize; float minDistance = (zone.second->getSize() + otherZone->getSize()) / mapSize;
float3 localForce = (((otherZoneCenter - pos)*(minDistance / (distance ? distance : 1e-3f))) / getDistance(distance)) * stifness; 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) 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<float, std::shared_ptr<Zone>> Misplacement; typedef std::pair<float, std::shared_ptr<Zone>> Misplacement;
std::vector<Misplacement> misplacedZones; std::vector<Misplacement> misplacedZones;
@@ -666,7 +678,7 @@ void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDista
boost::sort(misplacedZones, [](const Misplacement& lhs, Misplacement& rhs) 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); 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; auto firstZone = misplacedZones.front().second;
std::shared_ptr<Zone> secondZone; std::shared_ptr<Zone> secondZone;
std::set<TRmgTemplateZoneId> 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; auto level = firstZone->getCenter().z;
for (size_t i = 1; i < misplacedZones.size(); i++) for (size_t i = 1; i < misplacedZones.size(); i++)
{ {
//Only swap zones on the same level //Only swap zones on the same level
//Don't swap zones that should be connected (Jebus) //Don't swap zones that should be connected (Jebus)
if (misplacedZones[i].second->getCenter().z == level && 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; secondZone = misplacedZones[i].second;
break; break;
@@ -716,9 +738,14 @@ void CZonePlacer::moveOneZone(TZoneMap& zones, TForceVector& totalForces, TDista
//Move one zone towards most distant zone to reduce distance //Move one zone towards most distant zone to reduce distance
float maxDistance = 0; 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<float>(otherZone->getCenter().dist2dSQ(ourCenter)); float distance = static_cast<float>(otherZone->getCenter().dist2dSQ(ourCenter));
if (distance > maxDistance) if (distance > maxDistance)
{ {

View File

@@ -40,6 +40,7 @@ public:
void placeZones(CRandomGenerator * rand); void placeZones(CRandomGenerator * rand);
void findPathsBetweenZones(); void findPathsBetweenZones();
void placeOnGrid(CRandomGenerator* rand); void placeOnGrid(CRandomGenerator* rand);
float scaleForceBetweenZones(const std::shared_ptr<Zone> zoneA, const std::shared_ptr<Zone> zoneB) const;
void assignZones(CRandomGenerator * rand); void assignZones(CRandomGenerator * rand);
const TDistanceMap & getDistanceMap(); const TDistanceMap & getDistanceMap();