Search code examples
luacoronasdkpath-findingtouchmove

Highlight a path in a grid


In my grid-based game, The player clicks on a unit then he moves his finger to determine where this unit should move. I'm using the "Jumper" library for the pathfinding. The code for getting the path works perfectly, but the code for highlighting the path, not so much.

local function onTileTouch( event )
    local phase = event.phase
    local tile = event.target


    if ( phase == "began"  ) then
        -- I could create the line here
    elseif ( phase == "moved" ) then
        createPath( tile )

        -- Getting the position of the first tile based on where the unit is
        local t = tiles[currentSelectedUnit.pos.y][currentSelectedUnit.pos.x]

        -- Create the line at the first tile's position
        line = display.newLine( t.x, t.y, t.x, t.y )
        line:setStrokeColor( 1,0,0 )
        line.strokeWidth = 8

        -- "foundPath" is a table of tiles of the correct path
        for i=1,#foundPath do
            line:append( foundPath[i].x,foundPath[i].y )
        end
    elseif ( phase == "ended" or phase == "cancelled" ) then
end

The line doesn't look right when being created in the "moved" phase. It does, however, look very accurate when being created in the "began" phase and then getting appended during the "moved" phase. But in this case, another extra line gets drawn that doesn't follow the path but gets directly from the start tile to the end tile. My second problem with the "began" phase method, is I don't know how to keep deleting the old line and create a new one with for the new correct path.

Let me know if any extra information is needed.


Solution

  • I'm not sure what exactly you want so I have prepared my own version:

    enter image description here

    test.lua

    local composer   = require( 'composer' )
    -- Library setup
    local Grid       = require ( 'jumper.grid' ) -- The grid class
    local Pathfinder = require ( 'jumper.pathfinder' ) -- The pathfinder lass
    
    local scene = composer.newScene()
    
    -- First, set a collision map and value for walkable tiles
    local board  = { 
        tiles = {}, 
        walkable = 0, 
        map = {
            {0,1,0,0,0},
            {0,1,0,1,0},
            {0,1,0,0,0},
            {0,0,0,0,0},
        } 
    }
    
    local function createPath( startx, starty, endx, endy )
    
        -- Creates a grid object
        local grid = Grid( board.map ) 
        -- Creates a pathfinder object using Jump Point Search
        local myFinder = Pathfinder( grid, 'JPS', board.walkable ) 
        -- Calculates the path, and its length
        local path = myFinder:getPath( startx, starty, endx, endy )
    
        return path
    
    end
    
    function scene:create( event )
    
        local sceneGroup = self.view
        local rowNum = #board.map
        local colNum = #board.map[1]
        local width  = 40
        local height = width
        local margin = 5
    
        local function touch( self, event )
    
            local phase = event.phase
            local endTile = event.target
    
            if ( phase == 'began'  ) then
    
                board.startTile = endTile
    
            elseif ( phase == 'moved' ) then
    
                if board.startTile ~= endTile then
    
                    if ( board.endTile ~= endTile ) then
    
                        board.endTile = endTile
    
                        local path = createPath( board.startTile.col, board.startTile.row, board.endTile.col, board.endTile.row )
    
                        if path then
    
                            -- Remove old lines
                            display.remove( board.lines )
                            board.lines = nil           
    
                            -- Create new line
                            board.lines = display.newLine( sceneGroup, board.startTile.x, board.startTile.y, board.startTile.x, board.startTile.y + 1 )
    
                            for node, count in path:nodes() do
    
                                local id = colNum * ( node:getY() - 1 ) + node:getX()
                                local tile = board.tiles[id]
                                board.lines:append( tile.x, tile.y )    
    
                            end 
    
                        end 
    
                    end 
    
                else
    
                    -- Remove old lines
                    display.remove( board.lines )
                    board.lines = nil
                    board.endTile = nil
    
                end 
    
            elseif ( phase == 'ended' or phase == 'cancelled' ) then
    
                -- Remove old lines
                display.remove( board.lines )
                board.lines = nil
                board.endTile = nil
                board.startTile = nil
    
            end 
    
        end 
    
        for i=1, rowNum do
    
            for j=1, colNum do
    
                local tile = display.newRect( sceneGroup, (width + margin ) * j, ( height + margin ) * i, width, height ) 
                tile.col = j 
                tile.row = i 
                tile.touch = touch
                -- Add listener and change color for walkable tile
                if board.map[i][j] == board.walkable then
    
                    tile:addEventListener( 'touch' )
                    tile:setFillColor( 0, 0.5, 0.5 )
    
                end 
    
                local id = colNum * ( i -1 ) + j
                board.tiles[id] = tile
    
            end
    
        end     
    
    end
    
    function scene:show( event )
        local sceneGroup = self.view
        local phase = event.phase
        if phase == 'will' then
    
        elseif phase == 'did' then
    
        end
    end
    
    function scene:hide( event )
        local sceneGroup = self.view
        local phase = event.phase
        if event.phase == 'will' then
    
        elseif phase == 'did' then
    
        end
    end
    
    function scene:destroy( event )
    local sceneGroup = self.view
    
    
    end
    
    scene:addEventListener( 'create', scene )
    scene:addEventListener( 'show', scene )
    scene:addEventListener( 'hide', scene )
    scene:addEventListener( 'destroy', scene )
    
    return scene