Apunts Game Loop i TBE - Videojocs (2016)

Apunte Catalán
Universidad Universidad Politécnica de Cataluña (UPC)
Grado Ingeniería Informática - 4º curso
Asignatura Videojocs
Año del apunte 2016
Páginas 6
Fecha de subida 19/03/2016
Descargas 2
Subido por

Descripción

Apunts dels dos primers temes de VJ (Game loop i TBE)

Vista previa del texto

VIDEOJOCS GAME LOOP FRAMERATE i LAG E l framerate és el nombre de frames (renders) per segon (fps). Respecte el framerate, els jocs busquen que sigui consistent (30 fps, 60 fps, 120 fps). L'inversa del framerate és el temps per framerate: TxFramerate = 1 / Framerate.
El màxim framerate útil és el del monitor, tot i que sovint és difícil d'aconseguir per culpa dels problemes de sincronització. Com a orientació, per una banda tenim que el mínim framerate per a que un joc ens transmeti sensació de presència és 10 fps (qüestionablement baix); i, per l'altra banda, quan tractem amb jocs de reacció ràpida, necessitarem que sigui major a 30 fps (millor punteria, es veuen els moviments abans).
E l lag és el temps transcorregut entre que el jugador/a realitza una acció i l'efecte d'aquesta sobre el món del joc. El lag ha de ser, evidentment, el menor possible i constant. Petit perquè un lag massa gran trenca la causalitat, difculta la interacció (sobretot en casos de precisió, com la punteria) i pot provocar marejocs, entre d'altres efectes negatius; i constant perquè és més fàcil adaptar-s'hi quan no varia.
Hem d'intentar doncs, tenir un lag menor a 2/ framerate (el lag mitjà és de 1.5 / framerate).
GAMELOOP BÀSIC El gameloop és el component central del joc, ja que permet que funcioni encara que no hi hagin esdeveniments externs i dóna una seqüència d'accions a realitzar a cada frame. Per entendre la motivació del gameloop, hem de tenir en compte que els jocs són un subconjunt del real-time programming i que existeix una relació determinista entre el temps de les diverses tasques.
A la fgura de l'esquerra podem observar l'esquema d'un gameloop bàsic i a la de la dreta l'afectació del framerate i el lag a aquest component.
Entrada (player input).
Pel sistema d'entrada veurem dues opcions: el polling (enquesta contínua) i el even-driven (reaccionar només als esdeveniments). El primer és clarament menys efcient, però el segon com a tal no permet establir relació de temps entre tasques, fet que va en contra del concepte de gameloop. La solució és tenir un procés que registri les entrades dels esdeveniments.
Polling.
La crida a obtindreEvent() no pot ser bloquejant. Una 1 altra opció és una funció que esperi un nou esdeveniment.
Event-driven.
L'aplicació registra funcions que tractin els diferents esdeveniments, quan es produeix un esdeveniment determinat, la seva funció associada s'executa. En GLUT aquestes funcions són les anomenades callbacks (glutIdleFunc, glutcKeyboardFunc, glutResizeFunc, glucMouseFunc).
Objectes dinàmics i velocitats.
Els jocs tenen, inevitablement, objectes dinàmics i això provoca que hi hagin interaccions i col·lisions que cal tractar depenent del temps que triga el bucle en fer la volta. -> Solució: ús de velocitats (procés d'actualització).
Problema: velocitat variable del bucle. Timing.
Per causes com el hardware o el temps assignat pel planifcador multitasca, el temps que triga el bucle en fer la volta varia (una altra motivació per les velocitats). Així doncs, farem servir timers que ens permetin obtenir el temps transcorregut des d'un determinat moment (habitualment, des de l'inici de l'execució). Aquests t i m e r s depenen del SO, en G L U T tenim el gluGet (GLUT_ELAPSED_TIME), que ens retorna el temps en ms.
El temps esperat Te per frame que volem obtenir és de 1000 / framerate ms, així: – si 50 fps -> Te = 20 ms – si 60 fps -> Te = 17 ms Per tant, quan calculem la diferència entre el temps esperat i el transcorregut real...: – si >= 0: anem bé -> donem temps extra al SO en què el bucle intern espera (sleep) – altrament: no arribem -> cal accelerar-ho reduïnt la qualitat dels gràfcs i interpolant (velocitats) per tal de millorar l'efciència del joc.
Exemples de gameloop. (L'esquerra és GLUT).
2 TBE (Tile Based Engine) DEFINICIÓ I OBJECTIUS Un tile és un bloc fonamental d'un tauler (habitualment quadrat). Formalment, una imatge les mides de la qual (normalment potències de dos) cal decidir a partir de l'extensió del mapa i les restriccions de memòria.
Usem tiles amb l'objectiu principal de reutilitzar gràfcs, fet que ens estalviarà recursos de memòria i temps d'artistes (car). A més, podrem generar contingut dinàmicament, ja que tindrem un conjunt de tiles creats pels artistes, i amb un dissenyador de mapes procedural generarem mapes aleatòriament millorant la rejugabilitat.
Un exemple real de joc basat en TBE és el Legend of Zelda (NES, 1986). El consum de memòria que hagués suposat guardar la imatge d'un mapa com a tal hagués sigut de 5.5 MB, mentre que amb tiles un mapa consumia solament 22 KB, i tot el conjunt 58 KB (100 vegades menys!).
CONTINUÏTAT ENTRE TILES Per a que un TBE sigui bo, hem d'assegurar que no es pot distingir on comença i on acaba cada tile (la imatge ha de ser uniforme). Tenim dues opcions per gestionar-ho: – tiling textures: textures que es poden repetir sense discontinuïtat (esquerra) – tiles de connexió, entre qualsevol parella de terrenys (dreta).
Altres opcions a les anteriors per assegurar la continuïtat entre tiles són tenir imatges grans pels fons (més detall, però més espai ocupat), fer una combinació híbrida de tiles i imatges grans, o bé tenir més nivells (aproftar la repetició de tiles).
3 LAYERS I TRANSPARÈNCIES La majoria de jocs tenen objectes estàtics en els seus mapes (p.e.: vegetació). En aquests casos, normalment no voldrem tenir un tile per a cada combinació terra-objecte. Així doncs, treballarem amb múltiples capes o layers (denses o disperses).
Ens trobarem, aleshores, amb el problema de les capes que es sobreposin i necessetarem donar suport a les transparències --> veurem dos mètodes: – color clau (colour key): defnim un color que s'ignora al pintar (similar al discard) – mètode antic, – canal alpha (RGBA): permet donar una transparència variable a l'objecte (alphaa (0,1)) – OpenGL i DirectX no ho suporten directament.
Capes denses.
Les capes denses es fan servir de fons i s'implementen amb mapes de tiles.
A continuació veiem una possible implemetació de capa densa amb tiles.
Comentaris sobre l'implementació: – – – – RenderTile necessitarà accès a la classe que s'encarregui de la gestió de textures.
Hem de considerar la possibilitat de que la textura tingui més d'un tile.
Només s'han de visualitzar aquells tiles que realment siguin visibles.
Podria ser que ens trobem amb tiles grans (majors que widthTile i heightTile).
Capes disperses.
Es fan servir per representar objectes, normalment estàtics i s'implementen com un vector de tiles variables.
A continuació veiem una possible implemetació de capa dispersa amb vector.
Comentaris sobre l'implementació: – – – – RenderTile necessitarà accès a la classe que s'encarregui de la gestió de textures.
Hem de considerar la possibilitat de que la textura tingui més d'un tile.
Només s'han de visualitzar aquells tiles que realment siguin visibles.
Pot ser que tinguem posicions no enteres.
A la següent fgura veiem com els tiles d'una capa poden no cobrir tot el mapa, per tant, les capes disperses són força adequades per tiles de mides variables.
4 SCROLLING El món del joc sol ser més gran que una sola pantalla. Així doncs, podem dividir el joc en vàries pantalles o nivells, o bé usar scrolling, és a dir, que veiem el món a través d'una fnestra mòbil.
Com implementem l'scrolling? Haurem de moure la càmara per seguir l'acció del joc, per tant, considerarem els paràmetres següents: – Posició i mida de la càmara (foat cameraX, cameraY, cameraWidth, cameraHeight).
– cameraX a [0, mapWidth * tileWidth – cameraWidth].
– cameraY a [0, mapHeight * tileHeight – cameraHeight].
– Velocitat de la càmara (foat cameraVx, cameraVy) --> el moviment de la càmara s'ha d'actualitzar independentment de la velocitat del main loop. Això ens permet canviar la velocitat del scroll.
Implementació bàsica.
1. Haurem de defnir, primer, les tecles d'entrada que li donaran al programa l'ordre d'scroll (fase d'entrada).
2. L'actualització de la càmera dependrà de cameraX += loopTime * cameraVx; cameraY += loopTime * cameraVy; (fase d'actualització).
3. Visualitzarem només aquells tiles que siguin realment visibles, com sempre (fase de render), com podem observar a les fgures següents.
Com veiem, es dibuixen els tiles dins de (minX, maxX, minY, maxY). Així doncs, per donar la sensació de moviment tindrem dues opcions: – DESPLAÇAR TILES: amb la modifcació dels paràmetres cameraX, cameraY.
– CANVIAR FRUSTRUM: void gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top); gluOrtho2D(minX, maxX, minY, maxY); En els casos de jocs d'estratègia o similars podem moure la càmara directament sense tenir en compte on és l'avatar del jugador, però en side-scrollers com SuperMario o Sonic, caldrà que seguim al jugador amb l'avatar centrat (o una mica més avançat que el centre per donar la sensació de velocitat) – actualizem la posició del jugador i de la càmara a la vegada.
Scrolling en capes disperses. Interseccions.
Quan tractem amb capes disperses haurem de fer l'intersecció entre la càmara i cada una de les capses dels tiles de la capa.
5 Intersecció d'intervals 1D: tenim interesecció si es compleix que: min1 < max2 && min2 < max1.
Intersecció de capses 2D: suposem dues capses capsa1: (minX1, minY1) – (maxX1, maxY1), i capsa2: (minX2, minY2) – (maxX2, maxY2), tenim intersecció si es compleix que: (minX1 < maxX2) && (minX2 < maxX1) (minY1 < maxY2) && (minY2 < maxY1).
Exemples d'scrolling.
---------------- 6 ...