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 :oops: 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