Board Game Project: Drag and Drop in Lua for Corona SDK

I have been working on a board game type project with drag and drop properties and I have created this class for the pieces of the game.  I have programmed it to move but the picture will not move when I drag.  What do I need to change?

[lua]Piece = {}

function Piece:new(name , x, y, spaces, board)
    self.piece = display.newImage(name, x, y)
    self.x = x
    self.y = y
    self.canMove = true
    self.board = board
    self.spaces = spaces
    return piece
end

function Piece:touch(event)
    if self.canMove == true then
        if event.phase == “began” then
            print(“it worked”)
            self.piece.markX = self.piece.x
            self.piece.markY = self.piece.y
        elseif event.phase == “moved” then
            local x = (event.x - event.xStart) + self.piece.markX
            local y = (event.y - event.yStart) + self.piece.markY
            self.piece.x = x
            self.piece.y = y
        elseif event.phase == “ended” then
            print(“end”)
            if(Piece:canPlace() == true) then
                print( “ta da” )
                Piece:place()
            else
                Piece:removeSelf()
            end
        end
    end
return true
end[/lua]

Don’t worry about the print statements. Those are just to know if the touch is being recognized. Also I did not include the coding for the place() and canPlace() methods. Assume they work. My problem is getting the image to move.

edited:  see comment below, there may be parts missing here.


Ima newb, so you mileage may vary.

No bites, so I’ll try to help a little.

I don’t use “self” in my functions, I always reference my objects directly, so not exactly sure how it works.

if you would consider changing your references from “self” to Piece[i], this should work.  When you get it working, try reverting back to using self.

I would index each “Piece” as it’s spawned so you can reference it easily when touched.  Each “Piece” will now be identifiable as “Piece[i]” --No quotes obviously.  i is the numerical index of each Piece spawned.

Try adding this to the spawn functon…

at top:

i = #Piece + 1

Piece[i]. = display.newImage(name, x, y)

now replace all references of “self” with “Piece[i]”

blah

blah

lower down:

Piece[i].ID = i

return Piece

end

now in your drag functon…

replace all references to “self” and “Piece” with “Piece[i]”

i = event.target.ID

if Piece[i].canMove == true then

blah

blah

end

Piece[i] will now directly reference each object when touched/dragged.  I think this should work and get you going.

Hope this helps,

Nail

Hi @kdog

You say that you have a “piece” class and then mention that you can’t drag the “picture” so are the “pieces” and “picture” the same thing?  I don’t see any code here looking to move a picture, only each individual piece.

develephant, that’s a good one.

After looking at the code again, I would think the “function Piece:touch(event)” should be renamed something like

"function Piece.move:touch(event)

and when each Piece[i] is spawned, the corresponding listener should be added in the spawn function.

Piece[i]:addEventListener(“touch”, Piece.move)

As I said, I don’t use “self” in my funcitons and I never write functions the the above format, I always do it like this because I can call the function in the format below for inside the function itself, where as in the format above, you can’t.

function Piece.move(event)

Nail

So  I have been working on it and I fixed it before I looked at this responses.  This is my new code. Is there and easier way to do this?

Piece = {}

function Piece:new(name , x, y, spaces, board)
    self.name = name
    self.x = x
    self.y = y
    self.canMove = true
    self.board = board
    self.spaces = spaces
    Piece:init()
end

function Piece:init()
    local piece = display.newImage( self.name, self.x, self.y )
    canMove = self.canMove
    function piece:touch(event)
    if canMove == true then
        if event.phase == “began” then
            piece.markX = piece.x
            piece.markY = piece.y
       elseif event.phase == “moved” then
            local x = (event.x - event.xStart) + piece.markX
            local y = (event.y - event.yStart) + piece.markY
            piece.x = x
            piece.y = y
        elseif event.phase == “ended” then
            print(“end”)
            if(Piece:canPlace(piece.x, piece.y) == true) then
                print( “ta da” )
                --Piece:place()
            else
               print( “awww” )
               --Piece:removeSelf()
            end
        end
    end
return true
end
piece:addEventListener( “touch”, piece )
return true
end

Also I am fairly new to lua, but I have learned java.  I have seen other code in lua refered to using self.  Can I refer to the variables without it?  Also please look at the rest of my code to help my fix the following functions

function Piece:place(piece, x, y)
    --these are to find the squares it will be placed on when released

    squarex = math.round((x - 42)/10 + .5)
    squarey = math.round((y - 100)/10 + .5)
    --this is to snap the picture correctly on the board

    piece.x = 42 + squarex*20
    piece.y = 100 + squarey*20

    – this is so the piece can not be moved again
    self.canMove = false
end

function Piece:canPlace(x, y)
    --this is to test the position of the piece

    print( x )
    print( y )
    --this is to find the square it is over

    squarex = math.round((x - 42)/10 - .5)
    squarey = math.round((y - 100)/10 - .5)
    print(squarex)
    print(squarey)
    for i=1,#self.spaces, 1 do
        spacex = self.spaces[i][1] + squarex
        spacey = self.spaces[i][2] + squarey
        if(spacex <=0) then
            return false
        elseif(spacey <=0) then
            return false
        elseif(spacex > 10) then
            return false
        elseif(spacey > 10) then
            return false
        --[[elseif(self.board[spacex][spacey] == true) then
            return false]]–
        end
    end
return true
end

return Piece

In this code, the canPlace() method is trying to test to see if the piece can be placed on the 10x10 board.  The place() method will place the picture in the right spot and stop it from being moved again.

Each piece has a different size and takes up multiple spaces. That is why the canPlace() runs through an array of coordinates.

Nevermind, I have fixed all my methods

Cool!

@xnailbender

As I said, I don’t use “self” in my funcitons and I never write functions the the above format, I always do it like this because I can call the function in the format below for inside the function itself, where as in the format above, you can’t.

 

function Piece.move(event)

Could you elaborate a little bit more on this? I am curious about this approach, and the benefit.  Are you familiar with anonymous functions and closures?  It sounds like that would solve the issue.

@kdog I am glad you got your code working.  As a follow up I would like to point out that using “self” is the right thing to do, but if you don’t understand “scope” or how to work around certain situations, then yes you will have problems.  The idea of “scope” is a difficult one, and even more so in LUA.  I know because it took quite awhile for me to understand to use “self” properly as well.

Though I am only commenting from what code I can see, I would recommend that you think about how to implement certain functionality depending on it’s job.  For instance, the place piece functionality really shouldn’t be on the actual Piece instance, but a separate worker function that handles pieces more generically.  This can also help with scoping issues, for example:

<code>

local function canPlacePiece( Piece )

–Check Piece conditionals here

–return true or false

end

local function placePiece( Piece, x, y )

 if canPlacePiece( Piece ) then
  Piece.x = x
  Piece.y = y
 end

end

local pieces = {} --table of Piece instances

for p=1, #pieces do
 local piece = pieces[p]

 placePiece( piece )
end

</code>

Keep only the most mundane functionality in the Piece itself, more specifically, properties.  If you’re working with multiple objects of the same type try to handle them more generically as a group.  The benefits may not seem obvious, but down the line it will be.

I just happen to love board games (I was the kid who would mess up all the boards games by mixing and matching cards, pieces, and currency to try and make new games) and have made a couple real-world (gamecrafter.com) and app based ones myself.  Again, not seeing your full code, I would think about getting the game working “invisibly” first by structuring the game via objects and tables, and then use that data to render the board.  It’s a much easier approach.

Anyway, maybe some of this helps, and maybe none.  But in either case, good luck on your project.

Cheers.

@develephant

After reading this and encountering a few more problems, I have some more questions.  First of all, when I use a variable in a function like:

local function placePiece( Piece, x, y )

 if canPlacePiece( Piece ) then
  Piece.x = x
  Piece.y = y
 end

end

I am used to Java, where the piece’s x and y would not change, does this change the x and y?

Also, I am wondering about classes in Lua.  Are they traditional classes or just lists of info? Can I create an instant of the class.  I tried to create two pieces with the Piece:new method and when one began to affect another.

@develephant,

disregard my comment above referring to declaring a function format, it is not correct.

The function format “local testFunction3 = function()” cannot be called from within the same function. 

kdog’s formatting of his function declaration’s are fine as is.

@kdog
I’m guessing since I don’t know what your current code is, I still
believe your basic problem is you are not spawning into an indexed
table, your Piece’s have no index reference to identify them so when you drag one, the other may move for instance.

kdog wrote:

I am used to Java, where the piece’s x and y would not change, does this change the x and y?


yes, your function changed the x,y to the param values of x,y.

Nail

@kdog I have actually just ran into a similar issue with the properties being updated on one instance affecting another.  I’m still researching it and will post back my results.

This article demonstrates one possible “class” style framework:

http://www.develephant.net/an-rpg-themed-oop-design-pattern-for-corona-sdk-part-1/

Lua is able to be morphed into many types of coding styles, this is a great things at times, but coming from more structured languages like Java, it may seem counter-intuitive at first.

edited:  see comment below, there may be parts missing here.


Ima newb, so you mileage may vary.

No bites, so I’ll try to help a little.

I don’t use “self” in my functions, I always reference my objects directly, so not exactly sure how it works.

if you would consider changing your references from “self” to Piece[i], this should work.  When you get it working, try reverting back to using self.

I would index each “Piece” as it’s spawned so you can reference it easily when touched.  Each “Piece” will now be identifiable as “Piece[i]” --No quotes obviously.  i is the numerical index of each Piece spawned.

Try adding this to the spawn functon…

at top:

i = #Piece + 1

Piece[i]. = display.newImage(name, x, y)

now replace all references of “self” with “Piece[i]”

blah

blah

lower down:

Piece[i].ID = i

return Piece

end

now in your drag functon…

replace all references to “self” and “Piece” with “Piece[i]”

i = event.target.ID

if Piece[i].canMove == true then

blah

blah

end

Piece[i] will now directly reference each object when touched/dragged.  I think this should work and get you going.

Hope this helps,

Nail

Hi @kdog

You say that you have a “piece” class and then mention that you can’t drag the “picture” so are the “pieces” and “picture” the same thing?  I don’t see any code here looking to move a picture, only each individual piece.

develephant, that’s a good one.

After looking at the code again, I would think the “function Piece:touch(event)” should be renamed something like

"function Piece.move:touch(event)

and when each Piece[i] is spawned, the corresponding listener should be added in the spawn function.

Piece[i]:addEventListener(“touch”, Piece.move)

As I said, I don’t use “self” in my funcitons and I never write functions the the above format, I always do it like this because I can call the function in the format below for inside the function itself, where as in the format above, you can’t.

function Piece.move(event)

Nail

So  I have been working on it and I fixed it before I looked at this responses.  This is my new code. Is there and easier way to do this?

Piece = {}

function Piece:new(name , x, y, spaces, board)
    self.name = name
    self.x = x
    self.y = y
    self.canMove = true
    self.board = board
    self.spaces = spaces
    Piece:init()
end

function Piece:init()
    local piece = display.newImage( self.name, self.x, self.y )
    canMove = self.canMove
    function piece:touch(event)
    if canMove == true then
        if event.phase == “began” then
            piece.markX = piece.x
            piece.markY = piece.y
       elseif event.phase == “moved” then
            local x = (event.x - event.xStart) + piece.markX
            local y = (event.y - event.yStart) + piece.markY
            piece.x = x
            piece.y = y
        elseif event.phase == “ended” then
            print(“end”)
            if(Piece:canPlace(piece.x, piece.y) == true) then
                print( “ta da” )
                --Piece:place()
            else
               print( “awww” )
               --Piece:removeSelf()
            end
        end
    end
return true
end
piece:addEventListener( “touch”, piece )
return true
end

Also I am fairly new to lua, but I have learned java.  I have seen other code in lua refered to using self.  Can I refer to the variables without it?  Also please look at the rest of my code to help my fix the following functions

function Piece:place(piece, x, y)
    --these are to find the squares it will be placed on when released

    squarex = math.round((x - 42)/10 + .5)
    squarey = math.round((y - 100)/10 + .5)
    --this is to snap the picture correctly on the board

    piece.x = 42 + squarex*20
    piece.y = 100 + squarey*20

    – this is so the piece can not be moved again
    self.canMove = false
end

function Piece:canPlace(x, y)
    --this is to test the position of the piece

    print( x )
    print( y )
    --this is to find the square it is over

    squarex = math.round((x - 42)/10 - .5)
    squarey = math.round((y - 100)/10 - .5)
    print(squarex)
    print(squarey)
    for i=1,#self.spaces, 1 do
        spacex = self.spaces[i][1] + squarex
        spacey = self.spaces[i][2] + squarey
        if(spacex <=0) then
            return false
        elseif(spacey <=0) then
            return false
        elseif(spacex > 10) then
            return false
        elseif(spacey > 10) then
            return false
        --[[elseif(self.board[spacex][spacey] == true) then
            return false]]–
        end
    end
return true
end

return Piece

In this code, the canPlace() method is trying to test to see if the piece can be placed on the 10x10 board.  The place() method will place the picture in the right spot and stop it from being moved again.

Each piece has a different size and takes up multiple spaces. That is why the canPlace() runs through an array of coordinates.

Nevermind, I have fixed all my methods

Cool!

@xnailbender

As I said, I don’t use “self” in my funcitons and I never write functions the the above format, I always do it like this because I can call the function in the format below for inside the function itself, where as in the format above, you can’t.

 

function Piece.move(event)

Could you elaborate a little bit more on this? I am curious about this approach, and the benefit.  Are you familiar with anonymous functions and closures?  It sounds like that would solve the issue.

@kdog I am glad you got your code working.  As a follow up I would like to point out that using “self” is the right thing to do, but if you don’t understand “scope” or how to work around certain situations, then yes you will have problems.  The idea of “scope” is a difficult one, and even more so in LUA.  I know because it took quite awhile for me to understand to use “self” properly as well.

Though I am only commenting from what code I can see, I would recommend that you think about how to implement certain functionality depending on it’s job.  For instance, the place piece functionality really shouldn’t be on the actual Piece instance, but a separate worker function that handles pieces more generically.  This can also help with scoping issues, for example:

<code>

local function canPlacePiece( Piece )

–Check Piece conditionals here

–return true or false

end

local function placePiece( Piece, x, y )

 if canPlacePiece( Piece ) then
  Piece.x = x
  Piece.y = y
 end

end

local pieces = {} --table of Piece instances

for p=1, #pieces do
 local piece = pieces[p]

 placePiece( piece )
end

</code>

Keep only the most mundane functionality in the Piece itself, more specifically, properties.  If you’re working with multiple objects of the same type try to handle them more generically as a group.  The benefits may not seem obvious, but down the line it will be.

I just happen to love board games (I was the kid who would mess up all the boards games by mixing and matching cards, pieces, and currency to try and make new games) and have made a couple real-world (gamecrafter.com) and app based ones myself.  Again, not seeing your full code, I would think about getting the game working “invisibly” first by structuring the game via objects and tables, and then use that data to render the board.  It’s a much easier approach.

Anyway, maybe some of this helps, and maybe none.  But in either case, good luck on your project.

Cheers.