## Tilemap find by index

Advanced game related topics
OgreVorbis
User
Posts: 14
Joined: Thu Jan 16, 2020 10:47 pm

### Tilemap find by index

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.
Mijikai
Posts: 1027
Joined: Sun Sep 11, 2016 2:17 pm

### Re: Tilemap find by index

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

OgreVorbis
User
Posts: 14
Joined: Thu Jan 16, 2020 10:47 pm

### Re: Tilemap find by index

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.
NicTheQuick
Posts: 817
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

### Re: Tilemap find by index

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.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
chi
Posts: 861
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

### Re: Tilemap find by index

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
Et cetera is my worst enemy
Mijikai
Posts: 1027
Joined: Sun Sep 11, 2016 2:17 pm

### Re: Tilemap find by index

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

OgreVorbis
User
Posts: 14
Joined: Thu Jan 16, 2020 10:47 pm

### Re: Tilemap find by index

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.
OgreVorbis
User
Posts: 14
Joined: Thu Jan 16, 2020 10:47 pm

### Re: Tilemap find by index

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.
J. Baker
Posts: 2124
Joined: Sun Apr 27, 2003 8:12 am
Location: USA
Contact:

### Re: Tilemap find by index

www.posemotion.com

PureBasic Tools for OS X: PureMonitor, plist Tool, Data Maker & App Chef

Mac: 10.13.6 / 1.4GHz Core 2 Duo / 2GB DDR3 / Nvidia 320M
PC: Win 7 / AMD 64 4000+ / 3GB DDR / Nvidia 720GT

Even the vine knows it surroundings but the man with eyes does not.