Neodigi
Neodigi

Reputation: 193

moving data in a grid

I'm trying to make a chess game but i'm just starting to learn corona, and i'm having some difficulty to move the pieces on the board

here is how I do it:

to make the board:

First i make the full board without any special pieces:

local function MakeBoard()
local boardIndex = 0
for i = 1, tilesAcross do
    if not boardImg[i] then 
        boardImg[i] = {};
    end

    for j = 1, tilesDown do

        boardIndex = boardIndex + 1
        boardImg[i][j] = spawn({image = images[1].getFile , w = tileWidth, h = tileHeight, objTable = spawnTableBoard}) -- board image
        boardImg[i][j].x =  (j - 1) * (tileWidth + tileSpacing) + leftSpacing
        boardImg[i][j].y = (i - 1) * (tileHeight + tileSpacing) + topSpacing
        boardImg[i][j].testx = i
        boardImg[i][j].testy = j
        boardImg[i][j]boardIndex = boardIndex       
    end
end 

Then I put the piece on the board:

local pieceIndex = 0
for i = 1, tilesAcross do
if not pieceImg[i] then 
    pieceImg[i] = {};
end

for j = 1, tilesDown do
    pieceIndex = pieceIndex + 1
    boardIndex = boardIndex + 1
    local imagesId = levels[boardIndex]
    if imagesId ~= 1 then
        pieceImg[i][j] = spawn({image = images[imagesId].getFile , w = tileWidth, h = tileHeight, objTable = spawnTablePiece})
        pieceImg[i][j].x = (j - 1) * (tileWidth + tileSpacing) + leftSpacing
        pieceImg[i][j].y = (i - 1) * (tileHeight + tileSpacing) + topSpacing
        pieceImg[i][j].testx = i
        pieceImg[i][j].testy = j
        pieceImg[i][j].pieceIndex = pieceIndex  
        pieceImg[i][j]:addEventListener("tap", select)
    end
end

In my select event, I add an event on the board where the piece can move(there is a lot of useless thing and useless stuff because I went in so many direction but this is what the important part look like:

local function select(event)
    if selectedpiece == event.target then
        for i = 1, #spawnTableBoard do
            spawnTableBoard[i]:setFillColor( 255,255 )
        end
        selectedpiece = nil -- if you click on the same piece as before, we cancel the selection
    else
        selectedpiece = nil
        for i = 1, #spawnTableBoard do
            spawnTableBoard[i]:setFillColor( 255,255 )
            spawnTableBoard[i]:removeEventListener( "tap", move ) 
        end
        selectedpiece = event.target 
        selectedpiece._x = event.target.testx -- the x value according to the grid
        selectedpiece._y = event.target.testy -- the y value according to the grid

        if piece[selectedpiece._x][selectedpiece._y].testx == levelImg[selectedpiece._x][selectedpiece._y].testx then -- temporary test to check which piece we clicked

            levelImg[levelImg[selectedpiece._x][selectedpiece._y].testx][2]:setFillColor( 255,0,0 ) -- also for testing purpose
            levelImg[1][2]:addEventListener("tap", move)
        end
    end
    return true
end

and then comes my move event, and I guess that the problem come from there, i'm doing a transition to move the piece where the player clicked and it works without problem but if I click on the piece that i just move, i have a bug in my select event where the piece object is nil (the piece object is a global : local piece = {} ) and I can't click on it again, but the other piece are still working, so basically i can move every piece only one time.

I guess it's because when I do the transition the image move but the array is not updated correclty or something like that.

local function move(event)
    if selectedpiece then
        transition.to( selectedpiece, {time = 100, x = spawnTableBoard[event.target.index].x, y = spawnTableBoard[event.target.index].y} )
        selectedpiece.playerIndex = event.target.index
        piece[selectedpiece._x][selectedpiece._y] = selectedpiece

        piece[selectedpiece._x][selectedpiece._y].testx = event.target.testx

        piece[selectedpiece._x][selectedpiece._y].testy = event.target.testy
        for i = 1, #spawnTableBoard do
            spawnTableBoard[i]:setFillColor( 255,255 )
            spawnTableBoard[i]:removeEventListener( "tap", move )
            spawnTableBoard[i]:removeEventListener( "tap", select )
        end
        selectedpiece = nil
    end
end

Any help would be greatly appreciate! Or if i'm going the wrong way with my logic, please let me know.

Upvotes: 1

Views: 140

Answers (1)

Oliver
Oliver

Reputation: 29573

I think it is because you remove the tap event listener in the select function. The code you show doesn't indicate what is spawnTableBoard, but this is where you remove tap listeners. But there are also several other places where things could go wrong: maybe selectedpiece remains nil after a piece that has already been moved is selected, so move does nothing; or maybe select

In terms of logic, you might simplify or clarify your code by thinking in terms of states: after initialization, your game seems to either be in state "waiting for selection", "waiting for destination" or "moving". The 3rd state "moving" implies that until your piece has arrived at destination, your turn is not over. If you have two types of tap listeners, one for pieces, one for squares, then each listener can easily decide what to do based on active state.

For instance, after initialization, the game automatically transitions from "init" to "waiting for piece selection" (set variable currentState='wait for selection'). The "squares" tap handlers would look something like:

local function someSquare:tap(event)
    if currentState == 'wait for piece selection' then
        print('square has nothing to do while waiting for piece selection')

    elif currentState == 'wait for destination' then
        start transition.to with onComplete = function()
                if piece there then remove it
                set new position, updage grid (undo highlight of from/to squares) etc
                transition to 'waiting for piece selection'
            end
        switch state to 'moving piece'

    elif currentState == 'moving piece' then
        if tapped square is same as square of selected piece then cancel transition 

    else 
        error("BUG: unrecognized state")
    end
end

Similarly the piece tap handlers would look like:

local function somePiece:tap(event)
    if currentState == 'wait for piece selection' then
        transitionObj = transition.to(self, {..., onComplete = function()
                if destination has piece then remove it
                set new position of piece
                updage grid (reset highlights etc)
                currentState = 'waiting for piece selection'
            end}
        currentState = 'moving piece'

    elif currentState == 'wait for destination' then
        selectedPiece = nil
        currentState = 'waiting for piece selection'
        inform user that selection cancelled (undo highlight of square, whatever)

    elif currentState == 'moving piece' then
        transition.cancel(transitionObj)
        transitionObj = nil
        -- following lines probably identical to 'wait for destination' so probably put in function
        selectedPiece = nil
        currentState = 'waiting for piece selection'
        inform user that selection cancelled (undo highlight of square, whatever)

    else 
        error("BUG: unrecognized state")
    end
end

This will dramatically cleanup your logic by virtue of the fact that your game is in a known state, so some things are "impossible" and you don't need to test for them (though asserts are handy as sanity checks).

Upvotes: 2

Related Questions