tile map scroller testing...

Discuss any general programming issues here
Post Reply
User avatar
Tuxedo
Posts: 351
Joined: Sun Feb 14, 2010 12:41 pm

tile map scroller testing...

Post by Tuxedo »

Hi ALL!
I'm trying to create a game like a platfrom/metroidvania and looking for a routine that works nice on putting tiles on screen...
After a bit of study and some test I do the code linked:

Code: Select all

/* sPLATFORM */

; VARIABILI DI BASE

MapW		= 0	; Larghezza mappa in tiles
MapH		= 0	; Altezza mappa in tiles
MaptileW	= 0	; larghezza tile mappa
MaptileH	= 0	; Altezza tile mappa
MapOrientation	= ""	; orientamento mappa ("right-down" di default)
InfiniteMap	= ""	; Controllo se la mappa è infinita
Infinite	= 0	; Così so se la mappa è settata come infinita o no
LayersNo	= 0	; Numero di layers attivi in questa mappa
TileS1		= 0
BaseTT		= 0	; questo è il tile "ZERO" del tileset utilizzato correntemente per disegnare lo sfondo
salta		= 0
tile		= 0
x		= 0
y 		= 0
xy		= 0

/********************************************** DEBUG ********************************************************/
@OPTIONS {EnableDebug = false} ; ATTIVO L'OUTPUT DI DEBUG PER CONTROLLARE EVENTUALI ERRORI!!!!!!!!!
/********************************************** DEBUG *********************************************************/

@REQUIRE "rebelsdl", {Link = true}

;@DISPLAY {Width = 480, Height = 270, Color = $444444}
@DISPLAY {Width = 480, Height = 270, Color = $444444, Mode = "FullScreen", ScaleFactor = 4, SmoothScale = 0}

;OpenResourceMonitor()

Dim PrintT[100] ; imposto la tabella degli indirizzi degli assets

map$ , mapbyte = FileToString("MAPPA/mappa8.json")	; carico la mia mappa

Function p_LoadResources()	; carico le risorse
	HERO_ATTACK		= LoadBrush(Nil, "MAPPA/DATA/HERO/ATTACK_6X5.png", {LoadAlpha = True, Hardware = True})
	HERO_DEAD		= LoadBrush(Nil, "MAPPA/DATA/HERO/DEAD_5x5.png", {LoadAlpha = True, Hardware = True})
	HERO_IDLE		= LoadBrush(Nil, "MAPPA/DATA/HERO/IDLE_4X5.png", {LoadAlpha = True, Hardware = True})
	HERO_JUMP		= LoadBrush(Nil, "MAPPA/DATA/HERO/JUMP_4X4.png", {LoadAlpha = True, Hardware = True})
	HERO_JUMPHIGH		= LoadBrush(Nil, "MAPPA/DATA/HERO/JUMPHIGH_4X4.png", {LoadAlpha = True, Hardware = True})
	HERO_RUN		= LoadBrush(Nil, "MAPPA/DATA/HERO/RUN_5X5.png", {LoadAlpha = True, Hardware = True})
	MAP_BACKGROUND		= LoadBrush(Nil, "MAPPA/DATA/MAP/Background.png", {LoadAlpha = True, Hardware = True})
	MAP_BUILDINGS		= LoadBrush(Nil, "MAPPA/DATA/MAP/Buildings.png", {LoadAlpha = True, Hardware = True})
	MAP_GREENTREE		= LoadBrush(Nil, "MAPPA/DATA/MAP/Green-Tree.png", {LoadAlpha = True, Hardware = True})
	MAP_INTERIOR01		= LoadBrush(Nil, "MAPPA/DATA/MAP/Interior-01.png", {LoadAlpha = True, Hardware = True})
	MAP_TILES		= LoadBrush(Nil, "MAPPA/DATA/MAP/Tiles.png", {LoadAlpha = True, Hardware = True})
	MAP_TREEASSETS		= LoadBrush(Nil, "MAPPA/DATA/MAP/Tree-Assets.png", {LoadAlpha = True, Hardware = True})
	MAP_TREEBACKGROUND	= LoadBrush(Nil, "MAPPA/DATA/MAP/TreeBackground.png", {LoadAlpha = True, Hardware = True})
	BEE_ATTACK		= LoadBrush(Nil, "MAPPA/DATA/MOB/BEE_ATTACK_4X4.png", {LoadAlpha = True, Hardware = True})
	BEE_FLY			= LoadBrush(Nil, "MAPPA/DATA/MOB/BEE_FLY_4X4.png", {LoadAlpha = True, Hardware = True})
	BEE_HIT			= LoadBrush(Nil, "MAPPA/DATA/MOB/BEE_HIT_4X4.png", {LoadAlpha = True, Hardware = True})
	BOAR_HIT		= LoadBrush(Nil, "MAPPA/DATA/MOB/BOAR_HIT_3X2.png", {LoadAlpha = True, Hardware = True})
	BOAR_IDLE		= LoadBrush(Nil, "MAPPA/DATA/MOB/BOAR_IDLE_3X2.png", {LoadAlpha = True, Hardware = True})
	BOAR_RUN		= LoadBrush(Nil, "MAPPA/DATA/MOB/BOAR_RUN_3X2.png", {LoadAlpha = True, Hardware = True})
	BOAR_WALK		= LoadBrush(Nil, "MAPPA/DATA/MOB/BOAR_WALK_3X2.png", {LoadAlpha = True, Hardware = True})
	OBJ_BOX			= LoadBrush(Nil, "MAPPA/DATA/OBJ/BOX_2x2.png", {LoadAlpha = True, Hardware = True})
	OBJ_COIN		= LoadBrush(Nil, "MAPPA/DATA/OBJ/COIN_1x1.png", {LoadAlpha = True, Hardware = True})
	OBJ_KEY			= LoadBrush(Nil, "MAPPA/DATA/OBJ/KEY_1x1.png", {LoadAlpha = True, Hardware = True})
	OBJ_POTION33		= LoadBrush(Nil, "MAPPA/DATA/OBJ/POTION33_1x1.png", {LoadAlpha = True, Hardware = True})
	OBJ_POTION100		= LoadBrush(Nil, "MAPPA/DATA/OBJ/POTION100_1x1.png", {LoadAlpha = True, Hardware = True})
	OBJ_SPAWNBEE		= LoadBrush(Nil, "MAPPA/DATA/OBJ/SPAWN_BEE_2x3.png", {LoadAlpha = True, Hardware = True})

; ora setto i sorgenti degli assets

PrintT[0] = MAP_BUILDINGS
PrintT[1] = MAP_TILES
PrintT[2] = MAP_TREEBACKGROUND
PrintT[3] = MAP_GREENTREE
PrintT[4] = MAP_BACKGROUND
EndFunction

Function p_MapData()	; imposto le variabili di base della mia mappa prendendle dal file .JSON salvato da Tiled
	MapW		= map.width				; Larghezza mappa in tiles
	MapH		= map.height				; Altezza mappa in tiles
	MaptileW	= map.tilewidth				; larghezza tile mappa
	MaptileH	= map.tileheight			; Altezza tile mappa
	MapOrientation	= map.orientation			; orientamento mappa ("right-down" di default)
	InfiniteMap	= map.infinite				; Controllo se la mappa è infinita
	Infinite	= 0					; Così so se la mappa è settata come infinita o no
	LayersNo	= TableItems(map.layers)		; Numero di layers attivi in questa mappa
	TileBACKcol	= map.tilesets[4].columns		; salvo quante colonne in tiles ha il mio tielsets
	TileBACKcount	= map.tilesets[4].tilecount		; salvo quante tiles ha il mio tilesets
	TileBACKrow	= TileBACKcount/TileBACKcol		; numero righe tileset caricato
	TileBACKW	= map.tilesets[4].tilewidth		; Carico la larghezza delle tiles del tilesets specifico
	TileBACKH	= map.tilesets[4].tileheight		; Carico l'altezza delle tiles del tilesets specifico
	TileBACKstart	= map.tilesets[4].firstgid		; Quì carico il numero della prima tile del tileset
	TileBUILDcol	= map.tilesets[0].columns		; salvo quante colonne in tiles ha il mio tielsets
	TileBUILDcount	= map.tilesets[0].tilecount		; salvo quante tiles ha il mio tilesets
	TileBUILDrow	= TileBUILDcount/TileBUILDcol		; numero righe tileset caricato
	TileBUILDW	= map.tilesets[0].tilewidth		; Carico la larghezza delle tiles del tilesets specifico
	TileBUILDH	= map.tilesets[0].tileheight		; Carico l'altezza delle tiles del tilesets specifico
	TileBUILDstart	= map.tilesets[0].firstgid		; Quì carico il numero della prima tile del tileset
	TileTILEScol	= map.tilesets[1].columns		; salvo quante colonne in tiles ha il mio tielsets
	TileTILEScount	= map.tilesets[1].tilecount		; salvo quante tiles ha il mio tilesets
	TileTILESrow	= TileTILEScount/TileTILEScol		; numero righe tileset caricato
	TileTILESW	= map.tilesets[1].tilewidth		; Carico la larghezza delle tiles del tilesets specifico
	TileTILESH	= map.tilesets[1].tileheight		; Carico l'altezza delle tiles del tilesets specifico
	TileTILESstart	= map.tilesets[1].firstgid		; Quì carico il numero della prima tile del tileset
	TileTREEBcol	= map.tilesets[2].columns		; salvo quante colonne in tiles ha il mio tielsets
	TileTREEBcount	= map.tilesets[2].tilecount		; salvo quante tiles ha il mio tilesets
	TileTREEBrow	= TileTREEBcount/TileTREEBcol		; numero righe tileset caricato
	TileTREEBW	= map.tilesets[2].tilewidth		; Carico la larghezza delle tiles del tilesets specifico
	TileTREEBH	= map.tilesets[2].tileheight		; Carico l'altezza delle tiles del tilesets specifico
	TileTREEBstart	= map.tilesets[2].firstgid		; Quì carico il numero della prima tile del tileset
	ScreenW		= 480					; larghezza schermo in pixel
	ScreenH		= 270					; altezza schermo in pixel
	ScreenWtile	= Round(ScreenW/MaptileW)		; numero tiles larghezza schermo
	ScreenHtile	= Round(ScreenH/MaptileH)		; numero tiles altezza schermo
EndFunction

Function p_TileToLoad(tt) ; quì calcolo quali Tiles caricare dall'immagine di partenza
Local t = 0
Local TileSTART = 0

For t = 0 To 4
	If tt >= (map.tilesets[t].firstgid)
		If tt <= (map.tilesets[t].firstgid + map.tilesets[t].tilecount - 1)
		TileSTART = map.tilesets[t].firstgid
		tok = t
		EndIf
	EndIf
Next

tile = tt - TileSTART	; calcolo la tile da visualizzare

deltaTT = Int(tile/map.tilesets[tok].columns)
	
srcx = tile - (deltaTT * map.tilesets[tok].columns)
srcy = deltaTT

EndFunction

Function p_DrawTiles() ; scrivo a schermo le mie tiles
	srcx, srcy  = 0, 0
Local	destx, desty = 0,0
Local	deltaMAP = 0

	For Local tx = 0 To ((ScreenWtile*ScreenHtile)-1)

		If (tx <> 0) And Frac(tx/ScreenWtile) = 0
			desty = desty + TileTDH
			destx = destx - ScreenW ; In base alla Larghezza dello schermo imposto destx
			deltaMAP = deltaMAP + MapW - ScreenWtile
		EndIf

		If map.layers[0].data[(tx+deltaMAP)+xy] <> 0; disegno il layer 0(quello dello sfondo animato)
;		DebugPrint("0")
			p_TileToLoad(map.layers[0].data[(tx+deltaMAP)+xy])
			Local PrintTILE = PrintT[tok]	; questa varaibile mi dirà da quale tileset prendere le tiles da blittare.
			DisplayBrushPart(PrintTILE, srcx*TileTDW, srcy*TileTDH, destx+(tx*TileTDW), desty, TileTDW, TileTDH)
		EndIf
		If map.layers[1].data[(tx+deltaMAP)+xy] <> 0; disegno il layer 1(quello dello sfondo)
;		DebugPrint(" 1")
			p_TileToLoad(map.layers[1].data[(tx+deltaMAP)+xy])
			Local PrintTILE = PrintT[tok]	; questa varaibile mi dirà da quale tileset prendere le tiles da blittare.
			DisplayBrushPart(PrintTILE, srcx*TileTDW, srcy*TileTDH, destx+(tx*TileTDW), desty, TileTDW, TileTDH)
		EndIf
		If map.layers[2].data[(tx+deltaMAP)+xy] <> 0; disegno il layer 2(quello del parallasse più lontano)
;		DebugPrint("  2")
			p_TileToLoad(map.layers[2].data[(tx+deltaMAP)+xy])
			Local PrintTILE = PrintT[tok]	; questa varaibile mi dirà da quale tileset prendere le tiles da blittare.
			DisplayBrushPart(PrintTILE, srcx*TileTDW, srcy*TileTDH, destx+(tx*TileTDW), desty, TileTDW, TileTDH)
		EndIf
		If map.layers[3].data[(tx+deltaMAP)+xy] <> 0; disegno il layer 3(quello del parallasse più vicino)
;		DebugPrint("   3")
			p_TileToLoad(map.layers[3].data[(tx+deltaMAP)+xy])
			Local PrintTILE = PrintT[tok]	; questa varaibile mi dirà da quale tileset prendere le tiles da blittare.
			DisplayBrushPart(PrintTILE, srcx*TileTDW, srcy*TileTDH, destx+(tx*TileTDW), desty, TileTDW, TileTDH)
		EndIf
		If map.layers[4].data[(tx+deltaMAP)+xy] <> 0; disegno il layer 4(quello delle cose dietro il piano principale)
;		DebugPrint("    4")
			p_TileToLoad(map.layers[4].data[(tx+deltaMAP)+xy])
			Local PrintTILE = PrintT[tok]	; questa varaibile mi dirà da quale tileset prendere le tiles da blittare.
			DisplayBrushPart(PrintTILE, srcx*TileTDW, srcy*TileTDH, destx+(tx*TileTDW), desty, TileTDW, TileTDH)
		EndIf
		If map.layers[5].data[(tx+deltaMAP)+xy] <> 0; disegno il layer 5(quello del piano principale dove si muovono gli oggetti e ci hanno le collisioni con la mappa)
;		DebugPrint("     5")
			p_TileToLoad(map.layers[5].data[(tx+deltaMAP)+xy])
			Local PrintTILE = PrintT[tok]	; questa varaibile mi dirà da quale tileset prendere le tiles da blittare.
			DisplayBrushPart(PrintTILE, srcx*TileTDW, srcy*TileTDH, destx+(tx*TileTDW), desty, TileTDW, TileTDH)
		EndIf
		If map.layers[6].data[(tx+deltaMAP)+xy] <> 0; disegno il layer 6(quello delgli oggetti appena davanti il piano principale)
;		DebugPrint("      6")
			p_TileToLoad(map.layers[6].data[(tx+deltaMAP)+xy])
			Local PrintTILE = PrintT[tok]	; questa varaibile mi dirà da quale tileset prendere le tiles da blittare.
			DisplayBrushPart(PrintTILE, srcx*TileTDW, srcy*TileTDH, destx+(tx*TileTDW), desty, TileTDW, TileTDH)
		EndIf
		If map.layers[7].data[(tx+deltaMAP)+xy] <> 0; disegno il layer 7(quello degli oggetti un po' più vicini allo "schermo")
;		DebugPrint("       7")
			p_TileToLoad(map.layers[7].data[(tx+deltaMAP)+xy])
			Local PrintTILE = PrintT[tok]	; questa varaibile mi dirà da quale tileset prendere le tiles da blittare.
			DisplayBrushPart(PrintTILE, srcx*TileTDW, srcy*TileTDH, destx+(tx*TileTDW), desty, TileTDW, TileTDH)
		EndIf
		If map.layers[8].data[(tx+deltaMAP)+xy] <> 0; disegno il layer 8(quello degli oggetti proprio dietro il "vetro" del monitor)
;		DebugPrint("        8")
			p_TileToLoad(map.layers[8].data[(tx+deltaMAP)+xy])
			Local PrintTILE = PrintT[tok]	; questa varaibile mi dirà da quale tileset prendere le tiles da blittare.
			DisplayBrushPart(PrintTILE, srcx*TileTDW, srcy*TileTDH, destx+(tx*TileTDW), desty, TileTDW, TileTDH)
		EndIf
	Next

DebugPrint(x, y)

EndFunction

Function p_Keys()

IF IsKeyDown("p") ; se premo "p"....
wait(100) ; ...aspetto un secondo così guardo che c'è scritto nella finestra di output
EndIf

; controllo se ho premuto un tasto e imposto di conseguenza lo scroling
If IsKeyDown("UP") Then y = y - 1
If IsKeyDown("DOWN") Then y = y + 1
If IsKeyDown("LEFT") Then x = x - 1
If IsKeyDown("RIGHT") Then x = x + 1

If CountJoysticks() <> 0 ; se ho  un joystick/joypad attivo allora posso usare anche quello per gestire lo scrolling
	If JoyAxisX(0) > 150 Then x = x + 1
	If JoyAxisX(0) < -150 Then x = x - 1
	If JoyAxisY(0) > 150 Then y = y + 1
	If JoyAxisY(0) < -150 Then y = y - 1
EndIf

; ora controllo i valori che non devono assumere x e y
If x < 0 Then x = 0
If y < 0 Then y = 0
If x > 156 - ScreenWtile Then x = 156 - ScreenWtile
If y > 128 - ScreenHtile Then y = 128 - ScreenHtile

xy = (x + (y*156))

EndFunction

Function p_Scroll() ; quì gestisco lo scroling del mio programma
TileTDW = 16
TileTDH = 16

StartTimer(1)

p_Keys()

DisableLineHook()
p_DrawTiles()
EnableLineHook()

TextOut(450, 10,"[color=#RED]" ..  GetTimer(1))

Flip()

ResetTimer(1)

EndFunction

SetSerializeMode(#SERIALIZEMODE_NAMED) 	; imposto come va serializzata il file JSON che ho caricato...
map = DeserializeTable(map$)		; ...e lo Deserializzo in una TABELLA Hollywood con nomi invece di numeri.

StartTimer(2)
p_LoadResources()	; carico tutto quello che mi serve
p_MapData()		; Imposto i parametri della mia mappa dal file .JSON

DebugPrint("TIMER PRE....", GetTimer(2))

BeginDoubleBuffer(True) ; inizio il Double Buffering

EscapeQuit(True) ; così posso uscire con Esc quando voglio

Scroll	= SetInterval(Nil, p_Scroll, 1000/60) ; imposto la velocità di refresh

Repeat
	WaitEvent
Forever
The complied program (os4, and windows) with free assets I donwloaded around the net can be tryed here:

https://app.box.com/s/6s70wyomculg1zajnclyljsazvjr3w5p

Firstly I've a performace question:

- My simple approach to do a fastest possible code was to display all layers of the map directly in the FOR/Next lop without function calls that maybe was faster than do:

p_PrintLayer()

each time or was nonsense?
Naturally for the others game tasks I'll use function calls.

ATM btw I'm focused on performance so no big matter on what will be tomorrow... ;P

The code above gives me atm that rougly calculated(with the TextOut()) frametime ms:

Ryzen 5 5600x and RTX 2070SUPER : 1 to 2 ms going around the map with cursor keys
Ryzen 5625U : 4 to 5 ms
Ryzen 5 2600 and RX 6500XT : 4 to 5
Core I5 10400f RX 6600 XT : weirldy from 1 to 20 ms...maybe intel realted problem? That was similar to first configuration I tested(the 5600x)
Sam440Flex and Radeon9250 (64bit PCI): 50 to 100

On My R5 5600x and WinUAE on AMigaOS4.1FE and VooDoo3 emulated I cant run the RebelSDL version and have compiled a version without it and with no "hardware" tag and however get a not expected 25 to 50 that wasnt so bad compared to SamFlkex results...

I'm waiting for X1000 and X5000 results, to look for some optimizations, maybe lowering layers and changeing the background for example from tiles to single pic...

For speedup things I also tought to put a single bigger that screen(if need some parallax scroll or same a screen if no need) image as background that seems to me that in harware was similkar to draw a single tile...or maybe there was a better technique? Sorry really noob on that ...

- Another question was about the fps I get...

Setting the SetInterval() function to 1000/60 gives me 60 fps and setting to 1000/30 gives me 30 fps(measured with Nvidia overlay on my setup) but trying to go up(my monitor was 165Hz) I get always something around 63/64...was something related to RebelSDL? No big problem but just to know.

I hope that discussion can help me solving some doubts...and making something better....

PS I know that the scroll atm was tile/related my as stated above I need performance testing no focused on pixel scroll....

PPS Sorry for any stupid question I exposed...

EDIT: I noticed that the JoyPad wasnt recognized if inserted after the game load, not used atm the SDL functions but that was normal?
Simone"Tuxedo"Monsignori, Perugia, ITALY.
TearsOfMe
Posts: 17
Joined: Fri Apr 24, 2020 2:15 pm

Re: tile map scroller testing...

Post by TearsOfMe »

Hello.
I run the OS4 exe here on my X1000 and RadeonRX550. It shows in the right top corner 15 (FPS)?

sdl versions:
SDL1_2_13 1.4
libSDL2.so 0.22
User avatar
Tuxedo
Posts: 351
Joined: Sun Feb 14, 2010 12:41 pm

Re: tile map scroller testing...

Post by Tuxedo »

TearsOfMe wrote: Sat Apr 06, 2024 12:23 pm Hello.
I run the OS4 exe here on my X1000 and RadeonRX550. It shows in the right top corner 15 (FPS)?

sdl versions:
SDL1_2_13 1.4
libSDL2.so 0.22
Hi!
thanks for testing!
the red number was related to the time spent generating the frame so you are about 60 fps...not so bad...not so good...since there was to draw sill mobs, objects, hero, and other effects...but I hope there's room for optimizations to get the 60 fps or near on X1000 at the end...
For sure was interesting to see if with another graphics card on X1000 the values was better...
You have scrolled around the map(the number will increase in the middle/right middle of the map in theory).
Simone"Tuxedo"Monsignori, Perugia, ITALY.
TearsOfMe
Posts: 17
Joined: Fri Apr 24, 2020 2:15 pm

Re: tile map scroller testing...

Post by TearsOfMe »

Hehe lol, i have only try left right and not up down.
Yes, in the middle the number goes up to 20-26. Not realy smoth.
User avatar
Tuxedo
Posts: 351
Joined: Sun Feb 14, 2010 12:41 pm

Re: tile map scroller testing...

Post by Tuxedo »

Thank you.
Simone"Tuxedo"Monsignori, Perugia, ITALY.
Post Reply