dimarts, 13 de desembre del 2022

JailDoctor's Dilemma en ordenadors de 8 bits

Be, comencem un projecte interessant! La idea es passar el JailDoctor's Dilemma a Spectrum i MSX. En el dubtós cas que acabara este projecte (cosa mai vista), podria plantejar-me dur-lo també a CPC o (qui sap!) C64.

Però no divaguem més! La realitat es que va a ser prou mes fàcil passar-lo a MSX que a Spectrum (i amb aquestos dos primers posts espere que es veja un poc més clar), per tant, començarem amb la versió de MSX.

No obstant, m’agradaria primer fer un repàs del que ens ofereix el Spectrum. En tot moment estic parlant del ZX Spectrum 48K. Els de 128K, a part de òbviament molta més memòria, no m’aporten massa avantatges (exceptuant, també, el xip d’àudio!), així que per ara em centraré en el 48K.

Comencem amb la CPU: El Zilog Z80 “de tota la vida”. Però espera, si ara passem a la memòria, perquè no te els 64K que el Z80 pot adreçar? Doncs resulta que els primers 16K es on trobem la ROM.


Els 48K restants son RAM, i podem usar-los. Però part d’eixa RAM ja te una funció, i algunes d’aquestes funcions son intocables. Per a ser exactes, la memòria on està guardada la informació de la pantalla.

El Spectrum no te modes de pantalla, com la majoria dels seus contemporanis. Així que simplement te una zona on podem escriure 256x192 píxels, des de l’adreça 0x4000 (16384, o siga, quan acaben els 16K de la ROM) fins a 0x57FF (22527). Això ens dona 6144 bytes. Com cada píxel es nomes 1 bit, cada fila de la pantalla cap en 256x8bits, o siga, 32 bytes. Com hi ha 192 files, 32x192=6144.

Però el gran problema que sempre li he trobat a la memòria de pantalla del Spectrum es la forma en que està guardada. Per desgracia no es lineal, primer tots els píxels de la primera fila, després la segona fila, etc... No, la distribució es prou mes complexa: primer va la primera fila, sí, però després va la octava fila, després la fila 16, ... fins al final, aleshores continua amb la fila 2, després la 9, la 17...


Sí, es un poc rallant, però be... La qüestió es que, si guardem cada píxel nomes amb un bit, no hi ha possibilitat de color. Simplement o està el píxel o no està. Per a donar color tenim la zona de memòria contigua, des de 0x5800 a 0x5AFF, 768 bytes. Cada byte dona color a un bloc de 8x8 píxels (si dividim la pantalla en blocs de 8x8, tenim 32x24 blocs = 768). Y cada byte conté la següent informació:

Els 3 bits de menor pes contenen el color de primer pla (o siga, el color dels píxels que estan a 1), els següents 3 bits contenen el color de fondo (els píxels a 0). El bit 6 ens diu si usem els colors brillants o els obscurs. I l’últim bit si ha de estar fent flash (que gilipollada, no?).

Si recordem la paleta del Spectrum, els 7 primers colors son obscurs i els altres 7 clars. Com nomes tenim que triar entre 7 colors, amb 3 bits tenim prou. Però esta es la raó per la que no es poden usar els colors brillants i obscurs a l’hora en un mateix bloc de 8x8.

I açò de tindre que ficar la mateixa combinació de colors a cada bloc de 8x8 es el que du al famós “color clash”.

La qüestió es que podem arribar a usar pràcticament tota la resta de RAM, a partir de 0x5B00. Al final son uns 41K que tenim disponibles. En eixe espai ha de cabre el joc sencer: codi, imatges, musica, textos... tot.

Ah, per finalitzar, el ZX Spectrum 48K no te xipset de só. Nomes podem activar o desactivar el bit 4 del port 0xFE per a que el altaveuet pite. Així i tot intentarem traure-li profit.


En el pròxim post parlaré del MSX per a que també tingau un mínim coneixement de les màquines en les que treballarem. I seguidament ens ficarem a transformar les dades del JDD a formats mes reduïts i millor donats a les reduïdes màquines en les que anem a treballar.

divendres, 23 d’abril del 2021

JailScript (IV): La Màquina Virtual

Aquest es el quart escrit d’una sèrie que repassarà el desenvolupament d’un llenguatge de programació amb el qual poder fer JailGames de forma ràpida i còmoda. Hui començarem a vore com s’executarà el codi que escrivim amb JailScript.

Els fonaments

Una de les primeres cosses que em vaig plantejar a l’hora de dissenyar el llenguatge no està realment relacionat amb el llenguatge... be, sí... però no... es complicat...

Els llenguatges de programació clàssics es compilen a codi màquina. Un programa es poc mes que una "ristra" de codi màquina, instruccions que el processador entén directament. En el nostre cas, qui volem que interprete les nostres instruccions no es el processador directament, sinó el nostre programa. Així doncs, tenim dos possibilitats:

  • Interpretar el llenguatge al vol: Així es com funcionaven els BASICs de la era de 8 bits, o inclús GW-BASIC i familiars. Conforme es van llegint els comandos de text s’interpreten i s’executen. Açò te el problema, entre altres, de ser extremadament lent.
  • Compilar el llenguatge a un "codi màquina propietari", o byte code, que després una màquina virtual interpretarà i executarà. D’aquesta forma, la part mes lenta, que es anar llegint el text, decidint quines instruccions són i com actuar, es fa una vegada, abans d’executar res, generant una "ristra" d’instruccions. La màquina virtual es comportarà com si fos un "emulador", llegint aquestes instruccions i executant-les. Encara que es prou mes lent que un programa compilat a codi màquina, es molt més ràpid que l’anterior opció. Així funciona Java o .NET. També Lua, que es integrable en el teu propi codi; o Javascript en els navegadors; o Python, PHP, Ruby...

Per què?

Si es més ràpid compilar, per exemple, des de C a codi màquina i au, per què calfar-se el cap? Primera, perquè podem: Un JailGame funciona perfectament sobrat en qualsevol màquina de hui en dia... o de fa 20 anys inclús. Segona, ja que podem, tindre una màquina virtual ens dona certs avantatges i comoditats:

  • No hi ha que recompilar cada vegada. Compilar en gcc es prou mes lent que el que tardarà el nostre parser. A més d’estalviar-se lo farragós que es compilar un binari "legal" en Mac hui en dia.
  • Depuració. Escriure un depurador per a la màquina virtual es relativament fàcil i pots controlar tots els aspectes.
  • Portabilitat. Si es volen dur els jocs a altra plataforma, nomes hi ha que escriure la màquina virtual per a eixa plataforma, i els jocs en principi funcionaran gratis.
  • Comoditat. C/C++ mola molt i es super potent, però treballar amb una plataforma que estiga centrada en fer jocs, llevant tot el que es innecessari o superflu de davant, ajuda a que el desenvolupament siga mes fluid.

Tipus de màquines

Generalment hi ha dos tipus de màquines més usades. Màquines de registres i Màquines de pila.

Les màquines de registres son les més habituals, sobre tot per a processadors reals. El processador te accés a la memòria del sistema, però també disposa de una memòria interna super ràpida, anomenada registres, que usa per a fer les operacions que te en eixe moment entre mans. Així, es habitual que tinguen un registre acumulador A per a les operacions aritmètiques, registres X o Y per a iteradors, etc... els registres son molt ràpids, però molt cars, així que solen haver nomes uns pocs. En el cas de ser màquines virtuals, solen haver més registres i solen ser menys especialitzats, podent fer quasi totes les operacions des de quasi tots els registres. Dels dos tipus es el més difícil de generar codi, pel fet de tindre que gestionar la pressió sobre els registres a l’hora de assignar valors i operacions al limitat nombre de registres. També sol ser, no obstant, el tipus de màquina més ràpid.

Les màquines de pila no son habituals com a processadors reals, i menys hui en dia. En aquest tipus de màquines els operadors i les operacions es van deixant caure en una pila executant-se seguint la notació polaca inversa. Aquest tipus de màquina es més fàcil de fer i més fàcil de compilar per a ella, així que en principi es el tipus que he triat.

BYTECODE

Les instruccions de que disposarà la màquina aniran evolucionant durant el desenvolupament per a adequar-se a les necessitats, però ja podem vislumbrar algunes instruccions que necessitarem:

PUSH <numero>
Per a ficar un número en la pila
POP
Per a traure un número de la pila
LD <adreça>
Per a carregar un número d’una adreça de memòria a la pila
ST <adreça>
Per a guardar el numero al cim de la pila en memòria
ADD, SUB,
MUL, DIV,
AND, OR,
NOT, NEG,
SHR...
Operacions matemàtiques varies
JMP <adreça>
Bot incondicional del codi a l’adreça especificada
JT <adreça>,
JNT <adreça>
Bot si el cim de la pila es zero (o si no es zero)
CALL <adreça?>
Cridar a una funció interna (escrita en el propi llenguatge)
RET
Tornar des d’una crida a una funció interna
CALLEX <valor>
Cridar a una funció externa (escrita en C)

Exemple

Per a il·lustrar un poc com funcionaria, un exemple de codi a pseudo-bytecode:

var a as number = 4

a = a + 5




PUSH 4
ST a

LD a
PUSH 5
ADD
ST a
Fica un 4 en la pila
Agafa’l de la pila i guarda'l en "a"

Agafa el que hi ha en "a" i fica-ho en la pila
Fica un 5 en la pila
Suma els dos números al cim de la pila
Guarda el resultat en "a"

Es pseudo-bytecode perquè en compte de ficar una adreça de memòria corresponent a la variable he ficat la variable, per estalviar-se el concepte de variable-memòria i la gestió de memòria que vorem en un capítol més avant.

La Pila

Per últim, volia il·lustrar com funciona la pila, per si algú no ha captat la idea intuïtivament. Anem a executar el codi anterior i vorem com està la pila en cada moment. Al principi la pila està buida.

	PILA: []

La primera instrucció fica un 4 en la pila:

	PUSH 4  'PILA: [4]

La següent agafa el valor que hi ha al cim de la pila, el lleva, i el guardarà en memòria

	ST a	'PILA: []

Ara agafa el que hi ha en memòria i ho fica en la pila:

	LD a	'PILA: [4]

Ara fica un 5:

	PUSH 5	'PILA: [4, 5]

Ara executa la instrucció ADD, que agafa els dos valors al cim de la pila, els suma i deixa en la pila el resultat:

	ADD	'PILA: [9]

Per últim, agafa el que hi ha al cim de la pila i ho guarda en memòria

	ST a	'PILA: []

 

Mes avant vorem més exemples de bytecode i com funciona la pila. Crec que per hui ja hi ha prou. El pròxim post escriuré sobre el tokenitzador, que es altre tema satèl·lit al llenguatge en si.

dijous, 22 d’abril del 2021

JailScript (III): Lexemes, Gramàtiques i Contextos

Aquest es el tercer escrit d’una sèrie que repassarà el desenvolupament d’un llenguatge de programació amb el qual poder fer JailGames de forma ràpida i còmoda. En aquest post vorem una descripció pseudo-formal del llenguatge.

Nivell lèxic

A nivell lèxic, el llenguatge distingirà entre tres tipus genèrics de paraula:

  • Numèrics: 1 o més dígits, seguits opcionalment per un punt "." i 1 o mes dígits.
  • Alfanumèrics: Una lletra o "_", opcionalment seguida de lletra, dígit o "_".
  • Cadenes: doble cometa (") fins a la següent doble cometa.
  • Símbols: Operadors del tipus "=", ",", "+", "<=" o inclús "\n".

Els numèrics sempre seran constants numèriques i ja està. Però els alfanumèrics poden ser paraules clau del llenguatge (IF, ELSE...), tipus de dades (NUMBER, STRING o els que defineixca l’usuari), funcions (internes o externes) o variables. Les cadenes agafen qualsevol caràcter que hi haja entre les dobles cometes. Per últim, si no es numèric, alfanumèric o cadena, es comprovarà si es un dels operadors (matemàtics, lògics, de control...) coneguts pel llenguatge. En cas contrari, tindrem un error de sintaxi.

Gramàtica

Vaig a expressar la gramàtica del llenguatge, o siga les frases vàlides, en una espècie de pseudo forma de Backus-Naur, però sense crear realment regles de producció. Es un poc rotllo així que passe de liar. Pero abans de vomitar-les totes, un poquet d’explicació amb un exemple:

ASSIGNSTAT = <ID_VAR> = <EXPR>

Espera... que cony es això? Explique: Vaig a definir una assignació de valor a una variable, bàsicament açò:

peric = delgat + 3

“ASSIGNSTAT” es el nom d’esta regla o frase. “ID_VAR” representa a una paraula alfanumèrica asociada a una variable ja declarada abans (en el exemple, “peric”). “=” se representa a si mateix. <EXPR> representa a una expressió, o siga, una combinació de operacions matemàtiques i lògiques entre constants, variables i resultats de funcions que donarà com a resultat un valor (en l’exemple “delgat + 3”).

STRUCTSTAT = STRUCT <UNK> [ <UNK> AS <TYPE> ]+ END
FUNSTAT = FUNCTION <UNK> ( [ <UNK> AS <TYPE> [ , <UNK> AS <TYPE> ]* ) [ AS <TYPE> ] <LOCAL> END
VARSTAT = VAR <UNK> AS [ ARRAY OF <NUM> ] <TYPE> [ = <EXPR> ]
CONSTSTAT = CONST <UNK> = <EXPR>
ASSIGNSTAT = <ID_VAR> = <EXPR>
CALLSTAT = <ID_FUN> ( [ <EXPR> [ , <EXPR> ]* ] )
IFSTAT = IF <EXPR> THEN <LOCAL> [ ELSE <LOCAL> ] END
WHILESTAT = WHILE <EXPR> DO <LOCAL> END
REPEATSTAT = REPEAT <LOCAL> UNTIL <EXPR>
FORSTAT = FOR <UNK> = <EXPR> TO <EXPR> [ STEP <EXPR> ] DO <LOCAL> END
RETURNSTAT = RETURN [ <EXPR> ]

<UNK> es refereix a un identificador que no s’haja definit encara en el àmbit actual.

<TYPE> es refereix a un tipus que ja s’haja declarat.

<ID_VAR> i <ID_FUN> es refereixen a identificadors assignats a una variable i a una funció.

<EXPR> es refereix a una expressió, tindrem un capítol nomes per a les expressions més avant.

<LOCAL> es refereix a un context, ara ho vorem.

Contextos

Hi ha dos tipus de context definits: Global i local. El context global es el que hi ha a la part mes externa del programa. En eixe context nomes podem declarar variable, constants, estructures i implementar funcions.

GLOBAL = [ VARSTAT | CONSTSTAT | STRUCTSTAT | FUNSTAT ]*

Als contextos locals (que es corresponen als elements <LOCAL> de les gramàtiques anteriors) no es poden declarar estructures ni implementar funcions, però poden aparèixer totes les demes regles.

LOCAL = [ VARSTAT | CONSTSTAT | ASSIGNSTAT | CALLSTAT | IFSTAT | WHILESTAT | REPEATSTAT | FORSTAT | RETURNSTAT ]*

Àmbits

Les variables es declaren a un cert àmbit. Les variables declarades al context global tenen l’àmbit més ample, al poder ser accedides des de qualsevol context (el que coneguem com a “variables globals”).

Per altra part, les variables declarades dins d’un context local nomes podran ser accedides des d’eixe context i els contextos interns. Per exemple, si tenim una funció i dins d’ella declarem una variable “teib”. I a més dins de la funció tenim després un “if”, i dins del “if” declarem una variable “peiv”. Des de dins del “if” podem accedit tant a “teib” com a “peiv”, però desde la funció, fora del “if”, tant abans com després, no podrem vore “peiv”.

Els contextos i els àmbits es corresponen quasi totalment, excepte per les següents excepcions:

  • Els paràmetres de una funció formen part de l’àmbit del context <LOCAL> de dins de la funció.
  • La variable d'iteració d’un bucle FOR forma part de l’àmbit del context <LOCAL> de dins del FOR.

A més, STRUCT crea una especie d’àmbit “privat”.

Si re-declarem una variable ja declarada en un àmbit pare, la nova variable ocultarà a l’anterior, no havent forma de accedir a l’anterior des de l’àmbit actual. El compilador soltarà un “warning” quan ho detecte. Obviament, açò no afecta als STRUCTs.


Que rollo! En el pròxim post canviaré un poc el focus i parlaré de la màquina virtual.

dimecres, 21 d’abril del 2021

JailScript(II): El Llenguatge

Aquest es el segon escrit d’una sèrie que repassarà el desenvolupament d’un llenguatge de programació amb el qual poder fer JailGames de forma ràpida i còmoda. En aquest mostrarem com serà el llenguatge.

Whitespace i comentaris

Els espais en blanc, les tabulacions i els salts de línia seran considerats “whitespace” i s’ignoraràn, sent d’única utilitat com a separadors entre la resta de elements. Nomes els espais que estiguin entre dobles cometes (“) seran processades i incloses al “string” corresponent.

La paraula clau “rem” o el operador cometa simple “ ‘ “ indicaran el principi d’un comentari, fent que s’ignore la resta de la línia.

Variables i Tipus

Tindrem els tipus de dades number, string i els que pugem definir mitjançant estructures. El tipus number es un nombre decimal en coma flotant de 4 bytes, equivalent a float de C, i serà l’unic tipus numèric del llenguatge. El tipus string s’usarà per a cadenes de text i la seua implementació encara està un poc en l’aire. La lògica booleana es farà a traves del tipus number, sent 0 igual a fals i -1 igual a vertader. Es definiran les constants de sistema true, que valdrà -1, i false, que valdrà 0.

Les variables es declararàn de la següent forma:

var peiv as number = 4

No es obligatori especificar un valor al declarar una variable, però si es fa es pot ometre el tipus:

var meim as string ' Açò es vàlid
var teib = 4 'Açò també es vàlid

La forma que tenim de definir nous tipus es amb "struct":

struct tipus_arounder
    x as number
    y as number
end

var arounder as tipus_arounder

Accedirem als membres del struct amb l’operador “.”, com en C i molts altres llenguatges.

També es podran declarar arrays, amb la següent sintaxi:

var arounders as array of 10 tipus_arounder

I accedir a ells amb l’operador [], com en C:

peiv = arounders[2].x ' Accedim al tercer membre del array

Funcions

Es podran definir funcions, tant externes com internes. Les externes es definiran des de C, mentre que les internes es definirien de la següent forma:

function duplicar(valor as number) as number
    return valor * 2
end

Una funció pot no retornar ningun valor, però si en retorna s’ha d’especificar el tipus d’aquest valor, com en l’exemple anterior.

Condicions

Per ara nomes tinc planificat incloure la clàusula “if”, però potser mes avant incloga algun tipus de “switch”:

if arounder[1].x = arounder[2].y then
    arounder[3].y = arounder[3].y - 1
else
    reset_arounders()
end

No fan falta parèntesi al voltant de l’expressió avaluada. El operador de comparació es “=”, ja que, al contrari que en C, no es poden fer assignacions en mig d’una expressió. La clàusula “else” es, per suposat, opcional.

Bucles

Tenim tres tipus de bucles: “for”, “while” i “repeat”:

for i as number = 0 to 9 step 1 do
    arounders[i].x = 0
end

La variable iteradora pot existir prèviament o ser declarada in-situ per a us del bucle, com en l’exemple. El bucle s’executarà per a tot el rang, inclosos el nombre inicial i el final (en el cas del exemple, s’executarà tant per al “0” com per al “9”. La clàusula “step” es opcional i indica quant s’ha d’avançar en cada iteració. Si no s’especifica es suposa “1”

while peiv < 4 do
    peiv = peiv + 1
end

repeat
    peiv = peiv - 1
until peiv = 0

De nou, tant en el “while” com en el “repeat”, no fan falta parèntesi al voltant de l’expressió avaluada. Probablement acabe afegint les clàusules “break” i “continue”, que tindrien el seu significat habitual.

En el pròxim post parlaré de lexemes, gramàtiques i altres temes raros

dimarts, 20 d’abril del 2021

Jailscript (I): Consideracions Prèvies

Aquest es el primer escrit d’una sèrie que repassarà el desenvolupament d’un llenguatge de programació amb el qual poder fer JailGames de forma ràpida i còmoda

Per què des de zero?

Des de la meua època en Gavina Games he estat pensant, planificant, aprenent... sobre la creació de llenguatges de programació, compiladors i màquines virtuals. En un principi vaig intentar usar llenguatges ja existents, com Lua, Squirrel o Angelscript. El problema es que ningun d’ells em resultava còmode d’usar. Al menys no més còmode que fer-ho tot en C. A més, la idea de crear jo tant el llenguatge com la màquina virtual encarregada de executar els programes creats amb eixe llenguatge era molt atractiva. Al cap i a la fi, tot açò ho faig per diversió i aprenentatge.

Respecte al compilador, existia la possibilitat de usar Bison i Flex, però a part de quasi morir d’avorriment perdia l’oportunitat d’aprendre com fer un compilador. Al menys vaig aprendre sobre gramàtiques lliures de context.

Per últim, podria haver usat la màquina virtual de, per exemple, Lua. Però de nou, m’agradaria tindre el control de l’execució del bytecode i la integració amb el programa amfitrió en C.

Objectius

El primer llenguatge de programació que vaig aprendre, ja fa més de 30 anys, va ser BASIC, així que te un lloc a la meua memòria inesborrable. Després, al llarg dels anys, he usat en diverses ocasions Visual Basic. Així que la meua idea per al llenguatge es un BASIC simple però modern.

Respecte al paradigma, ja no es una qüestió tan clara. La primera vegada que em vaig plantejar fer un llenguatge tenia en ment un paradigma fortament orientat a events, però això ha d’anar emparellat amb un sistema que poder controlar a base de events. Consistiria en tindre arbres de entitats (Escena -> Mapa -> Personatge) que generarien events (col·lisió, tecla polsada, x segons han passat...) i el codi estaria dins de cada event, sense bucle principal. El framework que me vaig crear durant Gavina Games funcionava de forma similar, inspirat per Cocos2D, Unity..., però tot en C++. Haver tingut un llenguatge de script amb el que treballar sense recompilar i enviar al iPhone haguera sigut genial.

Més avant, ja fora de Gavina Games, sempre he buscat simplificar el codi dels meus jocs al màxim. Vaig llegir algunes notes sobre SCUMM. Ja en l’època del C64 usava un llenguatge de script propi amb multitasca col·laborativa. O siga, tindre mini-programes executant-se a l’hora, cada un amb el seu propi codi que nomes es preocupa de lo seu, en compte de tots en el bucle principal mesclats. El meu Math Wars usa una aproximació similar (però de nou tot en C++). Vaig pensar de nou en usar Lua per a fer alguna cosa així, però no vaig trobar que Lua tinguera suport per a tornar el control a C en un cert moment i a la següent iteració continuar per on anava (un YIELD), encara que si que ho te per a les seues corutines. Ron Gilbert va fer algunes modificacions en Squirrel per a aconseguir exactament això per a Thimbleweed Park, i probablement es puga fer el mateix en Lua. Però de nou, quan mes aprenc d’aquestes coses més ganes em donen de fer-ho jo mateix.


Treball previ

Conforme van passant els anys, els projectes es van solapant i el que no pareixia tindre utilitat de repent pareix tindre-la. Fa uns anys vaig començar a treballar amb microcontroladors, i una de les coses que mes em frustra es que solen usar la arquitectura Harvard, i la part del programari no es modificable durant un us normal. O siga, tu pujes el programa des de l’IDE de Arduino, per exemple, i el programa es el mateix fins que no el tornes a connectar i “cremar” un nou programa.

NOTA: No es completament cert, la part del bootloader pot reprogramar la memòria Flash al inici. Es el que fa l’IDE de Arduino, enviant al bootloader per comunicació sèrie el nou programa per a que reprograme la flash. Però no es fàcil ni pràctic.

La qüestió es que açò limitava les possibilitats de fer una consola a la que connectar cartutxos amb jocs. Una forma de solventar-ho era el que ja vau vore per Telegram: Basat en https://youtu.be/APwnDlavXlw i en https://www.tinyjoypad.com/, la consola ho te tot... excepte el propi microcontrolador! Així, cada cartutxo el que porta es el microcontrolador sencer amb el joc ja “burnejat”. Tenint en compte que usava Attiny85, que costen menys d’1€, tampoc era tan descabellat.

L’altra opció era crear una màquina virtual que executara bytecode extern. El microcontroladors de ATMega poden funcionar, com a molt, a entre 16 i 20 MHz, així que potser podria fer funcionar alguna cosa similar a un Spectrum o MSX, però tenint en compte que volia generar una senyal PAL, amb una quarta part de la resolució. Duc amb eixe projecte a ratos des de fa anys. Així va naixer PaCO, la Paco Console. Amb PaCO vaig aconseguir acabar el meu primer llenguatge de programació. Basat en BASIC i tot això. Pero en aquest cas es un llenguatge no funcional. O siga, no hi ha funcions. Tot va a base de GOTO i GOSUB, com “antanyo”. Va ser, no obstant, una gran experiència d’aprenentatge. I, en part, va a ser la base de la que vaig a partir.

L’actualitat

De fa uns anys a ara han aparegut diverses “Fantasy Consoles”, com Pico-8 o Tic-80, que han canviat un poc els meus objectius. La veritat es que tindre els editors integrats pot ajudar molt a accelerar el desenvolupament. M’agradaria fer alguna cosa similar, encara que estic debatent-me fins a quin punt.

La qüestió es que, tornant al llenguatge en sí, el paradigma, les capacitats, la integració i altres coses no son estrictament imprescindibles ni inamovibles. Puc fer una versió simplement funcional del llenguatge, i mes avant fer una versió “++” amb suport per a classes. Puc integrar-ho en un sistema clàssic, o en un sistema de funció “loop”, o en un sistema de events, o en un sistema de entitat-component...


Així que, mans a l’obra. Aniré comentant sobre cada aspecte del desenvolupament que em parega interessant.

divendres, 13 de desembre del 2019

Sequències

Hui he acabat el menú de selecció de personatge i la sequència d'historieta que va abans de jugar.



També he reemplaçat totes les músiques per midis. Sonen estupendament en Windows, ja vorem si sona algo en els demes sistemes operatius. Per ara es queda així.

Es divendres, en un horeta me pire i no vaig a parar per casa en tot el cap de setmana, així que no tinc ganes de començar res ara. El dilluns ja comence amb el mòdul del joc. De fet, en este ratet vaig a pegar-li una ullada al codi del port a Delphi que vaig fer, ja que la part del joc es la única que vaig portar.

dijous, 12 de desembre del 2019

First Commit!

Ale, ja están totes les músiques i gràfics preparats. També he deixat preparat el projecte i l'he pujat a un repo public en bitbucket.


Ja está implementat el logo de ICEKAS, el titol del joc, el menú principal i he començat a implementar el menu de selecció de personatge i dificultat.

Supose que val la pena comentar la curiositat del dia per a que quede constancia per a la posteritat: Estava mirant el video que ha pujat Sergi per a revisar com era el joc original, quan he vist esta pantalla:


El menú de selecció de personatge i dificultat... sols que el gràfic original es el següent:


Aleshores... Si els personatges ja están en la pantalla, com els lleva quan encara no estàn desbloquejats!? Pos molt fàcil: pinta un quadre negre damunt i després algunes estreletes XD


Així que com podeu vore, ho he portat tal qual. Es un port fidel!