0
votes

I'm new to Lua and coding in general so I decided to write a Chess Program to learn. I have setup a class and created objects from it to represent the pieces. Now I want to begin moving the pieces with my mouse. I looked at a tutorial, but it only handled one rectangle. My first though was to use a "for" loop in the love.mousePressed() function to go though each of the objects until it found an object with a matching x, y coordinate. This obviously did not work the way I did it. Instead, it only goes to the next object every time the mouse is pressed or at least it would if the program didn't immediately crash once the button was released. So my question is, what is the right way to be going about this?

local blackPawn = love.graphics.newImage("Textures/Blackpawn.png")
local blackRook = love.graphics.newImage("Textures/Blackrook.png")
local blackKnight = love.graphics.newImage("Textures/Blackknight.png")
local blackBishop = love.graphics.newImage("Textures/Blackbishop.png")
local blackQueen = love.graphics.newImage("Textures/Blackqueen.png")
local blackKing = love.graphics.newImage("Textures/BlackKing.png")
local whitePawn = love.graphics.newImage("Textures/Whitepawn.png")
local whiteRook = love.graphics.newImage("Textures/Whiterook.png")
local whiteKnight = love.graphics.newImage("Textures/Whiteknight.png")
local whiteBishop = love.graphics.newImage("Textures/Whitebishop.png")
local whiteQueen = love.graphics.newImage("Textures/Whitequeen.png")
local whiteKing = love.graphics.newImage("Textures/WhiteKing.png")
local chessboard = love.graphics.newImage("Textures/ChessBoard.png")

local register = {}

local id = 0

piece = {
    xSquare = 0, ySquare = 0,
    x = 0, y = 0,
    height = 64, width = 64,

    pawn = false,
    Rook = false,
    Knight = false,
    Bishop = false,
    Queen = false,
    King = false,
    color = "",
    texture = whitePawn,

    dragging = {active = false, diffx = 0, diffy = 0}
}

function piece.new()
    newPiece = {}
    for k, v in pairs(piece) do
        newPiece[k] = v
    end
    return newPiece
end

function piece:draw()

end

function getMouse()
    local x, y = love.mouse.getPosition()
    local isDown = love.mouse.isDown(1,2)
        return x, y, isDown
end

function createBoard(id)
    for x = 1, 8 do
        for y = 1, 8 do
            if y ~= 3 and y ~= 4 and y ~=5 and y ~= 6 then
                id = id + 1
                    register[id] = piece.new()
                    register[id].x = x * 64 - 48
                    register[id].y = (y - 1) * 64
                if y == 2 then
                    register[id].pawn = true
                    register[id].color = "white"
                    register[id].texture = whitePawn
                    print("item " .. id .. " is here x = " .. register[id].x  ..  " y = " .. register[id].y .. " Is pawn = " .. tostring(register[id].pawn) ..
                    " Color is " .. register[id].color)
                elseif y == 7 then
                    register[id].pawn = true
                    register[id].color = "black"
                    register[id].texture = blackPawn 
                    print("item " .. id .. " is here x = " .. register[id].x  ..  " y = " .. register[id].y .. " Is pawn = " .. tostring(register[id].pawn) ..
                    " Color is " .. register[id].color) 
                elseif y == 1 then 
                    register[id].color = "white"
                    if x == 1 or x == 8 then 
                        register[id].Rook = true
                        register[id].texture = whiteRook
                    elseif x == 2 or x == 7 then 
                        register[id].Knight = true
                        register[id].texture = whiteKnight
                        print("knight is here")
                    elseif x == 3 or x == 6 then
                        register[id].Bishop = true
                        register[id].texture = whiteBishop
                    elseif x == 5 then
                        register[id].King = true
                        register[id].texture = whiteKing
                    elseif x == 4 then
                        register[id].Queen = true
                        register[id].texture = whiteQueen
                    end
                elseif y == 8 then 
                    register[id].color = "black"
                    if x == 1 or x == 8 then 
                        register[id].Rook = true
                        register[id].texture = blackRook
                    elseif x == 2 or x == 7 then 
                        register[id].Knight = true
                        register[id].texture = blackKnight
                    elseif x == 3 or x == 6 then
                        register[id].Bishop = true
                        register[id].texture = blackBishop
                    elseif x == 5 then
                        register[id].King = true
                        register[id].texture = blackKing
                    elseif x == 4 then
                        register[id].Queen = true
                        register[id].texture = blackQueen
                    end
                end
            end
        end
    end
end

function drawBoard(id, register)
    love.graphics.draw(chessboard, 0, 0)
    for id = 1, 32 do
        love.graphics.draw(register[id].texture, register[id].x, register[id].y)
    end
end

function love.load()
    createBoard(id)
end

function love.update(dt)
    for id = 1, 32 do 
        if register[id].dragging.active == true then
            register[id].x = love.mouse.getX() - register[id].dragging.diffx
            register[id].y = love.mouse.getY() - register[id].dragging.diffy
        end
    end
end

function love.draw()
    drawBoard(id, register)
end

function love.mousepressed(x, y, button)
    for id = 1, 32 do
        if (button  == 1 or button == 2)
        and x > register[id].x and x < register[id].x + register[id].width
        and y > register[id].y and y < register[id].y + register[id].height 
        then
            register[id].dragging.active = true
            register[id].dragging.diffx = x - register[id].x
            register[id].dragging.diffy = y - register[id].y
        end
    end
end

function love.mousereleased(x, y, button)
    for id = 1, 32 do 
        if button == 1 or button == 2 then register[id].dragging.active = false end
    end
end

function love.keypressed(key, unicode)
end

function love.keyreleased(key)

end

function love.focus(bool)

end

function love.quit()
end

Update: I fixed the crashing, but I still have the weird bug where it changes the dragged piece into a different piece

Update 2: After a little more debugging I have figured out that the major issue is that it for some reason does not correctly check if the dragging is active. As the code stands right now I need an else dragging.active = false after to correctly set it, but now that it is correctly set it won't drag anything at all despite the correct object have dragging set to active (unless I try and drag the object with value 32 where it drags everything at once). I am very confused as to what's wrong. Why isn't Lua able to check value like this?

1
We're going to need some more information to really do anything beyond taking a shot in the dark here. What is the error message displayed after you release? What does your code look like? - DavisDude
The problem I'm currently seeing is you're using love.mousepressed() which is only for when a button is initially pressed, and not called until the next press. Change your code to use love.mouse.isDown() instead and it should have your desired effect. - Liam Mueller

1 Answers

0
votes

First, I'd create a global boolean for if a piece has been selected and then a variable to hold the piece selected

local selected = false
local selectedPiece = {}

Then create a playing board and split it into a grid, with each square being of equal size. Something like this

board = {
    size = { 8, 8 }, -- 8x8 grid
    squareSize = 40, -- 40 pixels long sides
    pieces = {
        {   -- First row contains which pieces?
            Piece:Rook(),
            Piece:Bishop(),
            ...
        },

        {   -- Second row
            Piece:Pawn(),
            ...
        },

        {   -- etc.
            Piece:Empty(),
            ...
        }
    }
}

I advise not using nil in your table for empty squares due to the odd behavior of tables with nil indexes.

In your love.mousepressed() method, you check where the click was based on its position (this is assuming the board takes up the whole window)

function love.mousepressed(x, y, btn)
    -- If a piece hasn't been clicked on.
    if (not selected) then
        -- This line is assuming that since all board squares are equal size, then the mouse click has to be in at least one square.
        -- Therefore, if we take the floor of the position/board.squareSize, we will always get a value from 0 - 7 (8 values) on the board.
        local piece = board.pieces[math.floor(x/board.squareSize)][math.floor(y/board.squareSize)]

        -- If there is a piece here.
        if (piece:isNotAnEmpty()) then
            selectedPiece = piece -- Select the piece.
            selected = not selected -- Notify program that a piece is selected to handle such things accordingly in other methods.
        end
    else
        -- Assuming you wrote a method that determines if a piece can be moved to a certain spot on the board.
        if (board:CanMovePieceHere(selectedPiece, x/board.size, y/board.size)) then
            -- Do your stuff here.
            ...

            -- Eventually, reset your variables.
            selected = not selected
            selectedPiece = {}
        end
    end
end

This is how I'd approach it, but your question is very open to interpretation.