Преглед на файлове

Smarter scaling for forces between zones.

Tomasz Zieliński преди 2 години
родител
ревизия
64e8b9b2b9
променени са 2 файла, в които са добавени 46 реда и са изтрити 18 реда
  1. 45 18
      lib/rmg/CZonePlacer.cpp
  2. 1 0
      lib/rmg/CZonePlacer.h

+ 45 - 18
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<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)
 {
 	logGlobal->info("Starting zone placement");
@@ -537,7 +545,7 @@ void CZonePlacer::attractConnectedZones(TZoneMap & zones, TForceVector & forces,
 			float3 otherZoneCenter = otherZone->getCenter();
 			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
 
@@ -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<float>(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<float, std::shared_ptr<Zone>> Misplacement;
 	std::vector<Misplacement> 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<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;
 		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<float>(otherZone->getCenter().dist2dSQ(ourCenter));
 			if (distance > maxDistance)
 			{

+ 1 - 0
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<Zone> zoneA, const std::shared_ptr<Zone> zoneB) const;
 	void assignZones(CRandomGenerator * rand);
 
 	const TDistanceMap & getDistanceMap();