Search code examples
lualove2d

How to offset bullet object, based on player's direction


I'm running lua 5.1 and love2d 11.3.0

In my demo, I have a top down shooter game. For visual purposes the character looks like so...As you can see from this top down perspective, he is holding his weapon out.

enter image description here

My issue is that I am having a hard time figuring out how to have his bullets start from the tip of his gun no matter what direction he is facing, or where on the screen he is positioned. Currently, the bullets always shoot from the center of this body. I have tried adjusting the bullet.x and bullet.y properties below, but that is a static change that doesn't respect the players direction...


function spawnBullet()
    local bullet = {}
    bullet.x = player.x
    bullet.y = player.y
    bullet.speed = 500
    bullet.direction = playerMouseAngle()
    table.insert(bullets, bullet)
end

The full game logic :

-- top down shooter game demo 2021

function love.load()

    -- create table to collect sprite assets
    sprites = {}
    sprites.bg = love.graphics.newImage('graphics/bg_grass.jpg')
    sprites.hero = love.graphics.newImage('graphics/hero.png')

    -- create table for our player hero
    player = {}
    player.x = love.graphics.getWidth() / 2
    player.y = love.graphics.getHeight() / 2
    player.speed = 360
    player.injured = false
    player.injuredSpeed = 270

    -- create table for player bullets
    bullets = {}

    -- game state, timer and score globals
    gameState = 1
    maxTime = 2
    timer = maxTime
    score = 0

end

function love.update(dt)

    if gameState == 2 then

        -- player speed will be adjusted below
        local moveSpeed = player.speed

        -- adjust player speed if player was injured
        if player.injured then moveSpeed = player.injuredSpeed end

        -- player moves right
        if love.keyboard.isDown("d") and player.x < love.graphics.getWidth() -
            50 then player.x = player.x + moveSpeed * dt end

        -- player moves left
        if love.keyboard.isDown("a") and player.x > 50 then
            player.x = player.x - moveSpeed * dt
        end

        -- player moves up
        if love.keyboard.isDown("w") and player.y > 50 then
            player.y = player.y - moveSpeed * dt
        end

        -- player moves down
        if love.keyboard.isDown("s") and player.y < love.graphics.getHeight() -
            50 then player.y = player.y + moveSpeed * dt end
    end

    -- make bullets move in desired direction
    for i, b in ipairs(bullets) do
        b.x = b.x + (math.cos(b.direction) * b.speed * dt)
        b.y = b.y + (math.sin(b.direction) * b.speed * dt)
    end

    -- remove the bullets from the game once they go off-screen
    for i = #bullets, 1, -1 do
        local b = bullets[i]
        if b.x < 0 or b.y < 0 or b.x > love.graphics.getWidth() or b.y >
            love.graphics.getHeight() then table.remove(bullets, i) end
    end

    -- manage game state and timer
    if gameState == 2 then
        timer = timer - dt
        if timer <= 0 then
            maxTime = 0.95 * maxTime
            timer = maxTime
        end
    end
end

function love.draw()

    -- setup background
    love.graphics.push()
    love.graphics.scale(0.20, 0.20)
    love.graphics.draw(sprites.bg, 0, 0)
    love.graphics.pop()

    -- click to begin
    if gameState == 1 then
        love.graphics.printf('Click anywhere to begin!', 0, 50, love.graphics.getWidth(), "center")
    end

    -- display score
    love.graphics.printf('Score: ' .. score, 0, love.graphics.getHeight() - 100, love.graphics.getWidth(), "center")

    -- adjust player color if player gets injured
    if player.injured then love.graphics.setColor(1, 0, 0) end
    -- draw player
    love.graphics.draw(sprites.hero, player.x, player.y, playerMouseAngle(),
                       nil, nil, sprites.hero:getWidth() / 2,
                       sprites.hero:getHeight() / 2)

    -- display player bullets
    for i, b in ipairs(bullets) do
        love.graphics.circle("fill", b.x, b.y, 10, 100)
    end
end

-- enable player direction based on mouse movement
function playerMouseAngle()
    return
        math.atan2(player.y - love.mouse.getY(), player.x - love.mouse.getX()) +
            math.pi
end

-- define bullet properties
function spawnBullet()
    local bullet = {}
    bullet.x = player.x
    bullet.y = player.y
    bullet.speed = 500
    bullet.direction = playerMouseAngle()
    table.insert(bullets, bullet)
end

-- game state determins shooting player bullets...
function love.mousepressed(x, y, button)
    if button == 1 and gameState == 2 then
        spawnBullet()
        -- ..or starting the game
    elseif button == 1 and gameState == 1 then
        gameState = 2
        maxTime = 2
        timer = maxTime
        score = 0
    end
end

Thanks in advance for any tips


Solution

  • You already have the required math in there during their travel...

    -- make bullets move in desired direction
    for i, b in ipairs(bullets) do
        b.x = b.x + (math.cos(b.direction) * b.speed * dt)
        b.y = b.y + (math.sin(b.direction) * b.speed * dt)
    end
    

    Just need to tweak it a bit for bullet creation

    local bullet = {}
    bullet.speed = 500
    bullet.direction = playerMouseAngle()
    bullet.x = player.x +(math.cos(bullet.direction + 0.5) * (sprites.hero:getWidth() / 2))
    bullet.y = player.y +(math.sin(bullet.direction + 0.5) * (sprites.hero:getWidth() / 2))
    table.insert(bullets, bullet)
    

    Guessing on the scale. You might have to change the /2 to something else, like *0.75.