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

基于LÖVE2D的射击游戏角色朝向鼠标光标问题求助

解决LÖVE2D角色朝向鼠标的问题

原代码存在的核心问题

  • 鼠标坐标未转换:使用push虚拟分辨率时,窗口坐标和虚拟坐标不匹配,直接调用love.mouse.getX()会导致瞄准偏移,需用push:toGame()转换。
  • 角色位置初始化错误:love.graphics.getWidth()在push:setupScreen()前调用,获取的是窗口尺寸而非虚拟尺寸,且应将角色位置设置在虚拟画布中心。
  • draw参数顺序错误:love.graphics.draw的旋转参数应在位置之后,原点参数在缩放之后,原代码参数顺序完全颠倒,导致旋转失效。
  • 角度单位错误:LÖVE的旋转使用弧度,原代码将atan2的结果转成角度传入,会导致旋转异常。
  • 游戏状态逻辑缺失:未处理空格按键切换状态,且角色绘制在push:apply('end')之后,不在虚拟画布上显示。

修正后的完整代码

local data = {}
push = require 'push'
Class = require 'class'
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720

VIRTUAL_WIDTH = 432
VIRTUAL_HEIGHT = 243

function love.load()
    love.graphics.setDefaultFilter('nearest', 'nearest')
    love.window.setTitle('Alien Shooter')
    math.randomseed(os.time())
    
    -- 初始化字体
    smallFont = love.graphics.newFont('font.ttf', 8)
    largeFont = love.graphics.newFont('font.ttf', 16)
    scoreFont = love.graphics.newFont('font.ttf', 32)
    love.graphics.setFont(smallFont)
    
    PlayerScore = 0
    
    -- 先初始化push,再设置角色位置
    push:setupScreen(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT, {
        fullscreen = false,
        resizable = true,
        vsync = true
    })
    
    -- 加载角色 sprite 并设置初始位置(虚拟画布中心)
    MCSprite = love.graphics.newImage("MC.png")
    data.width = MCSprite:getWidth()
    data.height = MCSprite:getHeight()
    data.x = VIRTUAL_WIDTH / 2 
    data.y = VIRTUAL_HEIGHT / 2
    data.originX = data.width / 2
    data.originY = data.height / 2
    
    gameState = 'start'
end

function love.resize(w, h)
    push:resize(w, h)
end

function love.update(dt)
    if gameState == 'play' then
        -- 将鼠标窗口坐标转换为虚拟坐标
        local mouseX, mouseY = push:toGame(love.mouse.getX(), love.mouse.getY())
        -- 计算角色到鼠标的角度(弧度,LÖVE默认使用弧度)
        if mouseX and mouseY then -- 确保鼠标在虚拟画布内
            local dx = mouseX - data.x
            local dy = mouseY - data.y
            data.angle = math.atan2(dy, dx)
        end
    end
end

function love.keypressed(key)
    if key == 'escape' then
        love.event.quit()
    elseif key == 'space' then
        -- 切换游戏状态
        gameState = gameState == 'start' and 'play' or 'start'
    end
end

function love.draw()
    push:apply('start')
    
    if gameState == 'start' then
        -- 开始界面绘制
        love.graphics.printf('ALIEN SHOOTER!', 0, VIRTUAL_HEIGHT / 2 - 6, VIRTUAL_WIDTH, 'center')
        love.graphics.printf('Press SPACE to Start!', 0, VIRTUAL_HEIGHT / 2 + 12, VIRTUAL_WIDTH, 'center')
    else
        -- 游戏界面绘制:角色朝向鼠标
        love.graphics.draw(MCSprite, data.x, data.y, data.angle, 1, 1, data.originX, data.originY)
        -- 可选:显示分数
        love.graphics.setFont(scoreFont)
        love.graphics.print(tostring(PlayerScore), VIRTUAL_WIDTH - 50, 10)
    end
    
    push:apply('end')
end

关键修正说明

  1. 坐标转换:用push:toGame()将鼠标的窗口坐标转为虚拟坐标,确保瞄准位置和角色在同一坐标系。
  2. 角色位置:在push初始化后,基于VIRTUAL_WIDTH和VIRTUAL_HEIGHT设置角色中心位置,保证在虚拟画布内。
  3. draw参数顺序:修正为(图像, x, y, 旋转弧度, 缩放X, 缩放Y, 原点X, 原点Y),让旋转和原点偏移生效。
  4. 角度计算:直接使用math.atan2(dy, dx)的弧度结果,无需转角度,匹配LÖVE的旋转要求。
  5. 状态切换:添加空格按键切换start/play状态,角色仅在play状态下绘制并更新瞄准逻辑。

内容的提问来源于stack exchange,提问作者Ahmet Talha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 03:27:03