L'idée est venue alors que je voulais faire quelques jeux rétro pour m'amuser et refaire mon portfolio. Je pensais à un shooter comme Fantasy Zone, un platform/puzzle game sur un tableau, voire peut-être un racer basé sur Highway Runners. En faisant joujou avec divers frameworks, j'ai vu qu'ils ne permettaient pas vraiment de faire des effets rétro style linescroll, reprogrammation de palette (voire palette tout court d'ailleurs), modifier les maps/tilesets dynamiquement…
Alors je me suis dit que j'allais faire un "GPU virtuel" en me basant sur une borne d'arcade des années de ma naissance, permettant nativement ce genre d'effets un peu oubliés, quitte à mettre des contraintes. Et que pour le défi, j'allais "émuler" entièrement la machine sur le GPU avec des shaders. L'idée est venue de le faire pour le web car il y a un intérêt à réduire la taille des ressources, avoir le GPU qui fait un max pour limiter l'usage du Javascript, et la facilité ensuite de distribuer les jeux faits par la communauté. Et j'ai pris la borne d'arcade car ça m'a toujours fait rêver de travailler avec la puissance et les fonctions supplémentaires qu'elles avaient comparé aux consoles de salon.
L'idée technique c'est d'avoir un accès facile en lecture/écriture à la mémoire vidéo pour les maps, tilesets/sprites et palettes, qui sont en interne des textures séparées. La mémoire est adressée en 2 dimensions, ce qui permet de facilement se la visualiser mais aussi extraire des parties des sprites/maps/palettes existantes et les réutiliser. Un outil de conversion avec un langage simple permet d'empaqueter des objets sur ces textures, qu'on re-crée rapidement en cas de modification.
palette Persos { sprite mario: 'mario.png' sprite luigi: 'mario-luigi-2.png' [rect(80, 20, 96, 36)] } palette Level1 { map mainbg: 'mainbg.tmx' } palette Level1-brighter {}
Ensuite dans le jeu on peut accéder facilement à ces ressources, automatiquement toutes chargées au démarrage (puisque sur la texture principale) en 3 requêtes HTTP.
function *main(vdp) { while (true) { vdp.drawBG('mainbg'); vdp.drawObj('mario', 0, 0); // Wait VBLANK yield 0; } }
Mais aussi:
function *main(vdp) { // Modify palette const colors = vdp.readPalette('Level1'); colors.forEach( (col, index) => { colors[index] = color16.multiply(col, 2.0); }); vdp.writePalette('Level1-brighter', colors); // Copy tile 2 over tile 1 (simulates arbitrary DMA) const tile2 = vdp.readSprite(vdp.tileset('mainbg').tile(2)); vdp.writeSprite(vdp.tileset('mainbg').tile(1), tile2); while (true) { // Normal intensity vdp.drawBG('mainbg'); // x2 color intensity vdp.drawBG('mainbg', { palette: 'Level1-brighter', scrollX: 2 }); yield 0; } }
Pour donner une idée des specs, on a 4 BGs, 512 sprites, 16 couleurs par sprite/tile parmi 4096 (12 bits), 256 palettes. Les sprites sont simples & rapides (et batchés) et peuvent être étirés individuellement. Les BGs sont plus complexes, supportant notamment une matrice de transformation affine (2x3) permettant la translation/rotation/scaling qui peut être reprogrammée à chaque ligne de balayage (qui peut être horizontal, ou vertical comme à l'époque) permettant à peu près tous les effets 16-bits qu'on imagine, de Mario Kart aux tremblements de terre de Gynoug. Par défaut il n'y a pas d'effets de transparence sauf pour les 32 derniers sprites, qui supportent un packing addition de couleur + ombres, histoire de pouvoir tout dessiner en 3 drawcalls.
Au début je ne voulais pas forcément mettre de limitations arbitraires. Il faudrait forcément en avoir, vu que tout tient sur une texture, mais je les ai mises assez haut pour que ça ne gêne pas. Après tout c'est un outil pour aider à faire ce que tu veux, pas pour te limiter. Pour ça j'ai 2 versions : une "web", sans limitation (résolution arbitraire, effets de transparence sur tous les objets, support de l'alpha blending "bête", palette 32 bits "true color", tilesets/sprites 8 bits (256 couleurs), infinité de BGs et sprites dessinés dans l'ordre d'invocation, pas de système de priorités) et une version "home" qui met des limites permettant une signature "16 bits", et force à l'utiliser un minimum correctement histoire d'avoir des performances excellentes sur toutes les machines, un truc auquel je tiens particulièrement vu qu'on parle d'un navigateur web.
La version "web" serait pour mes petits jeux, mais je pensais à développer et distribuer la version "home". L'idée est de permettre de s'amuser avec des effets simples mais désormais oubliés, d'apprendre comment fonctionnaient les consoles à l'époque, se challenger, d'avoir une communauté où on se partage "ah comment tu fais tel ou tel effet?" et d'essayer d'obtenir des effets créatifs, ou au contraire exactement identiques aux arcades (cette fausse 3D).
Qu'est-ce que vous pensez de l'idée ? Est-ce quelque chose qui pourrait avoir un intérêt ? Des remarques, suggestions ? Voire envie de comprendre comment on fait/ferait telle ou telle chose ? Ca m'intéresse beaucoup, histoire d'orienter le développement (vers la poubelle au pire) et offrir quelque chose qui ait un intérêt
