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
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?