[SOLVED] Tiled collision maps help

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
DudeJonte
Prole
Posts: 4
Joined: Sun Oct 20, 2019 1:14 pm

[SOLVED] Tiled collision maps help

Post by DudeJonte »

Hello dear forum users. Please have mercy on my soul if you dare to help me, as I am new to both Lua and Love2d. I am currently working on a top-down rpg zelda clone-ish. I will try to only show relevant pieces of code so you don't have to look at all of it :P

Importing the map is done via STI. It imports a tilemap done in Tiled. Very simple right? Which is then being updated and drawn to the screen.

Code: Select all

function love.load()
	map = sti("assets/maps/testmapbig.lua", {"box2d"})
end

function love.update(dt)
	map:update(dt)
end

function love.draw()
    	map:draw(-dx, -dy, mapScale, mapScale)
end
Now, the player is being created, updated and drawn in it's own seperate class "player.lua" which looks like this...

Code: Select all

player = {}
player.width = 16
player.height = 23
player.ismoving = false

player.collider = world:newCircleCollider(width/2, height/2, 15)

--Creates a grid table and places spreadsheet into it
player.grids = {}
player.grids.walk = anim8.newGrid(player.width, player.height, sprites.linkSpriteSheet:getDimensions())

--Creates animations out of these grids
player.animations = {}
player.animations.walkDown = anim8.newAnimation(player.grids.walk('1-8', 1), 0.1)
player.animations.walkUp = anim8.newAnimation(player.grids.walk('1-8', 2), 0.1)
player.animations.walkRight = anim8.newAnimation(player.grids.walk('1-8', 3), 0.1)
player.animations.walkLeft = anim8.newAnimation(player.grids.walk('1-8', 4), 0.1)

--Stores players current animation
player.anim = player.animations.walkDown

function player:update(dt)

    --Freeze animation if player isn't moving
    if player.isMoving then
        player.anim:update(dt)
    end

    local vectorX = 0
    local vectorY = 0

    playerX = player.collider:getX()
    playerY = player.collider:getY()

    --Keyboard direction checks for movement and changes animation
    if love.keyboard.isDown("a", "left") then
        vectorX = -1
        player.anim = player.animations.walkLeft
    end

    if love.keyboard.isDown("d", "right") then
        vectorX = 1
        player.anim = player.animations.walkRight
    end

    if love.keyboard.isDown("w", "up") then
        vectorY = -1
        player.anim = player.animations.walkUp
    end

    if love.keyboard.isDown("s", "down") then
        vectorY = 1
        player.anim = player.animations.walkDown
    end

    player.collider:setLinearVelocity(vectorX * 100, vectorY* 100)
    --Checks if player is moving
    --(if players previous position if different from current position)
    if vectorX == 0 and vectorY == 0 then
        player.isMoving = false
        player.anim:gotoFrame(1) -- Go to standing frame in current grid
    else
        player.isMoving = true
    end
end

function player:draw()
    local px = player.collider:getX()
    local py = player.collider:getY()

    --Sets stylesheet filter so scaling doesn't blur
    sprites.linkSpriteSheet:setFilter('nearest', 'nearest')

    --Draws current animation frame
    player.anim:draw(sprites.linkSpriteSheet, px, py, nil, 2, 2, player.width/2, player.height/1.3)
end
Here I am using anim8 to animate the character, and windfield to create a collision box for the player which follows him wherever he goes. Everything so far works just as I want, producing this result if I choose to draw the collision boxes...

The problem comes when I try to implement collisionboxes for my map. The way I've figured out to do this is to loop through every object in my map.lua file an retrieve it's x and y cords. Then the loop also creates a new collision rectangle at those specific coordinates.

Code: Select all

function love.load()
--Gets number of tables(objects) in currently loaded map
    colliderLayer = map.layers[2].objects
    --Loops through all objects and gets their respective x, y values
    --this then creates a new collider rectangle at respective coordinates
    for i, v in pairs(colliderLayer) do
        local colliderObjectX = map.layers[2].objects[i].x
        local colliderObjectY = map.layers[2].objects[i].y
        colliderBox = world:newRectangleCollider(
            (colliderObjectX*2+6), --Multiplies current cordinate by 2 too make up for map scaling in draw()
            (colliderObjectY*2-28), --then adds specific numbers to allign them just perfect
            20,
            25)
        colliderBox:setType('static')
    end
end
This works absolutely fine. The rectangles are placed where I want them to and the player collides with them just fine. The problem arose when I wanted to implement some kind of camera that follows the player around as he moved, scrolling the map accordingly. After testing library after library with my limited understanding for anything I came to this solution, which needed no library whatsoever

Code: Select all

function love.draw()

    dx = player.collider:getX() - (love.graphics.getWidth()/2)
    dy = player.collider:getY() - (love.graphics.getHeight()/2)

    love.graphics.scale(scale)
    love.graphics.translate(-dx, -dy)
    --Scales map to double size to fit screen
    --Draws map and sets new scale
    map:draw(-dx, -dy, mapScale, mapScale)
    player:draw()
    world:draw()
end
This achieves-ish what I want, as now when the player moves, the map does aswell, revealing the rest of the map depending on where you go. NOW, if you are still reading this, MY MAIN PROBLEM that I have been trying to fix for days now is to move my collision map along with my main map.lua. Which will not work the way I want. For some reason I can't post images in here so I will reply to my own post which the needed attachments and source code. Any help would be highly appreciated as I am slowly losing hope for this project.
Last edited by DudeJonte on Mon Oct 21, 2019 7:12 pm, edited 1 time in total.
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Tiled collision maps help

Post by pgimeno »

Hello, welcome to the forums.

Edit: Scratched the request for code because I didn't read all the way to the end, sorry. I await the rest of the code, as I can't make heads or tails from what you've posted so far.
DudeJonte
Prole
Posts: 4
Joined: Sun Oct 20, 2019 1:14 pm

Re: Tiled collision maps help

Post by DudeJonte »

Here I have attached the entire project file plus some images that were supposed to go into the post above. Have a look and don't hesitate to ask if anything is unclear to you. I really appreciate any help :awesome:
Attachments
2D RPG MAYBE.rar
(1.49 MiB) Downloaded 209 times
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Tiled collision maps help

Post by pgimeno »

OK, found the issue, thanks for attaching the project. The problem is that the coordinates that STI requires are map pixels, but you're passing screen pixels to it. Dividing the coordinates by mapScale does the trick:

Code: Select all

    map:draw(-dx/mapScale, -dy/mapScale, mapScale, mapScale)
DudeJonte
Prole
Posts: 4
Joined: Sun Oct 20, 2019 1:14 pm

Re: Tiled collision maps help

Post by DudeJonte »

pgimeno wrote: Mon Oct 21, 2019 10:28 am OK, found the issue, thanks for attaching the project. The problem is that the coordinates that STI requires are map pixels, but you're passing screen pixels to it. Dividing the coordinates by mapScale does the trick:

Code: Select all

    map:draw(-dx/mapScale, -dy/mapScale, mapScale, mapScale)
You my friend, are a lifesaver! This solved my problem. Thank you so much. May I ask one more thing just so I understand what I did wrong? What is the difference between the map pixels that STI requires and the screen pixels that I was passing in? Thank you once again for helping!
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Tiled collision maps help

Post by pgimeno »

DudeJonte wrote: Mon Oct 21, 2019 7:11 pmWhat is the difference between the map pixels that STI requires and the screen pixels that I was passing in?
It's easy to understand the difference. You use a zoom factor of 2, so disregarding translation, each pixel on the map occupies 4 pixels on the screen, as follows:
  • The map pixel at (0, 0) is drawn at screen pixels (0, 0), (1, 0), (0, 1) and (1, 1).
  • The map pixel at (1, 0) is drawn at screen pixels (2, 0), (3, 0), (2, 1) and (3, 1).
  • The map pixel at (2, 0) is drawn at screen pixels (4, 0), (5, 0), (4, 1) and (5, 1).
  • ...
  • The map pixel at (0, 1) is drawn at screen pixels (0, 2), (1, 2), (0, 3) and (1, 3).
  • ...
  • Profit! (kidding)
Your player coordinates are expressed in screen pixels, but STI requires map pixels, therefore you need to convert them, by dividing them by your scale factor, before sending them to STI's draw function.

By the way, this difference in coordinate systems could cause issues later if you're not careful.
DudeJonte
Prole
Posts: 4
Joined: Sun Oct 20, 2019 1:14 pm

Re: Tiled collision maps help

Post by DudeJonte »

pgimeno wrote: Mon Oct 21, 2019 7:58 pm
DudeJonte wrote: Mon Oct 21, 2019 7:11 pmWhat is the difference between the map pixels that STI requires and the screen pixels that I was passing in?
Your player coordinates are expressed in screen pixels, but STI requires map pixels, therefore you need to convert them, by dividing them by your scale factor, before sending them to STI's draw function.

By the way, this difference in coordinate systems could cause issues later if you're not careful.
Thanks a lot for the explanation. And as you say, different coordinate systems have already been driving me a little crazy sometimes. I'm gonna try to figure out a solution for this at some point. But thank you once again for your help. Have a good one!
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot], Google [Bot] and 50 guests