Index: source/graphics/TerritoryTexture.cpp =================================================================== --- source/graphics/TerritoryTexture.cpp +++ source/graphics/TerritoryTexture.cpp @@ -92,7 +92,7 @@ return; // Convert size from terrain tiles to territory tiles - m_MapSize = cmpTerrain->GetTilesPerSide() * Pathfinding::NAVCELLS_PER_TILE / ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE; + m_MapSize = cmpTerrain->GetMapSize() * Pathfinding::NAVCELL_SIZE_INT / ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE; m_TextureSize = (GLsizei)round_up_to_pow2((size_t)m_MapSize); Index: source/simulation2/components/CCmpObstructionManager.cpp =================================================================== --- source/simulation2/components/CCmpObstructionManager.cpp +++ source/simulation2/components/CCmpObstructionManager.cpp @@ -20,7 +20,6 @@ #include "simulation2/system/Component.h" #include "ICmpObstructionManager.h" -#include "ICmpTerrain.h" #include "ICmpPosition.h" #include "simulation2/MessageTypes.h" @@ -32,7 +31,6 @@ #include "simulation2/serialization/SerializeTemplates.h" #include "graphics/Overlay.h" -#include "graphics/Terrain.h" #include "maths/MathUtil.h" #include "ps/Profile.h" #include "renderer/Scene.h" @@ -145,7 +143,7 @@ entity_pos_t m_WorldZ0; entity_pos_t m_WorldX1; entity_pos_t m_WorldZ1; - u16 m_TerrainTiles; + u16 m_GridSize; static std::string GetSchema() { @@ -166,7 +164,6 @@ m_PassabilityCircular = false; m_WorldX0 = m_WorldZ0 = m_WorldX1 = m_WorldZ1 = entity_pos_t::Zero(); - m_TerrainTiles = 0; // Initialise with bogus values (these will get replaced when // SetBounds is called) @@ -196,7 +193,6 @@ serialize.NumberFixed_Unbounded("world z0", m_WorldZ0); serialize.NumberFixed_Unbounded("world x1", m_WorldX1); serialize.NumberFixed_Unbounded("world z1", m_WorldZ1); - serialize.NumberU16_Unbounded("terrain tiles", m_TerrainTiles); } virtual void Serialize(ISerializer& serialize) @@ -213,7 +209,8 @@ SerializeCommon(deserialize); - m_UpdateInformations.dirtinessGrid = Grid(m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE, m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE); + i32 size = ((m_WorldX1-m_WorldX0)/Pathfinding::NAVCELL_SIZE_INT).ToInt_RoundToInfinity(); + m_UpdateInformations.dirtinessGrid = Grid(size, size); } virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) @@ -243,12 +240,8 @@ ENSURE(x0.IsZero() && z0.IsZero()); // don't bother implementing non-zero offsets yet ResetSubdivisions(x1, z1); - CmpPtr cmpTerrain(GetSystemEntity()); - if (!cmpTerrain) - return; - - m_TerrainTiles = cmpTerrain->GetTilesPerSide(); - m_UpdateInformations.dirtinessGrid = Grid(m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE, m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE); + i32 size = ((m_WorldX1-m_WorldX0)/Pathfinding::NAVCELL_SIZE_INT).ToInt_RoundToInfinity(); + m_UpdateInformations.dirtinessGrid = Grid(size, size); CmpPtr cmpPathfinder(GetSystemEntity()); if (cmpPathfinder) @@ -259,8 +252,8 @@ { // Use 8x8 tile subdivisions // (TODO: find the optimal number instead of blindly guessing) - m_UnitSubdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); - m_StaticSubdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); + m_UnitSubdivision.Reset(x1, z1, entity_pos_t::FromInt(32)); + m_StaticSubdivision.Reset(x1, z1, entity_pos_t::FromInt(32)); for (std::map::iterator it = m_UnitShapes.begin(); it != m_UnitShapes.end(); ++it) { @@ -555,9 +548,7 @@ inline void MarkDirtinessGrid(const entity_pos_t& x, const entity_pos_t& z, const CFixedVector2D& hbox) { - ENSURE(m_UpdateInformations.dirtinessGrid.m_W == m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE && - m_UpdateInformations.dirtinessGrid.m_H == m_TerrainTiles*Pathfinding::NAVCELLS_PER_TILE); - if (m_TerrainTiles == 0) + if (m_UpdateInformations.dirtinessGrid.m_W == 0) return; u16 j0, j1, i0, i1; Index: source/simulation2/components/CCmpPathfinder.cpp =================================================================== --- source/simulation2/components/CCmpPathfinder.cpp +++ source/simulation2/components/CCmpPathfinder.cpp @@ -45,7 +45,7 @@ void CCmpPathfinder::Init(const CParamNode& UNUSED(paramNode)) { - m_MapSize = 0; + m_GridSize = 0; m_Grid = NULL; m_TerrainOnlyGrid = NULL; @@ -55,7 +55,7 @@ m_AtlasOverlay = NULL; - m_VertexPathfinder = std::unique_ptr(new VertexPathfinder(m_MapSize, m_TerrainOnlyGrid)); + m_VertexPathfinder = std::unique_ptr(new VertexPathfinder(m_GridSize, m_TerrainOnlyGrid)); m_LongPathfinder = std::unique_ptr(new LongPathfinder()); m_PathfinderHier = std::unique_ptr(new HierarchicalPathfinder()); @@ -151,7 +151,7 @@ SerializeVector()(serialize, "long requests", m_LongPathRequests); SerializeVector()(serialize, "short requests", m_ShortPathRequests); serialize.NumberU32_Unbounded("next ticket", m_NextAsyncTicket); - serialize.NumberU16_Unbounded("map size", m_MapSize); + serialize.NumberU16_Unbounded("grid size", m_GridSize); } void CCmpPathfinder::Serialize(ISerializer& serialize) @@ -371,11 +371,13 @@ // avoid integer overflow in intermediate calculation const u16 shoreMax = 32767; + u16 shoreGridSize = terrain.GetTilesPerSide(); + // First pass - find underwater tiles - Grid waterGrid(m_MapSize, m_MapSize); - for (u16 j = 0; j < m_MapSize; ++j) + Grid waterGrid(shoreGridSize, shoreGridSize); + for (u16 j = 0; j < shoreGridSize; ++j) { - for (u16 i = 0; i < m_MapSize; ++i) + for (u16 i = 0; i < shoreGridSize; ++i) { fixed x, z; Pathfinding::TileCenter(i, j, x, z); @@ -386,18 +388,18 @@ } // Second pass - find shore tiles - Grid shoreGrid(m_MapSize, m_MapSize); - for (u16 j = 0; j < m_MapSize; ++j) + Grid shoreGrid(shoreGridSize, shoreGridSize); + for (u16 j = 0; j < shoreGridSize; ++j) { - for (u16 i = 0; i < m_MapSize; ++i) + for (u16 i = 0; i < shoreGridSize; ++i) { // Find a land tile if (!waterGrid.get(i, j)) { // If it's bordered by water, it's a shore tile - if ((i > 0 && waterGrid.get(i-1, j)) || (i > 0 && j < m_MapSize-1 && waterGrid.get(i-1, j+1)) || (i > 0 && j > 0 && waterGrid.get(i-1, j-1)) - || (i < m_MapSize-1 && waterGrid.get(i+1, j)) || (i < m_MapSize-1 && j < m_MapSize-1 && waterGrid.get(i+1, j+1)) || (i < m_MapSize-1 && j > 0 && waterGrid.get(i+1, j-1)) - || (j > 0 && waterGrid.get(i, j-1)) || (j < m_MapSize-1 && waterGrid.get(i, j+1)) + if ((i > 0 && waterGrid.get(i-1, j)) || (i > 0 && j < shoreGridSize-1 && waterGrid.get(i-1, j+1)) || (i > 0 && j > 0 && waterGrid.get(i-1, j-1)) + || (i < shoreGridSize-1 && waterGrid.get(i+1, j)) || (i < shoreGridSize-1 && j < shoreGridSize-1 && waterGrid.get(i+1, j+1)) || (i < shoreGridSize-1 && j > 0 && waterGrid.get(i+1, j-1)) + || (j > 0 && waterGrid.get(i, j-1)) || (j < shoreGridSize-1 && waterGrid.get(i, j+1)) ) shoreGrid.set(i, j, 0); else @@ -410,10 +412,10 @@ } // Expand influences on land to find shore distance - for (u16 y = 0; y < m_MapSize; ++y) + for (u16 y = 0; y < shoreGridSize; ++y) { u16 min = shoreMax; - for (u16 x = 0; x < m_MapSize; ++x) + for (u16 x = 0; x < shoreGridSize; ++x) { if (!waterGrid.get(x, y) || expandOnWater) { @@ -426,7 +428,7 @@ ++min; } } - for (u16 x = m_MapSize; x > 0; --x) + for (u16 x = shoreGridSize; x > 0; --x) { if (!waterGrid.get(x-1, y) || expandOnWater) { @@ -440,10 +442,10 @@ } } } - for (u16 x = 0; x < m_MapSize; ++x) + for (u16 x = 0; x < shoreGridSize; ++x) { u16 min = shoreMax; - for (u16 y = 0; y < m_MapSize; ++y) + for (u16 y = 0; y < shoreGridSize; ++y) { if (!waterGrid.get(x, y) || expandOnWater) { @@ -456,7 +458,7 @@ ++min; } } - for (u16 y = m_MapSize; y > 0; --y) + for (u16 y = shoreGridSize; y > 0; --y) { if (!waterGrid.get(x, y-1) || expandOnWater) { @@ -482,12 +484,12 @@ if (!cmpTerrain) return; // error - u16 terrainSize = cmpTerrain->GetTilesPerSide(); - if (terrainSize == 0) + u16 gridSize = cmpTerrain->GetMapSize() / Pathfinding::NAVCELL_SIZE_INT; + if (gridSize == 0) return; // If the terrain was resized then delete the old grid data - if (m_Grid && m_MapSize != terrainSize) + if (m_Grid && m_GridSize != gridSize) { SAFE_DELETE(m_Grid); SAFE_DELETE(m_TerrainOnlyGrid); @@ -496,12 +498,12 @@ // Initialise the terrain data when first needed if (!m_Grid) { - m_MapSize = terrainSize; - m_Grid = new Grid(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); + m_GridSize = gridSize; + m_Grid = new Grid(m_GridSize, m_GridSize); SAFE_DELETE(m_TerrainOnlyGrid); - m_TerrainOnlyGrid = new Grid(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); + m_TerrainOnlyGrid = new Grid(m_GridSize, m_GridSize); - m_DirtinessInformation = { true, true, Grid(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE) }; + m_DirtinessInformation = { true, true, Grid(m_GridSize, m_GridSize) }; m_AIPathfinderDirtinessInformation = m_DirtinessInformation; m_TerrainDirty = true; @@ -511,7 +513,7 @@ #ifdef NDEBUG ENSURE(m_DirtinessInformation.dirtinessGrid.compare_sizes(m_Grid)); #else - ENSURE(m_DirtinessInformation.dirtinessGrid == Grid(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE)); + ENSURE(m_DirtinessInformation.dirtinessGrid == Grid(m_GridSize, m_GridSize)); #endif CmpPtr cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); @@ -588,21 +590,21 @@ if (terrainSize == 0) return; - const bool needsNewTerrainGrid = !m_TerrainOnlyGrid || m_MapSize != terrainSize; + const bool needsNewTerrainGrid = !m_TerrainOnlyGrid || m_GridSize != terrainSize / Pathfinding::NAVCELL_SIZE_INT; if (needsNewTerrainGrid) { - m_MapSize = terrainSize; + m_GridSize = terrainSize / Pathfinding::NAVCELL_SIZE_INT; SAFE_DELETE(m_TerrainOnlyGrid); - m_TerrainOnlyGrid = new Grid(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); + m_TerrainOnlyGrid = new Grid(m_GridSize, m_GridSize); // If this update comes from a map resizing, we must reinitialize the other grids as well if (!m_TerrainOnlyGrid->compare_sizes(m_Grid)) { SAFE_DELETE(m_Grid); - m_Grid = new Grid(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE); + m_Grid = new Grid(m_GridSize, m_GridSize); - m_DirtinessInformation = { true, true, Grid(m_MapSize * Pathfinding::NAVCELLS_PER_TILE, m_MapSize * Pathfinding::NAVCELLS_PER_TILE) }; + m_DirtinessInformation = { true, true, Grid(m_GridSize, m_GridSize) }; m_AIPathfinderDirtinessInformation = m_DirtinessInformation; } } @@ -612,17 +614,17 @@ const bool partialTerrainGridUpdate = !expandPassability && !needsNewTerrainGrid && itile0 != -1 && jtile0 != -1 && itile1 != -1 && jtile1 != -1; - int istart = 0, iend = m_MapSize * Pathfinding::NAVCELLS_PER_TILE; - int jstart = 0, jend = m_MapSize * Pathfinding::NAVCELLS_PER_TILE; + int istart = 0, iend = m_GridSize; + int jstart = 0, jend = m_GridSize; if (partialTerrainGridUpdate) { // We need to extend the boundaries by 1 tile, because slope and ground // level are calculated by multiple neighboring tiles. // TODO: add CTerrain constant instead of 1. - istart = Clamp(itile0 - 1, 0, static_cast(m_MapSize)) * Pathfinding::NAVCELLS_PER_TILE; - iend = Clamp(itile1 + 1, 0, static_cast(m_MapSize)) * Pathfinding::NAVCELLS_PER_TILE; - jstart = Clamp(jtile0 - 1, 0, static_cast(m_MapSize)) * Pathfinding::NAVCELLS_PER_TILE; - jend = Clamp(jtile1 + 1, 0, static_cast(m_MapSize)) * Pathfinding::NAVCELLS_PER_TILE; + istart = Clamp(itile0 - 1, 0, static_cast(m_GridSize)); + iend = Clamp(itile1 + 1, 0, static_cast(m_GridSize)); + jstart = Clamp(jtile0 - 1, 0, static_cast(m_GridSize)); + jend = Clamp(jtile1 + 1, 0, static_cast(m_GridSize)); } // Compute initial terrain-dependent passability @@ -635,8 +637,8 @@ Pathfinding::NavcellCenter(i, j, x, z); // Terrain-tile coordinates for this navcell - int itile = i / Pathfinding::NAVCELLS_PER_TILE; - int jtile = j / Pathfinding::NAVCELLS_PER_TILE; + int itile = i / Pathfinding::NAVCELLS_PER_TERRAIN_TILE; + int jtile = j / Pathfinding::NAVCELLS_PER_TERRAIN_TILE; // Gather all the data potentially needed to determine passability: @@ -665,7 +667,7 @@ } // Compute off-world passability - const int edgeSize = MAP_EDGE_TILES * Pathfinding::NAVCELLS_PER_TILE; + const int edgeSize = MAP_EDGE_TILES * Pathfinding::NAVCELLS_PER_TERRAIN_TILE; NavcellData edgeMask = 0; for (const PathfinderPassability& passability : m_PassClasses) @@ -880,7 +882,7 @@ PROFILE2("IsGoalReachable"); u16 i, j; - Pathfinding::NearestNavcell(x0, z0, i, j, m_MapSize*Pathfinding::NAVCELLS_PER_TILE, m_MapSize*Pathfinding::NAVCELLS_PER_TILE); + Pathfinding::NearestNavcell(x0, z0, i, j, m_GridSize, m_GridSize); if (!IS_PASSABLE(m_Grid->get(i, j), passClass)) m_PathfinderHier->FindNearestPassableNavcell(i, j, passClass); @@ -919,7 +921,7 @@ // Test against terrain and static obstructions: u16 i, j; - Pathfinding::NearestNavcell(x, z, i, j, m_MapSize*Pathfinding::NAVCELLS_PER_TILE, m_MapSize*Pathfinding::NAVCELLS_PER_TILE); + Pathfinding::NearestNavcell(x, z, i, j, m_GridSize, m_GridSize); if (!IS_PASSABLE(m_Grid->get(i, j), passClass)) return ICmpObstruction::FOUNDATION_CHECK_FAIL_TERRAIN_CLASS; Index: source/simulation2/components/CCmpPathfinder_Common.h =================================================================== --- source/simulation2/components/CCmpPathfinder_Common.h +++ source/simulation2/components/CCmpPathfinder_Common.h @@ -115,7 +115,7 @@ // Lazily-constructed dynamic state (not serialized): - u16 m_MapSize; // tiles per side + u16 m_GridSize; // Navcells per side of the map. Grid* m_Grid; // terrain/passability information Grid* m_TerrainOnlyGrid; // same as m_Grid, but only with terrain, to avoid some recomputations @@ -261,7 +261,7 @@ pass_class_t m_PassClass; AtlasOverlay(const CCmpPathfinder* pathfinder, pass_class_t passClass) : - TerrainTextureOverlay(Pathfinding::NAVCELLS_PER_TILE), m_Pathfinder(pathfinder), m_PassClass(passClass) + TerrainTextureOverlay(Pathfinding::NAVCELLS_PER_TERRAIN_TILE), m_Pathfinder(pathfinder), m_PassClass(passClass) { } Index: source/simulation2/components/CCmpRangeManager.cpp =================================================================== --- source/simulation2/components/CCmpRangeManager.cpp +++ source/simulation2/components/CCmpRangeManager.cpp @@ -1940,7 +1940,7 @@ // Territory data is stored per territory-tile (typically a multiple of terrain-tiles). // LOS data is stored per los tile. - auto scale = [](i32 coord) { return coord * LOS_TILE_SIZE / (ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE*Pathfinding::NAVCELLS_PER_TILE); }; + auto scale = [](i32 coord) { return coord * LOS_TILE_SIZE / (ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE*Pathfinding::NAVCELLS_PER_TERRAIN_TILE); }; // For each territory-tile, if it is owned by a valid player then update the LOS // for every vertex inside/around that tile, to mark them as explored. Index: source/simulation2/components/CCmpTerritoryManager.cpp =================================================================== --- source/simulation2/components/CCmpTerritoryManager.cpp +++ source/simulation2/components/CCmpTerritoryManager.cpp @@ -836,7 +836,7 @@ } TerritoryOverlay::TerritoryOverlay(CCmpTerritoryManager& manager) : - TerrainTextureOverlay((float)Pathfinding::NAVCELLS_PER_TILE / ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE), + TerrainTextureOverlay((float)Pathfinding::NAVCELLS_PER_TERRAIN_TILE / ICmpTerritoryManager::NAVCELLS_PER_TERRITORY_TILE), m_TerritoryManager(manager) { } Index: source/simulation2/components/CCmpUnitMotion.cpp =================================================================== --- source/simulation2/components/CCmpUnitMotion.cpp +++ source/simulation2/components/CCmpUnitMotion.cpp @@ -49,32 +49,32 @@ * Min/Max range to restrict short path queries to. (Larger ranges are (much) slower, * smaller ranges might miss some legitimate routes around large obstacles.) */ -static const entity_pos_t SHORT_PATH_MIN_SEARCH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*3)/2; -static const entity_pos_t SHORT_PATH_MAX_SEARCH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*14); -static const entity_pos_t SHORT_PATH_SEARCH_RANGE_INCREMENT = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*2); +static const entity_pos_t SHORT_PATH_MIN_SEARCH_RANGE = entity_pos_t::FromInt(12)/2; +static const entity_pos_t SHORT_PATH_MAX_SEARCH_RANGE = entity_pos_t::FromInt(56); +static const entity_pos_t SHORT_PATH_SEARCH_RANGE_INCREMENT = entity_pos_t::FromInt(8); /** * When using the short-pathfinder to rejoin a long-path waypoint, aim for a circle of this radius around the waypoint. */ -static const entity_pos_t SHORT_PATH_LONG_WAYPOINT_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*1); +static const entity_pos_t SHORT_PATH_LONG_WAYPOINT_RANGE = entity_pos_t::FromInt(Pathfinding::NAVCELL_SIZE_INT*4); /** * Minimum distance to goal for a long path request */ -static const entity_pos_t LONG_PATH_MIN_DIST = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*4); +static const entity_pos_t LONG_PATH_MIN_DIST = entity_pos_t::FromInt(16); /** * If we are this close to our target entity/point, then think about heading * for it in a straight line instead of pathfinding. */ -static const entity_pos_t DIRECT_PATH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*4); +static const entity_pos_t DIRECT_PATH_RANGE = entity_pos_t::FromInt(16); /** * To avoid recomputing paths too often, have some leeway for target range checks * based on our distance to the target. Increase that incertainty by one navcell * for every this many tiles of distance. */ -static const entity_pos_t TARGET_UNCERTAINTY_MULTIPLIER = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*2); +static const entity_pos_t TARGET_UNCERTAINTY_MULTIPLIER = entity_pos_t::FromInt(8); /** * When following a known imperfect path (i.e. a path that won't take us in range of our goal @@ -1417,7 +1417,7 @@ entity_pos_t goalDistance = moveRequest.m_MaxRange * 2 / 3; // multiply by slightly less than 1/sqrt(2) out.type = PathGoal::SQUARE; - entity_pos_t delta = std::max(goalDistance, m_Clearance + entity_pos_t::FromInt(TERRAIN_TILE_SIZE)/16); // ensure it's far enough to not intersect the building itself + entity_pos_t delta = std::max(goalDistance, m_Clearance + entity_pos_t::FromInt(4)/16); // ensure it's far enough to not intersect the building itself out.hw = targetObstruction.hw + delta; out.hh = targetObstruction.hh + delta; } Index: source/simulation2/components/ICmpRangeManager.h =================================================================== --- source/simulation2/components/ICmpRangeManager.h +++ source/simulation2/components/ICmpRangeManager.h @@ -25,8 +25,6 @@ #include "simulation2/helpers/Position.h" #include "simulation2/helpers/Player.h" -#include "graphics/Terrain.h" // for TERRAIN_TILE_SIZE - class FastSpatialSubdivision; /** Index: source/simulation2/components/tests/test_Pathfinder.h =================================================================== --- source/simulation2/components/tests/test_Pathfinder.h +++ source/simulation2/components/tests/test_Pathfinder.h @@ -200,7 +200,7 @@ sim2.LoadDefaultScripts(); sim2.ResetState(); - const entity_pos_t range = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*12); + const entity_pos_t range = entity_pos_t::FromInt(48); CmpPtr cmpObstructionMan(sim2, SYSTEM_ENTITY); CmpPtr cmpPathfinder(sim2, SYSTEM_ENTITY); @@ -402,7 +402,7 @@ stream << " title='length: " << length << "; tiles explored: " << debugSteps << "; time: " << debugTime*1000 << " msec'"; stream << " class='path' points='"; for (size_t i = 0; i < path.m_Waypoints.size(); ++i) - stream << path.m_Waypoints[i].x.ToDouble()*Pathfinding::NAVCELLS_PER_TILE/TERRAIN_TILE_SIZE << "," << path.m_Waypoints[i].z.ToDouble()*Pathfinding::NAVCELLS_PER_TILE/TERRAIN_TILE_SIZE << " "; + stream << path.m_Waypoints[i].x.ToDouble()*Pathfinding::NAVCELLS_PER_TERRAIN_TILE/TERRAIN_TILE_SIZE << "," << path.m_Waypoints[i].z.ToDouble()*Pathfinding::NAVCELLS_PER_TERRAIN_TILE/TERRAIN_TILE_SIZE << " "; stream << "'/>\n"; } Index: source/simulation2/helpers/HierarchicalPathfinder.h =================================================================== --- source/simulation2/helpers/HierarchicalPathfinder.h +++ source/simulation2/helpers/HierarchicalPathfinder.h @@ -299,7 +299,7 @@ HierarchicalPathfinder& m_PathfinderHier; HierarchicalOverlay(HierarchicalPathfinder& pathfinderHier) : - TerrainTextureOverlay(Pathfinding::NAVCELLS_PER_TILE), m_PathfinderHier(pathfinderHier) + TerrainTextureOverlay(Pathfinding::NAVCELLS_PER_TERRAIN_TILE), m_PathfinderHier(pathfinderHier) { } Index: source/simulation2/helpers/LongPathfinder.h =================================================================== --- source/simulation2/helpers/LongPathfinder.h +++ source/simulation2/helpers/LongPathfinder.h @@ -290,7 +290,7 @@ LongPathfinder& m_Pathfinder; LongOverlay(LongPathfinder& pathfinder) : - TerrainTextureOverlay(Pathfinding::NAVCELLS_PER_TILE), m_Pathfinder(pathfinder) + TerrainTextureOverlay(Pathfinding::NAVCELLS_PER_TERRAIN_TILE), m_Pathfinder(pathfinder) { } Index: source/simulation2/helpers/Pathfinding.h =================================================================== --- source/simulation2/helpers/Pathfinding.h +++ source/simulation2/helpers/Pathfinding.h @@ -137,18 +137,19 @@ * obstructions, all expanded outwards by the radius of the units. * Since units are much smaller than terrain tiles, the nav grid should be * higher resolution than the tiles. - * We therefore split each terrain tile into NxN "nav cells" (for some integer N, + * We therefore split each the world into NxN "nav cells" (for some integer N, * preferably a power of two). */ - const int NAVCELLS_PER_TILE = 4; - - /** - * Size of a navcell in metres ( = TERRAIN_TILE_SIZE / NAVCELLS_PER_TILE) - */ - const fixed NAVCELL_SIZE = fixed::FromInt((int)TERRAIN_TILE_SIZE) / Pathfinding::NAVCELLS_PER_TILE; + const fixed NAVCELL_SIZE = fixed::FromInt(1); const int NAVCELL_SIZE_INT = 1; const int NAVCELL_SIZE_LOG2 = 0; + /** + * The terrain grid is coarser, and it is often convenient to convert from one to the other. + */ + const int NAVCELLS_PER_TERRAIN_TILE = TERRAIN_TILE_SIZE / NAVCELL_SIZE_INT; + static_assert(TERRAIN_TILE_SIZE % NAVCELL_SIZE_INT == 0, "Terrain tile size is not a multiple of navcell size"); + /** * To make sure the long-range pathfinder is more strict than the short-range one, * we need to slightly over-rasterize. So we extend the clearance radius by 1. Index: source/simulation2/helpers/Position.h =================================================================== --- source/simulation2/helpers/Position.h +++ source/simulation2/helpers/Position.h @@ -24,7 +24,7 @@ * @file * Entity coordinate types * - * The basic unit is the "meter". Terrain tiles are TERRAIN_TILE_SIZE (=4) meters square. + * The basic unit is the "meter". * To support deterministic computation across CPU architectures and compilers and * optimisation settings, the C++ simulation code must not use floating-point arithmetic. * We therefore use a fixed-point datatype for representing world positions. Index: source/simulation2/helpers/VertexPathfinder.h =================================================================== --- source/simulation2/helpers/VertexPathfinder.h +++ source/simulation2/helpers/VertexPathfinder.h @@ -72,7 +72,7 @@ class VertexPathfinder { public: - VertexPathfinder(const u16& mapSize, Grid* const & terrainOnlyGrid) : m_MapSize(mapSize), m_TerrainOnlyGrid(terrainOnlyGrid), m_DebugOverlay(false) {}; + VertexPathfinder(const u16& gridSize, Grid* const & terrainOnlyGrid) : m_GridSize(gridSize), m_TerrainOnlyGrid(terrainOnlyGrid), m_DebugOverlay(false) {}; /** * Compute a precise path from the given point to the goal, and return the set of waypoints. @@ -93,7 +93,7 @@ void DebugRenderEdges(const CSimContext& simContext, bool visible, CFixedVector2D curr, CFixedVector2D npos) const; // References to the Pathfinder for convenience. - const u16& m_MapSize; + const u16& m_GridSize; Grid* const & m_TerrainOnlyGrid; std::atomic m_DebugOverlay; Index: source/simulation2/helpers/VertexPathfinder.cpp =================================================================== --- source/simulation2/helpers/VertexPathfinder.cpp +++ source/simulation2/helpers/VertexPathfinder.cpp @@ -662,8 +662,8 @@ // Add terrain obstructions { u16 i0, j0, i1, j1; - Pathfinding::NearestNavcell(rangeXMin, rangeZMin, i0, j0, m_MapSize*Pathfinding::NAVCELLS_PER_TILE, m_MapSize*Pathfinding::NAVCELLS_PER_TILE); - Pathfinding::NearestNavcell(rangeXMax, rangeZMax, i1, j1, m_MapSize*Pathfinding::NAVCELLS_PER_TILE, m_MapSize*Pathfinding::NAVCELLS_PER_TILE); + Pathfinding::NearestNavcell(rangeXMin, rangeZMin, i0, j0, m_GridSize, m_GridSize); + Pathfinding::NearestNavcell(rangeXMax, rangeZMax, i1, j1, m_GridSize, m_GridSize); AddTerrainEdges(m_Edges, m_Vertexes, i0, j0, i1, j1, request.passClass, *m_TerrainOnlyGrid); }