dilluns, 11 de maig de 2009

Cas d'estudi: Super Mario Bros - Part II: Estructura de joc i scroll

Be, açò es el que vaig fer el divendres, pero me vaig quedar sense temps de escriure.

Per a començar, he afegit algunes funcions a les APIs. Anem a repasar els canvis:
JDraw
- He afegit funcions per a carregar una font: JD_Font JD_LoadFont( char *file, int width, int height); carregarà una font a partir d'un bitmap i li especificarà que els caracters son de widthxheight. El bitmap que espera tindrà, en fila hitzontal, els caracters a partir del #32, que es el espai, en avant, seguint la codificació ASCII. Jo, en el meu bitmap, nomes he ficat els numeros (#48-#57) i les lletres majuscules (#65-#90), pero si es vol es poden ficar tots, seguint inclus més avant.
- Altra funció per a pintar text: void JD_DrawText( int x, int y, JD_Font *source, char *text); pintarà el text especificat en "text" en la posició (x,y) usant la font "source" que haurem carregat amb la funció d'abans. Més avant ho prepararé per a que les fonts puguen ser multicolor.
- Una funció que ens torna els FPS. Aquesta funció torna un text, ja que normalment vull els FPS per a pintarlos en pantalla.

JGame
- Normalment, en un bucle de joc, hi ha dos parts ben definides: El pintat i l'actualització interna. El pintat solem deixar que vaja el més rapid posible, així que es pinta a cada pas del bucle. No obstant, l'actualització de vegades no la volem el més rapid posible, per dos raons: La primera perque potser es massa rapid, i la segona perque el joc aniría a diferents velocitats depenent de la potencia de la màquina. Així que l'actualització lo normal es només executar-la cada x milisegons. Per a estalviar-se ficar la lògica de control del temps pel mig del bucle, ho he traslladat al mòdul JGame amb dos funcions:
- void JG_SetUpdateTicks(Uint32 milliseconds);. Amb aquesta funció fixem el nombre de milisegons que deu passar entre actualització i actualització.
- bool JG_ShouldUpdate();. En cada bucle podem consultar aquesta funció per a saber si ja toca actualitzar o no. Així, en compte de controlar tot el tema del temps, nomes tenim que fer un "if" d'aquesta funció. Ara després ho vorem en el codí del Super Mario Bros.


Ale, ara anem a començar per fi amb el Super Mario. Com el titol endica, vorem la estructura bàsica del joc i la càrrega i pintat del mapa.


Per a començar, anem a vore com es la funció "main" del joc. Repasaré un mínim conceptes de C, per a qui faça anys que no ho toca:


#include "jgame.h"
#include "jdraw.h"
#include "modulegame.h"

Comencem per inclure les capçaleres que ens faràn falta. Ací nomes s'inluou el que fa falta ací, no tot el que fa falta durant el joc.


int main( int argc, char* args[] ) {

JG_Init("Super Mario Bros");
JD_Init(256, 240, false);

Per a començar, inicialitzem JGame i JDraw. Com podeu vorem he ficat la resolució de la NES, per a que siga igual que l'original.


int gameState = 0;

La variable gameState mantindrà l'estat en que es troba el joc. Aquest estat es correspondrà amb els mòduls del joc, com per exemple: intro, menu, joc, sequència... i eixes coses.


while (gameState != -1) {
switch (gameState) {
case 0:
gameState = ModuleGame_Go();
break;
}
}

Aquest es el bucle principal. L'unic que fà es executar-se mentres el estat de joc no siga "-1", que voldrà dir que havem decidit eixir del joc. En la pròxima actualització canviarè aquestos numerets per constants, així es veu tot més clar.

En cas de que gameState no siga "-1" executarà el bucle, dins el qual el que tenim es un switch del propi gameState, que el que fa es que segons el estat executa un mòdul concret. Per ara nomes està el mòdul del propi joc, així que es simple.

Dins de cada mòdul hi ha un altre bucle que s'executarà fins que ocorrega el que siga per a eixir d'eixe mòdul, tornant a aquest bucle principal.


JG_Finalize();

return 0;
}

Quan s'haja decidit eixir del joc, es finlaitza JGame. I ja està, aquesta es la funció main.

Si vos haveu fixat, havem inclos un tal "modulegame.h" i, a més, estem cridant a una tal "ModuleGame_Go()", que no sabem per on para. Anem a crear tot aixó ara. Comencem per l'arxiu "modulegame.h":


#pragma once

int ModuleGame_Go();

Ale, ha sigut fàcil. Com a recordatori: els arxius de capçalera (.h) mostren la interficie externa d'un mòdul. Lo normal es que els ".h" vagen acompanyats d'un ".c" o ".cpp". Per a entendren's sería com si el ".h" continguera l'interficie d'un objecte i els ".cpp" contingueren l'implementació. Així, els demés moduls enllaçen amb el ".h", i nomes veuen el que havem declarat ahí dins. Després en el ".cpp" tenim que implementar el que havem declarat en el ".h", però també podem declarar més variables i funcions, que no es podràn vore desde fora del mòdul.

Per tant, com del mòdul de joc només ens interessa que es puga cridar al propi mòdul i au, nomes publiquem aquesta funció. Ara dins del ".cpp" implementarem aquesta funció i altres funcions satel·lit.

Una última cosa: "#pragma once" es una directiva de compilació que el que diu es que aquesta capçalera nomes s'ha d'incloure una vegada. Es equivalent al tipic "#IFNDEF _MODULEGAME_H_ ....". El cas es que en C, cada vagada que inclous una llibreria, esta va i se torna a incloure, provocant errors després de simbols duplicats. Amb aquestes directives el que fem es dir-li que, per moltes vegades que referenciem al arxiu, nomes s'incloga una.

Ara anem a vore l'implementació de "modulegame.cpp":


#include "modulegame.h"
#include "jgame.h"
#include "jdraw.h"
#include "jinput.h"
#include "jfile.h"

Lo primer es incloure les APIs que ens fan falta. A més, sempre incloguem el ".h" que anem a implementar.


JD_Surface *tiles;
JD_Font fuente;
Uint8 tileMap[256][15];
Uint8 blocMap[256][15];
int scrollX = 0;

Ara declarem les variables que necessitarem a nivell global en el mòdul. "tiles" mantindrà el bitmap de tiles; "fuente" mantindrà la font que usarem per a escriure text; "tileMap" mantindrà el array de tiles a pintar; "blocMap" mantidrà els tiles de bloc; per últim, "scrollX" mantindrà la posició horitzontal del mapa. Aquesta variable es tempòral, fins que tingam sprites i tal.

Ara ve la definició de les funcions. Les funcions, quan no s'han definit en el ".h", han de ser definides en el ordre correcte: Si una funció A crida a una funció B, la funció B ha de ser definida abans. Com aixó es un poc lio per a explicar, jo vaig a anar parlant de les funcions de més externa a més interna. Després, en el codi que vos podeu baixar, ja estàn ordenades correctament.


int ModuleGame_Go() {

Init();

while (!JG_Quitting()) {

ModuleGame_Draw();
ModuleGame_Update();
}

Finalize();

return ( JG_Quitting() ? -1 : 0 );
}

Aquesta es la funció principal, a la que se crida desde fora. En ella, el primer que es fa es cridar a una funció "Init()" que s'encarregarà d'inicialitzar tot el necessari. Després comença el bucle. Per ara, nomes controla si volem eixir de l'aplicació, pero més avant controlarà que eixim nomes del mòdul (per a tornar al menú, per exemple). Dins del bucle, es crida a una funció per a pintar l'escena i altra per a actualitzar-la. En quan eixim del bucle, cridem a una funció de finalització que allibere la memòria i tot això.

Per últim, tornem un valor, que serà el que adquirirà la variable gameState per aanar a altre mòdul o eixir de la aplicació. Ara mateixa nomes es pot eixir de la aplicació i au. En el return el que he ficat es un "if reduït" d'eixos: Si s'acompleix la condició que hi ha abans de l'interrogant, torna el que hi ha després de l'interrogant. Sinó, torna el que hi ha després dels dos punts.

Anem a vore les funcions a les que havem cridat:


void Init() {
LoadMap();
tiles = JD_LoadSurface("tiles.gif");
fuente = JD_LoadFont("fuente.gif", 8, 8);
JG_SetUpdateTicks(1);
}

La funció d'inicialització crida a altra funció que carregarà el mapa. Després carrega el bitmap de tiles i la font que usarem per a pintar text. Per últim, fixa el temps d'actualizació cada 1 milisegons.


void LoadMap() {
int fileSize;
char *buffer = JF_GetBufferFromResource("mapa1_1.map", &fileSize);
int filePos = 1;

int filenameSize = buffer[filePos++];
char *fileName = (char *)malloc(filenameSize+1);
for (int i=0;i fileName[i] = buffer[filePos+i];
}
fileName[filenameSize] = '\0';

filePos = filePos + filenameSize;

for (int y=0; y<15; y++) {
for (int x=0; x<256; x++) {
tileMap[x][y] = buffer[filePos++];
}
}

for (int y=0; y<15; y++) {
for (int x=0; x<256; x++) {
blocMap[x][y] = buffer[filePos++];
}
}

delete fileName;
delete buffer;
}

Aquesta es la funció que carrega el mapa desde l'arxiu. Aquesta funció la refaré més avant, ja que vull incloure en JFile funcions per a que llegir d'un arxiu siga més simple, sense buffers i chars (si no es vol, clar).

El primer que fa es obtindre un punter a un array de char amb el contingut de l'arxiu. Ara el processarem char a char (char = 8 bits sense signe). Primer fiquem el punter a 1 (passem del char[0], que es el de la versió). Llegim el tamany del nom del bitmap. Sabent el tamany del nom del bitmap, declarem un punter a array de char (que es el que s'usa per a les cadenes en C) del tamany
que havem llegit + 1 (ja que les cadenes en C acaven amb el caracter 0). Aleshores llegim cada char. Per últim, fiquem l'ultim a zero i ja tenim la cadena del nom del bitmap. Per ara no la use, pero més avant carregaré els tiles d'aquest arxiu, en compte de a pel com havem vist en la funció Init().

Després augmente el punter tantes posicions com caracters tenia el nom, i ja estic en posició de llegir l'informació del mapa de tiles i del mapa de blocs. Per últim allibere la memòria dels punters.


void Finalize() {
JD_FadeOut();

JD_FreeSurface(tiles);
JD_FreeSurface(fuente.surface);
}

Quan tot haja acavat farem un fade out, i alliberarem la memòria que tenen pillada els bitmaps de tiles i el bitmap de la font.


void ModuleGame_Draw() {
for (int y=0; y<15; y++) {
for (int x=0; x<17; x++) {
Uint8 tile = tileMap[x+(scrollX >> 4)][y] & 127;
JD_Blit((x << 4)-(scrollX & 15), y << 4, tiles, (tile & 15) << 4, (tile >> 4) << 4, 16, 16);
}
}

JD_DrawText(0, 0, &fuente, JD_GetFPS());
JD_Flip();
}

Aquesta es la funció que pinta el mapa a cada pas del bucle. Recorre tots els tiles en l'eix Y i 17 tiles en l'eix X (16 que en caben en pantalla + 1, com ja vaig explicar amb el Gauntlet). Per a cada un, mire en el array de tiles, sumant el scrollX per a saber el desplaçament en el mapa. A més, faig un AND de 127, amb lo qual lleve el bit 8 (que es el que m'especifica si el tile es animat) per a obtindre el número de tile correcte. Més avant comprovaré eixe bit per a saber si té animació o no. Per últim pinte el tile. Si algú no s'aclareix amb la lògica del scroll, que ho diga i fique un post especific.

Per a finalitzar, pinte els FPS per a vore que tal va, i faig el flip.


void ModuleGame_Update() {
if (JG_ShouldUpdate()) {
JI_Update();

if (JI_KeyPressed(SDLK_RIGHT)) {
scrollX++;
if (scrollX > 3776) scrollX = 3776;
}

if (JI_KeyPressed(SDLK_LEFT)) {
scrollX--;
if (scrollX < 0) scrollX = 0;
}

if (JI_KeyPressed(SDLK_ESCAPE)) {
JG_QuitSignal();
}
}
}

Aquesta es la funció d'actualització. Ara mateixa nomes comprove si s'ha d'actualitzar o no. En cas afirmatiu, actualizte JInput i comprove si s'ha pulsat dreta o esquerra, per a augmentar o disminuir el offset del scroll. També mire si s'ha pulsat ESC, per a enviar una senyal d'eixir de l'aplicació.


I açò es tot per ara. Per cert, també he actualitzat l'editor, perque era molt lento i xicotet, i se feia incómode usar-lo. Podeu descarregar el codi d'ací. Si hui me dona temps igual ja fique un inici als sprites. Comentaris, sugerencies, dubtes... seràn gràtament apreciats.

PD: Hui es el meu aniversari. Demostra interés per els JailGames per a felicitar-me ;-)

dijous, 7 de maig de 2009

API per a Jailgames

Vaig a presentar un poc la API que vaig a usar durant el cas d'estudi. Està composta de 6 moduls:

- JGame: S'encarrega de les coses genèriques.
- JDraw: S'encarrega de la part gràfica.
- JInput: S'encarrega dels dispositius d'entrada.
- JSound: S'encarrega del só i la música.
- JFile: S'encarrega de la càrrega de arxius encapsulats.
- JNnet: S'encarrega de la comunicació per red.

Per ara inclouré els 5 primers. jnet el deixe per a mes avant.

JGame

void JG_Init(char *title);
- Inicialitza tot el sistema. S'ha de cridar abans de res. El paràmetre que rep es el titol que tindrà l'aplicació en la barra de titol.

void JG_Finalize();
- Finalitza el sistema. S'ha de cridar al final de tot.

void JG_QuitSignal();
- Al cridar a aquesta funció marquem la senyal de que volem eixir de la aplicació. en realitat no fa res més que ficar un booleà a true. El criden algunes funcions internes per a avisar-nos de que ha ocorregut algún event d'eixida de l'aplicació. Si quan decidim que volem eixir de la aplicació l'usem, podrem gestionar-ho tot des del mateix lloc.

bool JG_Quitting();
- Aquesta funció ens tornarà true si la senyal anterior s'ha activat. Com ja he dit, podem activar-la nosaltres o potser s'ha activat internament, per exemple, quan pulsem l'aspa de tancar la finestra. Si no la tenim en compte i la ignorem, no es podrà tancar l'aplicació de les formes normals en que se tanca una aplicació.


JDraw

void JD_Init(int screenWidth, int screenHeight, bool doubleSize);
- Incialitza el sistema gràfic, amb la resolució indicada. Si doubleSize es true la finestra serà el doble de gràn. El mode de pantalla completa encara no està implementat. El ser una finestra, es pot ficar la resolució que es vullga.

void JD_ClearScreen(Uint32 color);
- Ompli la pantalla del color especificat (format de color: 0xRRGGBB)

JD_Surface *JD_LoadSurface(char *file, bool doColorKey = false);
- Carrega una imatge en una superficie. Les superficies son com les pantalles virtuals de antaño. Si s'especifica true per a doColorKey, els pixels de color 0xFF00FF seràn transparents. Més avant faré que el color transparent siga configurable.

void JD_Blit(int x, int y, JD_Surface *surface);
- Pinta la superficie "surface" en la posició (x,y) de la pantalla.

void JD_Blit(int x, int y, JD_Surface *surface, int sx, int sy, int sw, int sh);
- Pinta en la posició (x,y) de la pantalla, el rectangle (sx, sy, sw, sh) de la superficie "surface".

void JD_BlitToSurface(int x, int y, JD_Surface *surface, int sx, int sy, int sw, int sh, JD_Surface *dest);
- Igual que la anterior, pero en compte de pintar a pantalla, pinta sobre altra superficie "dest".

void JD_Flip();
- Fa el tipic flip per a que es mostre el que havem estat fent.

void JD_FreeSurface(JD_Surface *surface);
- Quan hajam acavat amb una superficie tenim que alliberar la memòria que havia reservat o es quedaràn "memory leaks".

Uint32 JD_GetPixel( JD_Surface *surface, int x, int y );
- Obtindre el pixel (x,y) de la superficie "surface".

void JD_PutPixel( JD_Surface *surface, int x, int y, Uint32 pixel );
- Escriure el pixel (x,y) del color "pixel".

void JD_FadeOut();
- Fa un fade a negre de forma síncrona. O siga, no es torna el control a la aplicació fins que no acava el fade.

void JD_FadeIn();
- Fa un fade desde negre. Recordeu pintar primer algo o no es farà res.


JInput
Per ara aquesta API la he deixada molt coixa. Més avant l'arreglaré bonica i amb soport per a ratolí i pad.

void JI_Update();
- Actualitza l'estat dels dispositius d'entrada. S'ha de cridar a cada pas del bucle de programa.

bool JI_KeyPressed(int key);
- Comprova si s'ha polsat determinada tecla.


JSound

bool JS_Init();
- Inicialitza el sistema de só.

void JS_LoadMusic(char *musicFilename);
- Carrega una cançò.

void JS_SetMusicVolume(int volume);
- Fixa el volum de la cançò (128 màxim)

void JS_PlayMusic(int loops);
- Fa que sone la música. Si loops = -1, sona infinitament. Si loops = 0 sona una vegada, si loops = 1 sona dos vegades, etc...

void JS_PauseMusic();
- Pausa la cançò.

void JS_FadeOutMusic();
- Para la cançò baixant progresivament el volum.

bool JS_MusicPlaying();
- Si la música està sonant, torna true.

JS_Sound *JS_LoadSound(char *soundFilename);
- Carrega un só.

void JS_SetSoundVolume(JS_Sound *sound, int volume);
- Fixa el volum del só.

void JS_PlaySound(JS_Sound *sound);
- Fa que sone el só.

void JS_FreeSound(JS_Sound *sound);
- Allibera la memòria ocupada per un só.

void JS_Finalize();
- Tanca el sistema de só.


JFile

void JF_SetResourceFile(char *p_resourceFileName);
- Fixa el arxiu paquet des del que se tenen que agafar els arxius. Per defecte es "data.jrf".

char *JF_GetBufferFromResource(char *resourcename, int *filesize);
- Obté un arxiu del arxiu paquet. Torna un punter a array de char. A més en el paràmetre d'entrada/eixida "filesize" escriu el tamany d'aquest array.


Exemple
Conforme anem avançant en el cas d'estudi anirem vegent-ho quasi tot, pero vaig a escriure un xicotet programeta d'exemple. Com podeu vore per la API, no estic usant orientació a objectes, i no la vaig a usar durant el cas d'estudi, per fer-ho tot el més similar als JailGames de antaño.

El que anem a fer es carregar un gràfic que ficarem de fondo, altre gràfic que serà un set de tiles, i en pintarem un en pantalla, un mp3 de música que deixarem sonant de fondo, i un WAV que sonarà quan pulsem la tecla espai.


#include "jgame.h"
#include "jdraw.h"
#include "jinput.h"
#include "jsound.h"

Incloguem les unitats que anem a usar.


int main( int argc, char* args[] ) {
JG_Init("PROVA");
JD_Init(320, 200, false);
JS_Init();

Primer inicialitzem els sitemes. El general, el de gràfics i el de só.


JD_Surface *fondo = JD_LoadSurface("jailgames.gif");
JD_Surface *tiles = JD_LoadSurface("tiles.gif");

Carreguem els gràfics necessaris.


JS_LoadMusic("musica.mp3");
JS_Sound *bomba = JS_LoadSound("chainsaw.wav");
JS_SetSoundVolume(bomba, 4);

JS_PlayMusic(-1);

Carreguem la música, el só, i li fiquem volum al só (no se perqué s'escolta altissim, per això l'he ficat a 4). Per últim, fem que sone la música indefinidament.


JD_Blit(0, 0, fondo);
JD_Blit(0, 0, tiles, 16, 32, 16, 16);
JD_FadeIn();

Pintem el fondo i el tile, i aleshores fem el fadein. Si no haguerem pintat res, no podriem fer fade de res.


while (!JG_Quitting()) {

Entrem en el bucle de programa. S'executarà fins que arrive una senyal de tancar.


JD_Blit(0, 0, fondo);
JD_Blit(0, 0, tiles, 16, 32, 16, 16);
JD_Flip();

Pintem el fondo i el tile i fem flip, ara ja dins del bucle.


JI_Update();

if (JI_KeyPressed(SDLK_SPACE)) {
JS_PlaySound(bomba);
}

if (JI_KeyPressed(SDLK_ESCAPE)) {
JG_QuitSignal();
}

Actualitzem els dispositius d'entrada i aleshores comprovem si s'ha pulsat la tecla espai (si s'ha pulsat, fem sonar el só), i la tecla ESC (si s'ha pulsat enviem senyal d'eixir de la aplicació).


}
JS_FadeOutMusic();
JD_FadeOut();

Quan eixim del bucle fem un fadeout de la pantalla i de la música.


while( JS_MusicPlaying() ) { };

Aquest bucle farà que l'execució es pare fins que deixe de sonar la música.


JS_FreeSound(bomba);
JD_FreeSurface(tiles);
JD_FreeSurface(fondo);

Alliberem la memòria reservada per els gràfics i el só. La música la gestiona la unitat així que no ens preocupem.


JS_Finalize();
JG_Finalize();

return 0;
}

Finalitzem els sitemes. JDraw, per ara, no requereix finalització.

Ale, adjunte el códi font per si voleu començar a trastejar. El projecte es diu SuperMarioBros, perque es la plantilla que ja tenia preparada per al cas d'estudi.

També adjunte el programa ResPack, una xicoteta aplicació que vaig fer per a agafar tots els arxius de un directori i ficarlos en un JRF (Jailgames Resource File). Totes les funcions de la API lligen de un JRF, mai directament de disc, així que si voleu modificar algún arxiu tindreu que regenerar el JRF que adjunte, que realment conté els arxius que teniu al directori "recursos".

Joder, que post més llarg. Si algú te dubtes que escriga un comentari, que ja no vull allargar açò més.

dimecres, 6 de maig de 2009

Cas d'estudi: Super Mario Bros - Part I: L'editor

Be, per a començar he fet l'editor. No vaig a parlar de com està fet, ja que es Visual Basic .NET i no ens importa per al joc en sí. El que vaig a comentar es el format de mapa.

Cada mapa serà de 256x15 tiles, ja que es una restricció similar a la que tenia el joc de NES. Més avant crearé zones per al tema de entrar en les tuberies i tal, pero això ja es parlarà en el seu moment.

He dividit el mapa en dos parts: la part dels tiles que se van a pintar i la part del tipus de tile.

El array dels tiles a pintar es un array de bytes, cada un apunta a un tile que es traurà de un bitmap. Els 7 primers bits son els que ens diràn el tile a pintar. Per tant, estarém restringits a 128 posibles tiles. El bit de major ordre de cada tile ens dirà, si està a 1, que el tile té una animació.

Les animacions les he inclos perque, al treballar en 32 bits de color no tenim paleta, i resulta que el canvi de color de les monedes i els taulells amb interrogant es un canvi de paleta. El fingirem afegint al bitmap de tiles el tile en els tres diferents colors. Si un tile es animat, farà un cicle entre ell i els dos següents tiles en el bitmap de tiles.

El array de tipus de tile també es un array de bytes. Per ara he definit els següents tipus de tile:

- Buit: Es un tile atravesable, sense més.
- Solid: Es un tile que no es pot atravesar, sense més.
- Trencable: Es un tile que, quan sigues Super Mario podrás trencar de una cabotada.
- Solta moneda: Es un tile que al pegar-li cabotada et donarà una moneda.
- Solta monedes: Es un tile que al pegar-li cabotades et donarà fins a 12 monedes.
- Solta seta: Es un tile que al pegar-li cabotada soltarà una seta de Super Mario.
- Solta estrela: Es un tile que al pegar-li cabotada soltarà una estrela.
- Solta vida: Es un tile que al pegar-li cabotada soltarà una seta de vida.

Amb açò podem fer les típiques combinacions de interrogant que solta seta, taulell trencable, etc... E inclus buit que solta vida. De totes formes, tot aixó ho vorem més avant.

Així doncs, el format del mapa es el següent:

Bytes Contingut
====== =========
1 Versió del mapa
1 Nombre de caràcters de l'arxiu de tiles (x)
x Nom de l'arxiu de tiles
3840 Array de tiles a pintar
3840 Array de tiles de bloc


Podeu descarregar l'editor i el seu codi font. L'editor encara es un poc tosc, pero fa el seu treball. He adjuntat un GIF amb tiles i el GIF necesari per als blocs. A més he inclos un exemple de mapa, amb uns pocs tiles ficats.


El funcionament de l'editor es el següent: Primer tria el arxiu de tiles en la caixa de text de baix. Pots triar qualsevol arxiu d'on siga, pero per a que funcione ha d'estar en el mateix directori que l'executable. Una vegada carregat, feu click sobre un tile, feu click sobre un bloc i marqueu o desmarqueu el check d'animació; i aleshores ja podeu fer click en el mapa per a pintar el tile resultant.

En l'editor, els tipus de tile (blocs) es pintaràn com un marc sobre el tile a pintar. Supose que es prou intuitiu, pero si no ho es digau-m'ho i ho explique millor.

Si voleu modificar i/o compilar l'editor necessitareu el Visual Basic .NET 2008 Express, descarregable desde ca Microsoft. Per a editar i compilar en Linux no estic segur, ja que MonoDevelop crec que només admet C#. No obstant, per a executar el programa ja compilat desde Linux tindreu que sudoaptgetar l'ultima versió de Mono i, a més, una extensió o parxe per a executar Visual Basic. Mon, com crec que eres l'unic Linuxero que segueix activament el blog, si t'interessa m'ho dius i t'ho mire, que per casa ho tinc apuntat.

dimarts, 5 de maig de 2009

Reconsideracions

Joer, quant de temps sense escriure. Ja van dos setmanes liades. Apenes he pogut fer res de JailGames ni de res. De fet, apenes he pogut tastar encara la PSP.

De totes maneres, he estat reflexionant sobre estes últimes setmanes. Desde que vaig acavar amb el Arounders he anat botant de projecte en projecte, i cada vegada més lento. Crec que no estic centrat.

Primer vaig començar per intentar fer alguns JailGames. El Bryndiana es quedà parat pel curro que es fer les animacions. El Patman es quedà parat perque, després de reescriure-ho 2 o 3 vegades, seguia donant-me per cul la ordenació (la veritat es que va ser la época en que em trobava fatal, igual quan torne a mirar-ho resulta que es una peivada).

Vegent que no estava molt inspirat vaig decidir fer un cas d'estudi amb el Gauntlet. Pero, en primer lloc, no vaig pensar be el disseny, pel que tinc que tornar enrrere; i en segon lloc, me vaig ficar en el marrón del multijugador. No me pareix un gran exemple per a un primer cas d'estudi que vos espente a fer algo. Pitjor encara, ni tan sols estava adjuntant el codi font, com havia dit que faria.

Per tant, em feia falta reconsiderar les prioritats, el temps disponible, la utilitat del resultat i la forma de fer-ho.

Al final crec que el camí que volia seguir es el adequat. Fer un cas d'estudi amb el codi font que pugau seguir e inclus anar compilant desde casa. Pero me fa falta un projecte més simple i tipic, que a la vegada tinga alguns truquets interessants. I esta vegada en compte de decidir un joc arreu he mirat detingudament que no tinguera res que no puguera anar fent a la marxeta sense més.

El projecte que he triat es un clon del Super Mario Bros original. M'he preocupat de buscar primer si tenía facil trobar els gràfics i ja tinc recopilats tiles, sprites i demés gràfics.

Respecte a la música i sons, els ripejaré del emulador. De totes formes, no vaig a fer que la música vaja igual. En el Mario Bros la música va sonant, i quan s'està acavant el temps la música va més apresa, pero desde el punt on s'havia quedat. Aixó no ho faré.

Respecte a enemics, faré els que eixen en la primera fase i au. Si algú vol fer més com a exercici genial.

Respecte a la API, com ningú a proposat encara res, començare amb l'esborrany que tinc fet i aniré ampliant conforme faça falta. No obstant, encara m'agradaria que comentareu algo al respecte.

Respecte al codi, en cada post inclouré el codi fins a eixe moment i tot lo necessari per a compilar i jugar. També inclouré els arxius de projecte de Visual Studio 2008 per a que ho tingau fàcil. Nomes vos fa falta seguir els pasos del tutorial d'instalació d'SDL (excepte la part de OpenGL, que no fa falta). En Linux, per a instalar SDL tindreu que "sudoaptgetar" les llibreries de desenvolupament: libsdl1.2-dev libsdl-image1.2-dev i libsdl-mixer1.2-dev. Després, per a compilar, ja donaré instruccions al seu moment.

Demà comence, a vore si, donant totes les facilitats posibles, algú ho segueix.

Durant les pròximes 3 setmantes faré aixó i la expansió del Arounders, que la vaig deixar a meitant. Després me tiraré 2 setmanes de vacances en casa sol amb el nano, pel que tindré més temps per anar adelantant tot el que m'he anat deixant pel camí.