Tilemap collisions are weird

,

I found this weird thing, and I don't know if it is a bug, but it sure seems like it.
So I made a tilemap, and I'm using that to generate collision boxes for my sprite collisions.
In the image below you can see where the collisions are.
You can also see that dot to the right of the character. That is where the SDK's sprite collision detection claims the character and the top wall are colliding. I think this might have something to do that the collision rectangle is not a square, but I am not sure.

Here is the minimal working bug source code.
pd_collide_test.zip (27.9 KB)

1 Like

Looks like there's a bug in the multi-tile wall building.

Collisions are correct if the wall sprite is just 1 tile
Collisions are offset along the longer axis by 8 pixels if the wall sprite is 2 tiles, 16 pixels if the wall sprite is 3 tiles, 24 pixels if the wall sprite is 4 tiles....

A shorter demo:

import "CoreLibs/sprites"
import "CoreLibs/graphics"

pd = playdate
gfx = pd.graphics

-- ================== Load Resources
hero_img = gfx.image.new("hero")
map_img = gfx.imagetable.new("map")
map_tilemap = gfx.tilemap.new()
map_tilemap:setImageTable(map_img)

map = {2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 2, 2, 2, 2, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 4, 4, 4, 5, 5, 5, 5, 4, 5, 5, 5, 5, 6, 5, 5, 5, 5, 4, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 8, 5, 5, 8, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
       5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5,
       2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
}

map_tilemap:setTiles(map,25)
tile_sprites = gfx.sprite.addWallSprites(map_tilemap, {5})

-- =================== Initialize Global Data
touchy = {}

function DrawBackground()
   map_tilemap:draw(0,0)
end

gfx.setColor(gfx.kColorWhite)
gfx.setBackgroundColor(gfx.kColorBlack)
gfx.setImageDrawMode(gfx.kDrawModeCopy)
gfx.sprite.setBackgroundDrawingCallback(DrawBackground)

hero = gfx.sprite.new(hero_img)
hero:moveTo(100,100)
hero:add()
hero:setCollideRect( 0,0,hero:getSize() )

function playdate.update()
   local move = {x=0, y=0}
   local speed = 4

   if pd.buttonIsPressed(pd.kButtonUp) then
      move.y -= speed
   end
   if pd.buttonIsPressed(pd.kButtonDown) then
      move.y += speed
   end
   if pd.buttonIsPressed(pd.kButtonRight) then
      move.x += speed
   end
   if pd.buttonIsPressed(pd.kButtonLeft) then
      move.x -= speed
   end

   local actualX, actualY, collisions, length = hero:moveWithCollisions(hero.x + move.x, hero.y + move.y)
   
   for i = 1, length do
      print("hero at: " .. hero.x .. ", " .. hero.y)
      print("collision at: " .. collisions[i].touch.x .. ", " .. collisions[i].touch.y)
      table.insert(touchy, {collisions[i].touch.x, collisions[i].touch.y})
   end
   
   hero:moveTo(actualX, actualY)

   gfx.sprite.update()

   for i = 1, #touchy do
      gfx.drawCircleAtPoint(touchy[i][1], touchy[i][2], 3)
   end

end

Huh, sorry about that. I know we fixed some bugs with wall sprites recently, so this might be an inadvertent consequence of those fixes. We'll take a look, thanks!

1 Like

Having the same problem. The red circles mark where data.touch reports that the player character hit the tiles (using moveWithCollision())

Thanks for this. It seems like there may be a different bug here than just the incorrect touch location... would you be able to share this project so I can do some testing? (or just the additional hero and map image files that are being loaded in your sample code)

Okay, I have a fix in now for the incorrect touch point being returned (the same problem existed for the bouce and slide points as well) - thanks for pointing that issue out!

I think the offset wall problem @TheMediocritist mentioned is a different issue that I have so far not been able to reproduce... I'm not sure I completely understand the problem yet.

Thanks for looking into this Dan.
I'm pretty sure your fix is all that's needed. I tried building my own walls from the tilemap collision rects (which are correct) and the issue persisted, so I figure the bug was in the collisions and not the tilemap.

collide_test.zip (32.2 KB)