Help with tilemap, collision, and movement

I'm really stuggling with tilemaps. I have two problems, but first some context. I've fumbled my way around enough to get some on screen. I have a sprite in too.

problem 1: Collision
I'm using addWallSprites, when I do though, it only adds one big block around my whole tilemap. I wanted it to be 16x16 blocks.

image

problem2: tilemap movement with collisions
I'm able to move my sprite no problem using moveWithCollisions. But tilemap doesn't have that. In the above screenshot. I am able to move the tileset where ever I want, but the collision stays in place making it usless.

I've seen some demos around that show it's possible to do this, but it's not clear from the documentation as to how.

Demo Code here, if anyone has any advice that would be awesome.

import "CoreLibs/sprites"
gfx = playdate.graphics

-- playdate.display.setScale(2)

tiles = gfx.imagetable.new('assets/link/rprite')

map = gfx.tilemap.new()
map:setImageTable(tiles)
map:setSize(16,16)
-- map:setTiles({0,0,1,1}, 16)
-- map:setZIndex(100)

s = gfx.sprite.new(gfx.image.new('assets/link/s1'))
s:add()
s:moveTo(15, 15)
s:setCollideRect(0, 0, s:getSize())

-- s:setZIndex(300)

for y = 5,10 do
	for x = 1, 16 do
		map:setTileAtPosition(x, y, 1)
	end
end
-- s.addEmptyCollisionSprite(22, 22,16,16)
print(map:getTileAtPosition(1, 1))

function s:collisions()
	local collisions = self:overlappingSprites() 
 
    -- for c = 1, #collisions do
	-- 	local collisionPair = collisions[c]
    --     local sprite1 = collisionPair[1]
    --     local sprite2 = collisionPair[2]
		
	-- 	print("sprite1: ",sprite1)
	-- 	print("sprite2: ", sprite2)
	-- 	print("collisions",collisionPair)
	-- 	collisionPair:remove()
	-- 	if sprite1 == 1 then
	-- 		sprite1 = 0
	-- 	end

	-- 	if sprite2 == 1 then
	-- 		print(sprite2)
	-- 		sprite2:remove()
	-- 	end
	-- 	--print(c)
	-- end
end
s.addWallSprites(map, {2, 3},16,0)

x = 0
y = 0

leftdown = false
rightdown = false
updown = false
downdown = false

-- gfx.sprite.addWallSprites()
a = 0
b = 0

function playdate.update()

	-- if leftdown then x = x + 3 end
	-- if rightdown then x = x - 3 end
	-- if updown then y = y + 3 end
	-- if downdown then y = y - 3 end

	if leftdown then a = -3 b = 0 end
	if rightdown then a = 3 b = 0 end
	if updown then a = 0 b = -3 end
	if downdown then a =  0 b = 3 end

	-- gfx.setColor(gfx.kColorWhite)
	-- gfx.fillRect(0,0,50,40)
	
	gfx.sprite.update()
	s:moveWithCollisions(s.x,s.y)

	s:moveBy(a, b)
	 map:draw(15,1)
	s:collisions()
	--  c = [x , y]
	--  gfx.sprite.addWallSprites(map, 2, {x, y})
	-- map:moveWithCollisions(map.x,map.y)
	
end

function playdate.leftButtonDown()	leftdown = true		end
function playdate.leftButtonUp()	leftdown = false	end
function playdate.rightButtonDown()	rightdown = true	end
function playdate.rightButtonUp()	rightdown = false	end
function playdate.upButtonDown()	updown = true		end
function playdate.upButtonUp()		updown = false		end
function playdate.downButtonDown()	downdown = true		end
function playdate.downButtonUp()	downdown = false	end

I found a clue, if I randomize the indexes it does work the way I think it should. it's only due to the whole thing being all one index does it assume I want the whole thing to have a one collision box.

image

On further inspection I see that those with similar indexes are still grouped together.... still more searching to do.

It optimizes the collision to merge rectangles, having a hundred separate collision rects can be painful on performance

I was looking at this post here

it shows similar tiles, but act independently. and the map moves with the collision so... I'm a bit confused on how it's pulled off.

I have been summoned! I'll try to explain my own project's structure (also maybe I should update it in the future...) if it can help you understand it.

Note that I'm only using C for this project, so the API and the function names might be different. I don't know how to work with the Lua API yet. Sorry in advance.
In my project, the world map's sprites dont move, I make everything "move" by using draw offsets, in a similar system than having a camera pan over the world (I also add/remove chunks of sprites on the fly but that out of the scope of the topic right now).

Setting a draw offset here is a bit like moving where the pixel (0;0) would be related to the top-left of your screen. For instance, try playing with it in a side-project where you'd draw something to locate where (0;0).

I looked up the SDK, If you open up the Level 1-1 sample, there is some code in level.lua to handle the sample's level scrolling, it looks pretty close to what I'm doing, minus the easing: centering on the player and setting the draw offset.

To sum it up: I don't move anything in the tilemap, I just make it draw somewhere else with setDrawOffset.

(As an extra: Even though it's way past your question, if you're interested in how I'm handling the other layers, I'll have to say it's a big hack where I'm updating two sprites to move them according to the global offset. The dark background is a big hack I cannot explain easily the white background is only moving to get into the view and is locked is the camera is under a specific coordinate.)

Also, +1 for the reference to Hedgehog Launch, I kinda miss this era of games.

I got an answer from the dev @Eiyeron ! Neato ^....^

Based on this gif here, the up and down is the map moving (I assume that is where the setDrawOffset comes in) and the sprite can move left and right (to a point) before the map moves with it.

In my testing with setDrawOffset, it moves everything, including the sprite, making it harder to deal with. Would make a great shake screen effect though.

I have been trying to work with level 1-1 sample for a while now. Still teasing out the innerworkings of it.

I'm not to concerted about the backgrounds just yet. Just the foreground the black parts. It still boggles my mind that you're able to fit so much on screen, and treat them independently for collision.

playdate-20230201-215140

I answered in the DMs but for anyone curious and learning, I'll be copying my explanation here too.

I haven't found any helper function in the C API to manage a tilemap like you do in the Lua API, so I made mine involving a bunch of Sprites I pack myself in a grid. I also have a matching grid containing all the tiles' data, HP and type.

Also once a tile is dug, I update the neighboring tiles to make their graphics match the new layout. It's a mechanism similar to auto-tiling: for a tile in the grid, I check and accumulate the presence of the neighbors, turn that into an index I use in the bitmapTable and it gives me the bitmap to apply on the sprite.

The collision against the tilemap is less optimized though: the API has to check my tank against as many sprite colliders as there are active solid tiles instead of an optimized list built from a static tilemap.

There are some design issues with my system as a whole: for performance reasons I only load tiles around the camera, so if there's an object moving too far from the camera, it'll clip through the world, I still have to fix that and that's when I put working this project on pause (but for other reasons than solving this).

Those are the reasons my world looks dynamic: it's actually a whole bunch of tiles I manage manually. I suppose that the process of creating a tilemap might be way more expensive in Lua. Panic probably provides simple functions on C to the Lua runtime to make them faster I'd have done something like that too. Though, I wonder if they do fancier stuff like rendering the map into a big bitmap to only one visual element to display or other caching stuff elsewhere.