Stage 4, un petit bout de code devient grand (Partie 1)

On approche doucement du scope fixé pour en finir avec la beta. Tout de même, Super Tilt Bro v1.0, ça enverrait ! Il reste quelques petites choses à faire : améliorer quelques animations, rééquilibrer quelques mécaniques et faire une quatrième arène... Sans spoiler, cette dernière arène va s'avérer être un mini projet à part entière, les congés du mois de mai ne seront pas du luxe.

L'idée de départ est simple. Il existe une arène avec des plateformes mouvantes, mais cette arène est volontairement difficile, il s'agit de réussir à rester en équilibre au-dessus du vide. Du coup, les joueurs occasionnels l'évitent, se privant de plateformes mouvantes. Faisons une arène plus simple avec des plateformes mouvantes. Ce sera juste un nouvel arrangement de plateformes, réutilisant du code existant, tout se passera bien.

Quelques minutes passées sur Super Smash Bros sont suffisantes pour trouver un arrangement sympa à jouer. Il s'agit de l'arène Mute City de Super Smash Bros 4. Il dispose d'une plateforme principale plus petite que d'habitude et de deux plateformes mouvantes qui ajoutent de la largeur à l'arène. Il n'y a plus qu'à tenter de reproduire cette idée dans Super Tilt Bro. En plus, ça va aller vite, je dispose d'un merveilleux script qui prend du JSON en entrée et écrit l'assembleur tout seul.

MBvmSf6.png
De gauche à droite :
The Pit : l'arène qui fait peur !
Mute City : le pod en bas sert de plateforme stable, les plateformes mouvantes suivent les virages
Le script : à partir de la description des plateformes, il génère l'assembleur d'une arène

Le format JSON des arènes de Super Tilt Bro est simple, mais l'écrire à la main reste désagréable. (C'est là que tout commence à barrer en c*uilles.) C'est l'occasion idéale pour améliorer mes outils. Tiled étant la référence open source, aucune question à se poser, la première étape est de définir comment organiser les informations. Après quelques tâtonnements, l'organisation suivante est arrêtée:

Les emplacements spéciaux (comme les points de spawn) sont placés dans un calque d'objets nommé "spots". Les plateformes sont placées dans un calque d'objets nommé "platforms" et peuvent être de type "hard" (on ne peut pas passer au travers) ou "smooth" (on peut passer au travers). Les éléments esthétiques sont des images alignées sur la grille. Enfin, tout calque inconnu est ignoré, ce qui est pratique pour dessiner le résultat final même si le moteur n'en a pas besoin.

1FMfd9z.png
L'arène dans Tiled, les décors gris sont ignorés, les scripts les recalculeront.

Comme Tiled permet d'exporter ses cartes en JSON (et que j'adore le JSON), il y a juste à faire un nouveau script pour convertir les fichiers exportés par Tiled en fichier d'arène pour Super Tilt Bro. Le processus est donc: Dessiner la carte dans Tiled, lancer plein de scripts et pouf on obtient une ROM.

Hcw7BI5.png
Le résultat de tous ces scripts, une nouvelle arène \o/

C'est magique, c'est facile, ça va super vite... Et ça m'a pris la journée de coder tous ces outils.

Il n'y a plus qu'à ajouter les plateformes mouvantes, avec du code déjà prêt. Ça va être vite-fait... Non ?
avatar
Stage 4, un petit bout de code devient grand (Partie 2)

Changement d'idée ! Les plateformes mouvantes c'est du déjà-vu. Pour ce niveau il faut un bonus apparaissant régulièrement, flottant au-dessus des joueurs, celui qui arrive à le casser gagne des super-pouvoirs.

qptX2as.gif
The Hunt : quatre jours de code, et encore un niveau dont je suis fier !

Voyez comme les mouvements de l'orbe sont souples. On est loin de "un mouvement sinusoïdal ça semble vivant". Pour obtenir cet effet, on utilise une autre de mes techniques favorites : les steering behaviours. Aucune idée de comment ça se traduit, appelons les simplement steering behaviours.

Les steering behaviours nous viennent principalement des recherches sur l'IA. Ils permettent de déplacer des objets de façon naturelle tout en visant certains objectifs. Comme un orbe qui voudrait se positionner entre deux joueurs sans passer trop prêt de chacun d'eux.

Une fois par frame, on calcule le vecteur de déplacement idéal de l'objet pour chaque objectif, puis on additionne tous ces vecteurs à la vélocité de l'objet. Ça nous donne une nouvelle vélocité qui respecte au mieux chaque objectif en prenant en compte l'inertie de l'objet.

kYQn9H7.gif
Steering behaviours : le vecteur du succès !

Ce qui est génial avec ce système c'est qu'on obtient un mouvement fluide, et surtout qu'on peut penser chaque objectif séparément. On peut créer des comportements particulièrement complexes en implémentant trois ou quatre fonctions super simples. Enfin, comme chaque comportement est indépendant, il est facile d'en ajouter ou d'en supprimer pour essayer différentes combinaisons. L'exemple illustré est ce que j'avais en tête en commençant, puis j'ai remarqué que c'était plus sympa de ne pas fuir les joueurs, mais juste d'essayer de se placer au-dessus d'eux, un changement très simple.

Voilà, bilan la nouvelle arène est prête et m'aura coûté mes vacances. Si vous pouviez y jeter un œil et me remonter vos remarques/bugs avant la prochaine release, je vous en serais éternellement reconnaissant. Les points à avoir à l'œil sont : la fréquence d'apparition de l'orbe, la puissance du buff, le mouvement de l'orbe (est-ce amusant d'essayer de l'atteindre ?). Voici une ROM de test : http://blabla.wontfix.it/Super_Tilt_Bro_Playtest(E).nes
avatar
Merci pour les explications des steering behaviours !
Très intéressant et bien illustré.
Faut que je teste tout ça asap smile
avatar@originalfei
In pixels we trust.
ORE WO DARE DA TO OMOTTE YAGARU !
Changement de plan, perspectives chamboulées

J'ai un plan. Avec Super Tilt Bro. qui commence à ressembler à quelque chose, il faut peaufiner quelques animations, ajouter des effets ici et là et on peut appeler ça une version 1.0. Ensuite, produire un batch d'une petite dizaine d'exemplaires pour se donner l'impression d'être un vrai producteur de homebrew sans se ruiner. Enfin, le chantier de la 2.0 et de son nouveau moteur révolutionnaire peut commencer.

C'est super sympa de chercher à produire ses cartouches en petit batch. On passe beaucoup de temps à fouiller l'internet pour trouver des solutions économiques. Un boitier de cartouche seul, ça coûte facilement dans les 5€ (il y a des jeux entiers moins chers que ça !) Donc beaucoup de lèche-vitrine en ligne et de discussions avec des petits producteurs de circuits imprimés pour reproductions.

JhI2zWh.jpg
Tout ce qu'il faut pour faire des cartouches ! Il ne manque plus que le logiciel sad

Tout se présente donc bien, sauf qu'entre temps Glutock a décidé de dévoiler au monde un truc génial. Un module wifi greffé dans la cartouche ! De l'or en barre, du porn pour geek ! Vous imaginez un peu ce que donnerait Super Tilt Bro. en réseau ? Pas moi. Il faut que j'essaye pour voir !

On s'attaque peut-être à un gros morceau. On veut porter un jeu local en réseau, ce qui est réputé très casse-gueule. Le jeu en question est un jeu temps réel qui supporte très mal la latence mais doit rester jouable avec ~50ms de ping. Enfin, on est sur la NES, il faut faire très attention au budget CPU et RAM. Tant pis, c'est trop beau comme idée, on fonce tête baissée !

La première étape est de penser au protocole de communication entre les NES. Une nuit blanche et c'est réglé. Le protocole est composé de quelques messages simples faits pour être envoyés en UDP. Chaque NES compte le nombre de frames depuis le début de la partie (appelé timestamp). Quand le joueur appui sur un bouton, elle envoie un message avec le timestamp et l'état de la manette, puis continue le jeu normalement. Le serveur connait l'état de la partie. Quand il reçoit ce message, il calcule son impact sur l'état de la partie puis renvoie un message aux deux NES contenant le nouvel état et le timestamp associé. Enfin, quand une NES reçoit un état de la partie, elle le copie dans sa mémoire puis rejoue les frames entre le timestamp de l'état reçu et le timestamp courant.

mDKnR3k.png
Une conversation banale entre une NES et le cloud.

Ce protocole permet aux NES de faire de la prédiction, en l'absence de message du serveur le jeu continue et donc le lag est moins visible. Les algorithmes gourmands sont déportés sur le serveur, la NES n'a besoin de ne maintenir qu'un seul état de la partie, sa consommation de RAM est préservée.

Avec ce protocole définit, il y reste trois choses à faire : patcher un émulateur pour envoyer des paquets UDP depuis la ROM, implémenter le protocole dans la ROM, implémenter le serveur.

Patcher un émulateur est rapide. J'ai choisi Mesen, parce que celui-là je ne l'avais encore jamais patché. Il est en C++ avec une classe par mapper. Le mapper NROM a été vampirisé pour l'occasion, permettant l'envoi de paquets UDP suivant une interface super simple pour la ROM. L'idée est de prouver que Super Tilt Bro. en réseau est possible, pas de s'arracher les cheveux sur de l'assembleur utilisant une interface crédible.

Dans la ROM, un hook pour le protocole réseau a été mis en place. Ainsi le code du réseau est séparé du reste, c'est à priori une bonne organisation définitive. Le code en lui-même va au plus simple, pas de configuration, si on sait ce qu'on fait ça marche, sinon ça explose.

Il ne manque plus que le serveur. Et là c'est un gros bout. On part sur du C++ qui gère notre protocole et, surtout, qui est capable de simuler l'état de la partie. Le code de Super Tilt Bro. est tout sauf portable, c'est de l'assembleur pour un vieux CPU, utilisant des souvent astuces de roublard et parfois dépendant des registres de la NES. Trois options : recoder une grosse partie de Super Tilt Bro. en C++, faire tourner un émulateur NES ou adapter un émulateur 6502 pour pouvoir appeler les fonctions de Super Tilt Bro. depuis le C++. J'ai choisi de réimplémenter le jeu en C++, à défaut d'être le plus rapide à implémenter c'est ce qui semble cacher le moins de surprises.

C'est super long ! Mine de rien, tenter de recoder deux ans de travail en quelques jours c'est sportif. J'ai réussi à avoir un serveur fonctionnel tant qu'on se contente de courir. Si on fait autre chose, ce n'est pas implémenté, donc le personnage ne fait rien. Comme le serveur fait autorité, le résultat sur la NES est comme si on ne pouvait rien faire d'autre que courir. Le protocole n'est pour l'instant supporté qu'en partie, notamment le serveur est incapable de rejouer une commande arrivée en retard. Ces limitations sont énormes, mais on a enfin un truc qui marche sur un réseau local. L'avenir s'annonce radieux.

Woh bourdel ! Ça valait le coup de ne pas dormir !

Bilan, le matos pour faire les premières cartouches est là. Sortir une version 1.0 dans les mois qui viennent serait super. Avant toute chose on va améliorer le prototype réseau, même si ça n'a rien à voir, c'est trop cool. En améliorant la prédiction on pourra aller sur internet. En finissant de réimplémenter Super Tilt Bro. en C++ on pourra réellement jouer.
avatar
Ah mais grave ouais !!!
J'eu pensé à un autre truc mais je ne sais point si c'est possible sur NES: utiliser le port manette 2 pour lire/écrire => câble link entre 2 consoles (mais bon, du coup tu restes physiquement dans la même pièce).
avatarMatmook -- http://blog.barreteau.org
Twitter : @matmookJagware
A priori, en croisant OUT0 ET D0, on devrait pouvoir écrire une valeur en écrivant dans $4016 et la lire depuis l'autre en lisant $4017. Et ça serait bidirectionel, un bit dans chaque direction a tout moment.

Ce qui va être drôle sera de synchroniser les deux NES et de gérer le fait que tu sois obligé d'écrire dans le cable pour lire l'état de la manette 1 (OUT0 est commun aux deux ports manette). Rien d'insurmontable, ça pourrait être marrant à faire smile

Documentation sur le sujet :
http://wiki.nesdev.com/w/index.php/Controller_port_pinout
http://wiki.nesdev.com/w/index.php/Input_devices
avatar
Tu es décidément trop fort boing

Merci pour ce post qui vient compléter brillamment la vidéo que tu avais tweeté !
avatar@originalfei
In pixels we trust.
ORE WO DARE DA TO OMOTTE YAGARU !
Internet, une latence sans pitié

Après beaucoup de temps passé à réimplémenter Super Tilt Bro. en C++ et un peu passé à rendre le serveur plus "intelligent", on a pu tester le jeu sur le vrai internet. Deux améliorations ont été nécessaires côté serveur à cause de la latence de 50~80 ms de nos connexions. La première est de gérer intelligemment les messages arrivant dans le désordre. Disons que les deux joueurs pressent un bouton presque en même temps, le joueur 1 le fait à la frame 23, le joueur 2 à la frame 24, rien n'empêche le message du second joueur d'arriver en premier, le serveur ne doit pas se laisser perturber. La seconde optimisation nécessaire pour que ce soit jouable sur l'internet mondial est de compenser la latence côté serveur. Au lieu de simplement calculer l'état courant de la partie, le serveur prédit quelques frames dans le futur avant d'envoyer son état aux NES. Cette prédiction compense le temps de transport, ainsi la NES reçoit l'état présent de la partie.

On teste l'internet, feat. Bjorn

Le bilan de ce réseau est "pas mauvais, peut mieux faire." Avec ces améliorations côté serveur, on peut jouer gentiment, c'est fluide et agréable. Les problèmes surviennent quand on commence à jouer sérieusement. En effet, quand un joueur lance une attaque, le message est envoyé au serveur, puis le nouvel état de la partie est envoyé à l'autre NES. Tout ceci prend entre 100 et 160 ms, soit entre 2 et 3 frames. Pour rester synchronisée, la NES qui reçoit le message n'affiche pas le début de l'attaque. Super Tilt Bro. étant un jeu particulièrement rapide et nerveux, ces quelques frames sont souvent très importantes, on a donc beaucoup de mal à suivre l'action dès que le rythme s'accélère.

Il y a plusieurs solutions à ce problème, je n'en ai encore essayé aucune. Une idée serait de ralentir le rythme du jeu. Si les attaques prennent plus de 4 frames à sortir, le lag serait beaucoup moins visible. Cette solution est dégueulasse, on peut changer le gameplay du jeu, mais le faire pour des raisons techniques, ça craint. Un classique est de ne pas avoir de serveur, le peer-to-peer enlève une étape et réduit donc le lag de moitié. C'est une bonne idée, mais c'est vraiment plus facile à dire qu'à faire, d'abord les techniques pour le mettre en place ne sont pas toujours fiables (cherchez "hole punching"), ensuite ça forcerait la NES à être aussi intelligente que le serveur actuel ce qui fait exploser les budgets CPU et RAM. Enfin, un autre classique est d'induire un lag en entrée. Quand le joueur appuie sur un bouton, le jeu ne le prend en compte que deux frames plus tard, mais envoie le message au serveur immédiatement. Il faut à tout prix éviter d'induire trop de lag en entrée sinon l'expérience s'en ressent, même en réseau local.

Voilà qui clôt pour l'instant l'épisode du réseau. Très bientôt je posterai à propos de la version 1.0 (sans réseau) et de la production de cartouches... Qui devraient être prêtes pour la RGC 2018
avatar
Version 1.0 et production de cartouches

Toutes les mécaniques sont là. Les quatre arènes sont implémentées. Une foultitude de détails ont été ajoutés. Particules, physique, intelligence artificielle, compression,... Super Tilt Bro. à largement dépassé son ambition initiale, qui était simplement de finir un tutoriel. On va donc aller jusqu'au bout...

wAplses.jpg
Super Tilt Bro. en vrai


Une édition physique ! Voilà qui bouclera définitivement le tutoriel smile Et tout devrait être prêt pour la RGC 2018 \o/

La version 1.0 de la ROM est presque prête. Margarita a préparé une superbe notice en un temps record. Tout le matériel nécessaire à la production de cartouches est là. Il n'y a plus qu'à finaliser la v1.0, flasher les ROMs, souder les composants (67 soudures par cartouche), tester chaque cartouche, imprimer/coller les étiquettes, imprimer/relier les notices, préparer les boites et, enfin, mettre les cartouches en boite. Bref, il y a de quoi s'occuper d'ici à la RGC, surtout que la plupart de ces tâches sont nouvelles pour moi.

Préparez-vous à m'entendre brailler fièrement que ce jeu entièrement brassé à la maison est ma meilleure cuvée smile
avatar
top
Super tout ça grin
Merci pour ces précisions !
avatar@originalfei
In pixels we trust.
ORE WO DARE DA TO OMOTTE YAGARU !