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 !