Beispiel #1
0
void Map::FindBestPathToTile( const Unit* unit, const Vec2s& tilePos, Path& result )
{
    std::vector< PrimaryDirection > reverseDirections;
    int searchIndex = ReserveSearchIndex();

    // Clear the list of results.
    result.Clear();
    result.SetOrigin( unit->GetTilePos() );

    // Clear the open list.
    mOpenList.clear();

    // Get the Unit's current Tile and type.
    Iterator originTile = unit->GetTile();
    UnitType* unitType = unit->GetUnitType();
    MovementType* movementType = unit->GetMovementType();

    // Get the starting movement range of the Unit.
    int movementRange = unit->GetMovementRange();

    // Add the origin tile to the open list.
    originTile->Open( searchIndex );
    originTile->SetPreviousTileDirection( PrimaryDirection::NONE );
    originTile->SetBestTotalCostToEnter( 0 );
    mOpenList.insert( 0, originTile );

    while( !mOpenList.isEmpty() )
    {
        // Pop the first element off the open list.
        Map::Iterator tile = mOpenList.popMinElement();

        if( tile.GetPosition() != tilePos )
        {
            // If this isn't the goal tile, close it.
            tile->Close( searchIndex );

            for( int i = 0; i < CARDINAL_DIRECTION_COUNT; ++i )
            {
                // Determine the direction to search.
                PrimaryDirection direction = CARDINAL_DIRECTIONS[ i ];

                // If the adjacent tile isn't in the previous direction, get the adjacent tile.
                Iterator adjacent = tile.GetAdjacent( direction );

                if( adjacent.IsValid() && !adjacent->IsClosed( searchIndex ) )
                {
                    // If the adjacent tile is valid and isn't already closed, get the TerrainType of the adjacent tile.
                    TerrainType* adjacentTerrainType = adjacent->GetTerrainType();

                    if( movementType->CanMoveAcrossTerrain( adjacentTerrainType ) )
                    {
                        // If the adjacent tile is passable, find the total cost of entering the tile.
                        int costToEnterAdjacent = movementType->GetMovementCostAcrossTerrain( adjacentTerrainType );
                        int adjacentTotalCost = ( tile->GetBestTotalCostToEnter() + costToEnterAdjacent );
                        int distanceToGoal = ( originTile.GetPosition().GetManhattanDistanceTo( tilePos ) );
                        int adjacentWeight = ( adjacentTotalCost + distanceToGoal );

                        if( adjacentTotalCost <= movementRange )
                        {
                            if( !adjacent->IsOpen( searchIndex ) )
                            {
                                // If the tile info isn't already on the open list, add it.
                                adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() );
                                adjacent->SetBestTotalCostToEnter( adjacentTotalCost );
                                mOpenList.insert( adjacentWeight, adjacent );
                            }
                            else if( adjacentTotalCost < adjacent->GetBestTotalCostToEnter() )
                            {
                                // If the node is already on the open list but has a larger total cost,
                                // update the value.
                                adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() );
                                adjacent->SetBestTotalCostToEnter( adjacentTotalCost );
                                mOpenList.update( adjacentWeight, adjacent );
                            }
                        }
                    }
                }
            }
        }
        else
        {
            // If this is the goal tile, construct the path to the location.
            PrimaryDirection previousDirection = tile->GetPreviousTileDirection();

            while( previousDirection != PrimaryDirection::NONE )
            {
                // Construct the list of directions from the goal back to the origin tile.
                reverseDirections.push_back( previousDirection );
                tile = tile.GetAdjacent( previousDirection );
                previousDirection = tile->GetPreviousTileDirection();
            }

            // End the search.
            break;
        }
    }

    for( auto it = reverseDirections.rbegin(); it != reverseDirections.rend(); ++it )
    {
        // Construct the path by reversing the directions from the goal to the origin.
        PrimaryDirection direction = *it;
        result.AddDirection( direction.GetOppositeDirection() );
    }
}
Beispiel #2
0
void Map::FindReachableTiles( const Unit* unit, TileSet& result )
{
    int searchIndex = ReserveSearchIndex();

    // Clear the list of results.
    result.clear();

    // Clear the open list.
    mOpenList.clear();

    // Get the Unit's current Tile and type.
    Iterator originTile = unit->GetTile();
    UnitType* unitType = unit->GetUnitType();
    MovementType* movementType = unit->GetMovementType();

    // Get the starting movement range of the Unit.
    int movementRange = unit->GetMovementRange();

    // Add the origin tile to the open list.
    originTile->Open( searchIndex );
    originTile->SetPreviousTileDirection( PrimaryDirection::NONE );
    originTile->SetBestTotalCostToEnter( 0 );
    mOpenList.insert( 0, originTile );

    while( !mOpenList.isEmpty() )
    {
        // Pop the first element off the open list.
        Map::Iterator tile = mOpenList.popMinElement();

        // Close the tile and add it to the result.
        tile->Close( searchIndex );
        result.insert( tile );

        for( int i = 0; i < CARDINAL_DIRECTION_COUNT; ++i )
        {
            // Determine the direction to search.
            PrimaryDirection direction = CARDINAL_DIRECTIONS[ i ];

            // If the adjacent tile isn't in the previous direction, get the adjacent tile.
            Iterator adjacent = tile.GetAdjacent( direction );

            if( adjacent.IsValid() && !adjacent->IsClosed( searchIndex ) )
            {
                // If the adjacent tile is valid and isn't already closed, get the TerrainType of the adjacent tile.
                TerrainType* adjacentTerrainType = adjacent->GetTerrainType();

                if( movementType->CanMoveAcrossTerrain( adjacentTerrainType ) )
                {
                    // If the adjacent tile is passable, find the total cost of entering the tile.
                    int costToEnterAdjacent = movementType->GetMovementCostAcrossTerrain( adjacentTerrainType );
                    int adjacentTotalCost = ( tile->GetBestTotalCostToEnter() + costToEnterAdjacent );

                    if( adjacentTotalCost <= movementRange )
                    {
                        if( !adjacent->IsOpen( searchIndex ) )
                        {
                            // If the tile info isn't already on the open list, add it.
                            adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() );
                            adjacent->SetBestTotalCostToEnter( adjacentTotalCost );
                            mOpenList.insert( adjacentTotalCost, adjacent );
                        }
                        else if( adjacentTotalCost < adjacent->GetBestTotalCostToEnter() )
                        {
                            // If the node is already on the open list but has a larger total cost,
                            // update the value.
                            adjacent->SetPreviousTileDirection( direction.GetOppositeDirection() );
                            adjacent->SetBestTotalCostToEnter( adjacentTotalCost );
                            mOpenList.update( adjacentTotalCost, adjacent );
                        }
                    }
                }
            }
        }
    }
}