You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Lua & Love2D表格加载异常:最后放置的tile随机位移问题

Love2D拖拽Tile释放后随机位移问题修复

我开发的Love2D游戏支持拖拽tile到屏幕指定位置,但释放鼠标后,最后放置的tile会随机位移到屏幕某个位置,点击左上角按钮可复现该问题。

问题代码

local mouseX
local mouseY
local love = require "love"

local placeImg, deleteImg, rotateImg

local mouseleftDown = false

local placeRail = false
local placeNewRail = false

local railArray = {}
local railIndex = 0

function love.load()
    placeRail = true
    -- 全屏设置
    love.window.setFullscreen(true, "desktop")
    placeHolderImg = love.graphics.newImage('PlaceIcon.png')
    placeImg = love.graphics.newImage('PlaceIcon.png')
    deleteImg = love.graphics.newImage('DeleteIcon.png')
end

function love.draw()
    drawIcons()
    if(checkPressed(mouseX, mouseY, 5, 100, 10, 100, 100) and mouseleftDown) then
        placeNewRail = true
    end

    if placeNewRail then
        newRail(placeImg)
    end

    drawRails(placeImg, railArray)
end

function love.update()
    mouseX = love.mouse.getX()
    mouseY = love.mouse.getY()
    if love.mouse.isDown(1) then
        mouseleftDown = true
    else
        mouseleftDown = false
    end
end

function drawIcons()
    love.graphics.draw(placeImg, 100, 10)
    love.graphics.draw(deleteImg, 300, 10)
end

function newRail(image)
    -- 放置轨道
    if placeNewRail then
        currentImgPosX = mouseX
        currentImgPosY = mouseY
        love.graphics.draw(image, mouseX, mouseY)
        if not mouseleftDown then
            table.insert(railArray, railIndex, currentImgPosX)
            table.insert(railArray, railIndex + 1, currentImgPosY)
            railIndex = railIndex + 1
        end
    end
    if not mouseleftDown then
        placeNewRail = false
    end
end

function drawRails(img, arr)
    local array = arr

    local i = 0

    for i in pairs(array) do
        -- 获取数组大小
        i = i + 1
        local _ = 0
        -- 遍历数组绘制元素
        while _ < i do
            love.graphics.draw(img, array[_], array[_+1])
            _ = _ + 1
        end
    end
end

function checkPressed(mouse_x, mouse_y, cursor_radius, button_x, button_y, button_width, button_height)
    if (mouse_x + cursor_radius >= button_x) and (mouse_x - cursor_radius <= 
        button_x + button_width) then
        if (mouse_y + cursor_radius >= button_y) and (mouse_y - cursor_radius <= 
            button_y + button_height) then
                return true
        end
    end
end

function test()
    return true
end

-- 后续用的碰撞检测
function detectCollision(a, b) 
    return a.x < b.x + b.width and
           a.x + a.width > b.x and
           a.y < b.y + b.height and
           a.y + a.height > b.y;
end

问题根源

  1. 数组存储逻辑错误:每次插入x和y两个值,但railIndex只自增1,导致后续插入位置错位、索引混乱。
  2. 绘制函数逻辑完全错误:drawRails用pairs遍历数组,内部嵌套while循环重复绘制,触发索引越界,读取到表中未初始化的无效数据。
  3. 全局变量污染:currentImgPosX和currentImgPosY是全局变量,可能被意外修改导致坐标错误。
  4. 按钮检测位置错误:在love.draw中检测按钮点击,draw函数每帧调用多次,会导致placeNewRail被重复触发,执行多次插入操作。

修复后的代码

local mouseX, mouseY
local love = require "love"

local placeImg, deleteImg, rotateImg

local mouseleftDown = false

local placeRail = false
local placeNewRail = false

-- 改用table存储每个tile的坐标,结构更清晰
local railArray = {}

function love.load()
    placeRail = true
    love.window.setFullscreen(true, "desktop")
    placeHolderImg = love.graphics.newImage('PlaceIcon.png')
    placeImg = love.graphics.newImage('PlaceIcon.png')
    deleteImg = love.graphics.newImage('DeleteIcon.png')
end

function love.draw()
    drawIcons()

    if placeNewRail then
        -- 绘制跟随鼠标的预览tile
        love.graphics.draw(placeImg, mouseX, mouseY)
    end

    drawRails(placeImg, railArray)
end

function love.update()
    mouseX = love.mouse.getX()
    mouseY = love.mouse.getY()
    mouseleftDown = love.mouse.isDown(1)
end

-- 用love的鼠标点击事件检测按钮,避免重复触发
function love.mousepressed(x, y, button)
    if button == 1 then
        if checkPressed(x, y, 5, 100, 10, 100, 100) then
            placeNewRail = true
        end
    end
end

-- 鼠标释放时完成放置
function love.mousereleased(x, y, button)
    if button == 1 and placeNewRail then
        -- 插入当前鼠标坐标作为新tile
        table.insert(railArray, {x = x, y = y})
        placeNewRail = false
    end
end

function drawIcons()
    love.graphics.draw(placeImg, 100, 10)
    love.graphics.draw(deleteImg, 300, 10)
end

function drawRails(img, arr)
    -- 用ipairs遍历顺序数组,每个元素是包含x和y的table
    for _, tile in ipairs(arr) do
        love.graphics.draw(img, tile.x, tile.y)
    end
end

function checkPressed(mouse_x, mouse_y, cursor_radius, button_x, button_y, button_width, button_height)
    return (mouse_x + cursor_radius >= button_x) and 
           (mouse_x - cursor_radius <= button_x + button_width) and
           (mouse_y + cursor_radius >= button_y) and 
           (mouse_y - cursor_radius <= button_y + button_height)
end

function test()
    return true
end

function detectCollision(a, b) 
    return a.x < b.x + b.width and
           a.x + a.width > b.x and
           a.y < b.y + b.height and
           a.y + a.height > b.y;
end

关键修改说明

  • 数组结构优化:railArray存储每个tile的坐标table({x=..., y=...}),避免索引混乱,逻辑更清晰。
  • 事件拆分:把按钮点击检测移到love.mousepressed,放置操作移到love.mousereleased,避免每帧重复触发。
  • 修复绘制逻辑:用ipairs遍历数组,直接读取每个tile的x和y,确保正确绘制所有已放置的tile。
  • 消除全局变量:移除了全局的currentImgPosX/Y,直接使用鼠标释放时的坐标。

内容的提问来源于stack exchange,提问作者robert Vincent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 00:43:22