Implement slope calculation and uphill/downhill step cost in terrainmovementmanager.cpp
This commit is contained in:
@@ -13,7 +13,11 @@ TerrainMovementConfig::TerrainMovementConfig()
|
|||||||
polarSnowLineEnabled(true),
|
polarSnowLineEnabled(true),
|
||||||
polarSnowLineBaseKm(2.5f),
|
polarSnowLineBaseKm(2.5f),
|
||||||
polarSnowFactorStart(0.40f),
|
polarSnowFactorStart(0.40f),
|
||||||
polarSnowFactorEnd(0.85f)
|
polarSnowFactorEnd(0.85f),
|
||||||
|
uphillSlopeMultiplier(4.0f),
|
||||||
|
downhillSlopeBonusMultiplier(2.0f),
|
||||||
|
minStepCost(0.25f),
|
||||||
|
maxClimbableSlopeKm(1.2f)
|
||||||
{
|
{
|
||||||
movementCosts["grasland"] = 1.0f;
|
movementCosts["grasland"] = 1.0f;
|
||||||
movementCosts["bos"] = 2.0f;
|
movementCosts["bos"] = 2.0f;
|
||||||
@@ -74,6 +78,19 @@ bool TerrainMovementManager::loadConfig(const QString &filePath)
|
|||||||
m_config.polarSnowFactorEnd = root["polar_snow_factor_end"].asFloat(0.85f);
|
m_config.polarSnowFactorEnd = root["polar_snow_factor_end"].asFloat(0.85f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (root.hasChild("uphill_slope_multiplier")) {
|
||||||
|
m_config.uphillSlopeMultiplier = root["uphill_slope_multiplier"].asFloat(4.0f);
|
||||||
|
}
|
||||||
|
if (root.hasChild("downhill_slope_bonus_multiplier")) {
|
||||||
|
m_config.downhillSlopeBonusMultiplier = root["downhill_slope_bonus_multiplier"].asFloat(2.0f);
|
||||||
|
}
|
||||||
|
if (root.hasChild("min_step_cost")) {
|
||||||
|
m_config.minStepCost = root["min_step_cost"].asFloat(0.25f);
|
||||||
|
}
|
||||||
|
if (root.hasChild("max_climbable_slope_km")) {
|
||||||
|
m_config.maxClimbableSlopeKm = root["max_climbable_slope_km"].asFloat(1.2f);
|
||||||
|
}
|
||||||
|
|
||||||
if (root.hasChild("movement_costs")) {
|
if (root.hasChild("movement_costs")) {
|
||||||
const YamlNode &costsNode = root["movement_costs"];
|
const YamlNode &costsNode = root["movement_costs"];
|
||||||
for (auto it = costsNode.children.begin(); it != costsNode.children.end(); ++it) {
|
for (auto it = costsNode.children.begin(); it != costsNode.children.end(); ++it) {
|
||||||
@@ -220,3 +237,67 @@ float TerrainMovementManager::getHexMovementCost(int tx, int ty, Matrix2D<Terrai
|
|||||||
QString tType = getTerrainType(tx, ty, mapPoints, numPoints05);
|
QString tType = getTerrainType(tx, ty, mapPoints, numPoints05);
|
||||||
return getTerrainMovementCost(tType);
|
return getTerrainMovementCost(tType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float TerrainMovementManager::getHexElevationKm(int tx, int ty, Matrix2D<TerrainPoint> *mapPoints, int numPoints05) const
|
||||||
|
{
|
||||||
|
if (!mapPoints || numPoints05 <= 0) return 0.0f;
|
||||||
|
|
||||||
|
QVector2D w = Pathfinder::hexToWorld(tx, ty);
|
||||||
|
float scaleX = numPoints05 * 2.0f;
|
||||||
|
float scaleY = numPoints05 / LOD_0_SIZE_Y;
|
||||||
|
|
||||||
|
int mapX = (int) std::round(w.x() * scaleX);
|
||||||
|
int mapY = (int) std::round(w.y() * scaleY);
|
||||||
|
|
||||||
|
if (mapX < 0) mapX = 0;
|
||||||
|
if (mapX >= (int)mapPoints->getWidth()) mapX = (int)mapPoints->getWidth() - 1;
|
||||||
|
if (mapY < 0) mapY = 0;
|
||||||
|
if (mapY >= (int)mapPoints->getHeight()) mapY = (int)mapPoints->getHeight() - 1;
|
||||||
|
|
||||||
|
unsigned char h = mapPoints->operator()(mapX, mapY).height;
|
||||||
|
return (h / 255.0f) * 3.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float TerrainMovementManager::calculateStepCost(
|
||||||
|
int fromX, int fromY,
|
||||||
|
int toX, int toY,
|
||||||
|
MovementDomain domain,
|
||||||
|
Matrix2D<TerrainPoint> *mapPoints,
|
||||||
|
int numPoints05,
|
||||||
|
const UnitConfig *unitConfig) const
|
||||||
|
{
|
||||||
|
// Check general hex passability of destination first
|
||||||
|
if (!isHexPassable(toX, toY, domain, mapPoints, numPoints05, unitConfig)) {
|
||||||
|
return -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toTerrain = getTerrainType(toX, toY, mapPoints, numPoints05);
|
||||||
|
float baseCost = getTerrainMovementCost(toTerrain);
|
||||||
|
|
||||||
|
// Ships only move on flat water
|
||||||
|
if (domain == MovementDomain::Naval) {
|
||||||
|
return baseCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For land units: compute elevation difference
|
||||||
|
float hFrom = getHexElevationKm(fromX, fromY, mapPoints, numPoints05);
|
||||||
|
float hTo = getHexElevationKm(toX, toY, mapPoints, numPoints05);
|
||||||
|
float deltaH = hTo - hFrom; // in kilometers
|
||||||
|
|
||||||
|
// Impassable cliff check
|
||||||
|
if (deltaH > m_config.maxClimbableSlopeKm) {
|
||||||
|
return -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deltaH > 0.001f) {
|
||||||
|
// Uphill penalty: going uphill increases movement cost
|
||||||
|
float penalty = deltaH * m_config.uphillSlopeMultiplier;
|
||||||
|
return baseCost + penalty;
|
||||||
|
} else if (deltaH < -0.001f) {
|
||||||
|
// Downhill bonus: going downhill decreases movement cost (negative penalty)
|
||||||
|
float bonus = (-deltaH) * m_config.downhillSlopeBonusMultiplier;
|
||||||
|
return std::max(m_config.minStepCost, baseCost - bonus);
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseCost;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user