Page 1 of 1
Tilemap find by index
Posted: Wed Aug 18, 2021 11:17 am
by OgreVorbis
So this is a relatively common question, but with all my searching, none of the answers sufficed. It's
to admit that I can't figure this out. It seems simple.
So I have a tilemap png file. Its tiles are 32x32 and has 8 columns and 133 rows. I have the index number of each tile (the index starts at upper left and goes across and down - like expected). I need to turn that index number into the coords (x, y). I'm using ClipSprite. The vars are obvious and they are words.
Code: Select all
ClipSprite(0, (Mod(TileNumber, TileMapWidth / 32) * 32) - 32, [no idea what], #TileWidth, #TileHeight)
That's probably not even close to correct. I was at it for long enough that my brain started to frost over and I couldn't think anymore.
Re: Tilemap find by index
Posted: Wed Aug 18, 2021 1:19 pm
by Mijikai
Give this a try
Code: Select all
Procedure.i ClipTile(Tile,Index.i,TileMapWidth.i)
Protected x.i
Protected y.i
y = Index / TileMapWidth
x = Index - (y * TileMapWidth)
ProcedureReturn ClipSprite(Tile,x << 5,y << 5,32,32)
EndProcedure
Re: Tilemap find by index
Posted: Thu Aug 19, 2021 7:29 am
by OgreVorbis
Mijikai wrote: ↑Wed Aug 18, 2021 1:19 pm
Give this a try
First off, x is always zero. Why are you doing that second operation?
I'm not sure how you arrived at that. It doesn't work.
Re: Tilemap find by index
Posted: Thu Aug 19, 2021 10:01 am
by NicTheQuick
It goes like this:
Code: Select all
#TileWidth = 32
Procedure.i ClipTile(Tile, Index.i, TileMapWidth.i)
Protected x.i
Protected y.i
x = (Index % (TileMapWidth / #TileWidth)) * #TileWidth
y = (Index / (TileMapWidth / #TileWidth)) * #TileWidth
Debug "(" + x + ", " + y + ")"
EndProcedure
For i = 0 To 10
ClipTile(0, i, 256)
Next
Of course you can optimize it a bit if you like.
Re: Tilemap find by index
Posted: Thu Aug 19, 2021 10:47 am
by chi
My two cents
Code: Select all
CompilerIf #PB_Compiler_Debugger = 0
MessageRequester("", "Enable the debugger...")
CompilerEndIf
Procedure ClipTile(index, tc=8, tw=32, th=32)
Static tmp.RECT
tmp\left = tw * ((index - 1) % tc)
tmp\top = th * Round((index - 1) / tc, #PB_Round_Down)
tmp\right = tw
tmp\bottom = th
ProcedureReturn tmp
EndProcedure
tiles = 69
columns = 8
tileWidth = 32
tileHeight = 32
CreateImage(0, tileWidth * columns, tileHeight * Round(tiles / columns, #PB_Round_Up))
StartDrawing(ImageOutput(0))
For i=1 To tiles
*tile.RECT = ClipTile(i, columns, tileWidth, tileHeight)
Box(*tile\left, *tile\top, *tile\right, *tile\bottom, RGB(Random(255), Random(255), Random(255)))
Next
StopDrawing()
ShowLibraryViewer("Image", 0)
CallDebugger
Re: Tilemap find by index
Posted: Thu Aug 19, 2021 12:19 pm
by Mijikai
OgreVorbis wrote: ↑Thu Aug 19, 2021 7:29 am
Mijikai wrote: ↑Wed Aug 18, 2021 1:19 pm
Give this a try
First off, x is always zero. Why are you doing that second operation?
I'm not sure how you arrived at that. It doesn't work.
The second operation is multiplying by 32 (TileSize) by shifting its faster than normal multiplication.
The code works here is an example:
Code: Select all
EnableExplicit
Procedure.i ClipTile(Tile,Index.i,TileSize.i,TileMapWidth.i,*X.Integer,*Y.Integer)
Protected x.i
Protected y.i
y = Index / TileMapWidth
x = Index - (y * TileMapWidth)
*X\i = x * TileSize
*Y\i = y * TileSize
ProcedureReturn ClipSprite(Tile,*X\i,*Y\i,TileSize,TileSize)
EndProcedure
Procedure.i Sprite(Index.i,Color.i)
Protected x.i
Protected y.i
If CreateSprite(Index,133 * 8,8 * 8)
If StartDrawing(SpriteOutput(Index))
DrawingMode(#PB_2DDrawing_Outlined)
For y = 0 To 7
For x = 0 To 132
Box(x * 8,y * 8,8,8,Color)
Next
Next
StopDrawing()
ProcedureReturn #True
EndIf
FreeSprite(Index)
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i Main(Index.i)
Protected exit.i
Protected x.i
Protected y.i
If InitSprite()
If OpenWindow(0,0,0,1920,1080,#Null$,#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)
If OpenWindowedScreen(WindowID(0),0,0,1920,1080)
SetFrameRate(60)
Sprite(0,$FFFFFF)
Sprite(1,$222222)
Repeat
Repeat
Select WindowEvent()
Case #PB_Event_CloseWindow
exit = #True
Case #Null
Break
EndSelect
ForEver
ClearScreen($0)
DisplaySprite(1,120,200)
ClipTile(0,Index,8,133,@x,@y)
DisplaySprite(0,120 + x,200 + y)
StartDrawing(ScreenOutput())
DrawText(200,420,"Tile Index: " + Str(Index))
DrawText(200,440,"Tile Offset: " + Str(x) + " x " + Str(y))
DrawingMode(#PB_2DDrawing_Outlined)
Box(120,200,133 * 8,8 * 8)
LineXY(120 + x + 4,100,120 + x + 4,400)
LineXY(10,200 + y + 4,1600,200 + y + 4)
StopDrawing()
FlipBuffers()
Until exit
EndIf
CloseWindow(0)
EndIf
EndIf
ProcedureReturn #Null
EndProcedure
Main(500)
End
Re: Tilemap find by index
Posted: Sun Aug 22, 2021 7:20 pm
by OgreVorbis
NicTheQuick wrote: ↑Thu Aug 19, 2021 10:01 am
It goes like this:
Code: Select all
#TileWidth = 32
Procedure.i ClipTile(Tile, Index.i, TileMapWidth.i)
Protected x.i
Protected y.i
x = (Index % (TileMapWidth / #TileWidth)) * #TileWidth
y = (Index / (TileMapWidth / #TileWidth)) * #TileWidth
Debug "(" + x + ", " + y + ")"
EndProcedure
For i = 0 To 10
ClipTile(0, i, 256)
Next
Of course you can optimize it a bit if you like.
That works perfectly. Thank you. BTW I didn't know you could use % in PB, I thought it was Mod().
In terms of optimize, do you mean like a lookup table? That way it doesn't have to run the calculation on every loop.
As a side note. I think I'm going to GrabSprite after the first draw and render the background tiles as one sprite. I'd assume greater speed. Then only the upper layers will draw separate tiles.
Re: Tilemap find by index
Posted: Sun Aug 22, 2021 7:23 pm
by OgreVorbis
Mijikai wrote: ↑Thu Aug 19, 2021 12:19 pm
The second operation is multiplying by 32 (TileSize) by shifting its faster than normal multiplication.
No, not that operation. The X =
You get 0 every time for X.
Re: Tilemap find by index
Posted: Sat Oct 16, 2021 1:39 pm
by J. Baker