Journal Sortie de Bim! en version 10, avec un bouclier et des stats

Posté par  (site web personnel) . Licence CC By‑SA.
22
1
sept.
2025

Sommaire

Cher journal,

J'ai récemment sorti la version 10 de Bim!, c'est l'occasion de te présenter les nouveautés des deux versions qui nous séparent du dernier journal. Mais commençons par copier-coller le paragraphe descriptif du précédent journal.

Pour rappel, Bim! est un jeu libre (code AGPL3 et assets CC-by-sa 4.0) multijoueur de type dernier survivant, et qui se joue uniquement en ligne. Il n'est disponible que pour les systèmes Android. Le jeu étant encore en bêta sa diffusion sur le PlayStore est limitée à quelques pays (France, Belgique, Suisse). Le reste du monde peut néanmoins le trouver sur GitHub, F-Droid, et d'autres magasins alternatifs.

Les changements de ces deux nouvelles versions vont nous amener à parler d'argent, d'utilisation d'outils d'IA, un peu de graphisme, d'internationalisation, et enfin d'une nouvelle fonctionnalité de jeu avec l'introduction du bouclier :)

Présentation des nouveautés

Côté client

La grosse nouveauté de la version 9 est l'arrivée d'une boutique où le joueur peut enfin dépenser de l'argent réel pour acheter de l'argent virtuel qui lui permettra de débloquer des fonctionnalités plus rapidement qu'en jouant. Une manière de contribuer à la charge financière du développement et de la maintenance du jeu.

Cette boutique n'est pas disponible dans la version publiée sur F-Droid puisqu'elle nécessite la bibliothèque Billing d'Android, qui n'est évidemment pas libre. Je réfléchis à une alternative pour F-Droid, soit via une autre bibliothèque (je n'en connais pas), soit en mettant juste un appel aux dons (mais le joueur n'obtient alors rien dans le jeu).

Dans la version 9 j'ai aussi amélioré et corrigé différents éléments qui pouvaient causer une déconnexion du joueur. Cela devrait donc moins fréquemment se produire.

L'internationalisation du jeu s'étend avec l'arrivée de traductions en allemand, en breton, en portugais, et en portugais brésilien. Ces traductions sont gérées via Weblate, on en reparle dans une section dédiée plus bas. Je suis ravi de voir des joueurs d'un peu partout dans le monde, et aussi de voir que le serveur de jeu installé en France est suffisant pour des joueurs à l'autre bout du monde.

J'ai aussi ajouté un nouvel élément de gameplay avec le bonus de bouclier. Ce dernier protège le joueur qui le trouve contre une attaque. On en reparle dans la section dédiée.

J'en ai profité pour refaire les dessins de tous les bonus, qui étaient restés en mode brouillon depuis toujours. C'est mieux, non ? J'ai aussi ajouté un petit effet de reflet dessus car je craignais qu'on ne les distingue pas assez. Au départ je voulais repomper ce shader pour Godot mais ça n'a pas fonctionné, et le code m'a semblé un peu douteux. J'ai commencé à l'analyser puis je me suis dit que ça me coûterait autant de le réécrire, donc acte.

Effet normal Effet ralenti

Le client a reçu une correction pour une légère inconvénience : l'écran des paramètres se ferme maintenant quand le bouton retour du téléphone est pressé. Il s'agit d'une contribution de Saransh Gupta. Merci à lui !

J'ai découvert un bug un peu surprenant récemment, où un des blocs qui tombent en fin de partie ne bloquait pas le joueur. Ce n'était pas évident à reproduire mais grâce au système d'enregistrement de parties précédemment implémenté (une sacrée bonne idée) j'ai pu rejouer la partie et debuguer. Il s'avère que quand un bloc tombait sur une case où est présent une flamme, il n'était pas marqué comme solide. C'est maintenant corrigé.

Enfin, dernière nouveauté, l'écran d'accueil présente quelques stats au joueur : parties jouées, gagnées, perdues. Il s'agit à nouveau d'une contribution de Saransh Gupta, merci encore. Je me suis uniquement chargé de la présentation.

Côté serveur

Côté serveur, j'ai supprimé des logs les IPs des joueurs, ce qui est d'avantage RGPD-friendly. L'IP n'apparaît maintenant que dans les logs Apache quand le client récupère la config mais cela devrait disparaître quand j'aurai implémenté un serveur pour gérer la config. Merci à MaxMind de fournir des bases de données GeoIP ainsi que la bibliothèque pour les lire.

J'ai branché cpptrace pour obtenir la pile d'appel lors d'un crash. J'ai eu des crashs à quelques reprises et j'avais pris l'habitude de déployer une version du serveur compilée avec AddressSanitizer pour avoir les traces. Cette solution était insatisfaisante notamment parce que ça coûtait cher en RAM. Avec cpptrace j'obtiens toutes les infos avec un build prod normal. Merci à Jeremy Rifkin pour cette bibliothèque et son excellente documentation.

Enfin, j'ai ajouté la possibilité de passer la config au serveur via un fichier JSON ainsi que par les paramètres de la ligne de commande.

Côté construction du projet

Je t'avais raconté dans les journaux précédents les contorsions que j'avais du faire pour activer le Link Time Optimizations (LTO), notamment avec l'utilisation de -ffat-lto-objects pour avoir des bibliothèques statiques comprenant à la fois le code compilé et la représentation interne du compilateur. Depuis l'activation de ce flag les temps de compilation ont augmenté, y compris pour un build debug. En effet, il semblerait que GCC active LTO lors du link dès lors qu'une bibliothèque a été compilée avec ce flag. C'est ballot, parce que je n'ai que faire d'avoir des optimisations dans mon build debug.

Pour corriger le problème je passe maintenant -fno-lto au linker en debug pour le forcer à ne pas utiliser LTO. Le build est maintenant de nouveau rapide.

Pendant que j'étais sur le sujet du link j'en ai profité pour passer à mold pour le build debug, pour un build encore un peu plus rapide. Pas moyen de l'utiliser en release cependant car LTO n'a de sens qu'avec le linker du compilateur.

Un petit tour des plates-formes web de traductions

Durant le développement de la version 10 j'ai reçu une demande pour permettre à des profils non-techniques de contribuer en fournissant des traductions du jeu. C'est quelque chose qui m'inquiétait depuis longtemps car je suis incapable de lire l'étrangerien, à quelques exceptions près, et je ne pourrai donc vérifier si les traductions sont fidèles ou si elles cachent des messages nuisibles. D'un autre côté j'ai pour principe que si quelqu'un veut contribuer il faut commencer par dire oui puis trouver comment travailler ensemble. Donc acte, la personne me proposait de passer par Weblate, ou éventuellement Crowdin ou Transifex. J'ai fait le tour des trois offres, regardons ce qu'elles annoncent sur leurs sites :

Crowdin

Crowdin is AI-powered localization software for teams and businesses.

Super, des traductions par de l'IA… On veut m'en filer tous les jours, et je déteste ça. Je sais donc à quel point c'est médiocre et en tant que lecteur, quand on me fournit une traduction automatique, je me sens méprisé. Donc ça ne sera pas Crowdin.

Transifex

Localization, orchestrated with AI.

Bien, même maladie ici, on dirait que c'est la mode de vouloir être tendance. Adieu Transifex, nous ne travaillerons pas ensemble.

Weblate

Plateforme Web de traduction en continu.

Ah, pas d'IA ? Je fouille un peu et je ne vois pas le terme. Ça sent bon. Ils mettent bien en avant que c'est un logiciel libre, et c'est le seul des trois dont le site s'affiche en français. J'en déduis qu'ils sont attentifs à fournir une bonne expérience et à bien faire leur travail, c'est top. De plus ils offrent l'hébergement pour les logiciels libres. Bref, ils cochent toutes cases.

J'ai eu un peu de mal à m'y retrouver dans leur interface, déjà parce que j'ai configuré cela à 22 h au lieu de remettre à demain, mais surtout parce que leur interface, très fournie, est très bien traduite. Du coup quand je vois « demande de tirage » et « style de fusion : refonder » au lieu de « pull request » et « style de fusion : rebase », il me faut un peu de temps pour comprendre qu'on ne parle pas de photo ni de métallurgie.

Au final j'ai configuré un composant pour recevoir les traductions en fichiers PO et j'ai laissé de côté les messages d'attente de l'écran de recherche d'adversaire, qui n'utilisent pas du tout la même technologie.

Weblate m'a permis d'obtenir une traduction du jeu en allemand, en breton, en portugais, et en portugais brésilien. Pour ce qui est de la validation des traductions reçues, et bien on se retrouve dans la section IA ci-dessous :)

Introduction du bouclier

Le bouclier est resté longtemps en tête de ma todolist et se retrouvait pourtant sans cesse repoussé à plus tard… La gestion de projet, c'est pas facile. Mais bon, ça y est, il est dispo :) Il suffit de l'activer sur l'écran de recherche d'adversaire pour qu'il soit ajouté à la partie.


Bouton d'activation du bouclier.

Quand la fonctionnalité est activée, quatre bonus bouclier sont répartis aléatoirement dans l'aire de jeu. Il ne reste plus qu'à les dénicher ! J'aurais voulu les distribuer aléatoirement de manière à ce qu'il y en ait un par quart mais je n'ai pas réussi à le faire sans biais. Il faudra que j'y revienne plus tard.


Heatmap de la distribution par quart. Plus c'est blanc, plus fréquemment la case est choisie pour recevoir le bonus, sur 6000 tirages. Le biais est flagrant.

Le bouclier est un tonneau en bois, mais sacrément solide. Dessiné dans GIMP, évidemment, il a le bon goût d'être à la fois drôle et facile à animer.


Croquis préparatoires du bouclier. Pour le coup j'avais une idée assez claire de ce vers quoi aller.

Enfin je dis que c'était facile à animer mais j'ai quand même réussi à me planter en calant la rotation du tonneau en son centre plutôt qu'en bas. Ça donne l'impression que le personnage danse ! En mettant le centre de la rotation en bas le rendu est meilleur, on a d'avantage un sentiment d'encombrement.

Animation toute ratée Animation convenable

Bilan financier

Bim! est un jeu libre et gratuit. Enfin… gratuit pour vous, pas pour moi :) Les coûts se répartissent entre l'hébergement du serveur de jeu, un hébergement web (pour la config et une page de politique de vie privée), et des commandes d'assets.

L'hébergement me coûte 4,20€ par mois mais il s'agit aussi de la machine qui héberge mon site perso. Proportionnellement le trafic web pour Bim! est minuscule (il y a juste un petit JSON à récupérer de temps en temps) mais je n'ai aucune idée du trafic lié au jeu lui-même. Pour la config, sur les 12 derniers mois cela représente 1,1% des hits et 0,4% des données, d'après Webalizer. Proportionnellement ça ferait quelques dizaines de centimes attribués aux besoins de Bim!

Afin de pouvoir publier l'application sur le PlayStore j'ai du débourser $25 (26,43 €). Il s'agit d'un paiement unique qui me permet d'y diffuser ce jeu et d'autres, à vie.

Enfin le gros des dépenses est sans aucun doute les commandes d'assets graphiques qui s'élèvent à 1500 €.

Bien entendu je ne chiffre pas le temps passé ; pour l'instant on est sur du loisir.

Du côté des revenus, ils se présentent sous deux formes. Il y a d'une part le sponsoring GiHub. Le fournisseur de service ne prenant pas de commission, la totalité des revenus me reviennent, ce qui s'élève à 0 € pour l'instant.

L'autre part des revenus vient des achats in-app. Ici Google prend 15% de commission sur chaque achat. L'ensemble des achats m'a donc rapporté 0 €.

Comme tu peux le voir la balance n'est pas du tout équilibrée.

Si le jeu te plaît, ou si t'es trop riche et que tu cherches un investissement à 0%, garanti, tu peux m'aider financièrement avec les solutions listées ci-dessus, soit en partageant avec Google, soit tout pour moi. Je me chargerais ensuite de faire ruisseler tout cela.

Alternativement tu peux aussi contribuer directement auprès des projets qui me rendent d'énormes services, par exemple :

Le rôle de l'IA dans les derniers développements

Il s'avère que j'ai utilisé ChatGPT comme outil pour diverses taches sur la dernière version de Bim! Comme le sujet est tendance je te propose un petit retour d'expérience.

J'en ai parlé plus haut, je suis inquiet du sens des traductions vers des langues que je ne connais pas. Pour les valider j'ai donc demandé à ChatGPT de faire la traduction inverse pour retomber sur des phrases en français. Ça donne un résultat de mauvaise qualité mais ça permet de vérifier si le sens colle à l'intention. Un problème étant que ChatGPT n'a pas compris la consigne et lorsque je lui ai envoyé le fichier PO avec les textes anglais vers brésilien il m'a renvoyé, fièrement, une traduction anglais vers français. Après quelques itérations j'ai eu le résultat attendu mais avec un gros doute. Au final je pense que j'aurais du extraire les textes en brésilien et ne lui envoyer que cela, mais alors le service rendu n'aurait pas été mieux qu'un Google Translate par exemple. Dans tous les cas c'est moins bien que ce que m'aurait fait un humain.

D'autre part, je lui ai aussi demandé de me générer des assets graphiques pour les bonus ; un peu par curiosité, pour voir de quoi il était capable, et aussi parce que j'étais en manque d'inspiration. C'était extrêmement laborieux. S'il est relativement facile de lui faire générer un joli dessin, c'est bien plus difficile de retravailler la proposition comme on le ferait avec un artiste. Et bon sang ce que c'était long… chaque image prend une éternité à sortir. Au final je n'ai évidemment pas repris les assets générés mais j'ai repompé certaines caractéristiques dans mes dessins. Typiquement la forme de la boîte et le fait que l'icône sorte du cadre m'ont été suggérées par l'outil.

Je trouve intéressant de comparer la démarche avec celle suivie pour dessiner le tonneau bouclier. Point d'IA pour celui-ci, je suis parti de ce que je savais (j'ai une vague idée de ce à quoi ressemble un tonneau) puis j'ai effectué une recherche d'images sur le thème « cartoon barrel ». Ensuite j'ai étudié les résultats pour en extraire des caractéristiques qui me conviennent (couleurs mais aussi nombre de planches et de cerclages). Et voilà, j'ai dessiné du mieux que je pouvais ce que j'avais en tête et c'est tout. Est-ce très différents de la démarche pour les bonus ? Au final je me suis inspiré de travaux de tiers pour faire quelque chose à ma sauce.

Globalement je suis plutôt mitigé sur l'utilisation de l'IA. C'est long, laborieux, d'une qualité assez moyenne, écologiquement et éthiquement mauvais, mais on a toujours l'impression d'être pas loin d'un truc bien.

Un dernier exemple. J'ai utilisé un agent pour certaines parties du code. Je lui ai écrit un prompt assez précis, il m'a proposé un code, qui de plus passait les tests. J'ai demandé ensuite plein de modifs sur des trucs qui ne m'allaient pas, il les a corrigés et j'ai fini par accepter le résultat. Mais ça m'a demandé un temps énorme de vérifier le code, bien plus que si je l'avais écrit moi-même.

Bon il s'avère que l'agent était un humain, le prompt une issue sur GitHub, et les demandes de corrections une revue de code. J'ai construit un truc avec une autre personne, c'était très sympa, et contrairement a une IA on a appris des trucs et on fera mieux la prochaine fois.

Quelques stats

Comme d'habitude je vais terminer avec quelques stats sur la fréquentation du jeu. Commençons par l'évolution du nombre de recherches d'adversaire sur les deux derniers mois.

Si on regarde le nombre de recherches d'adversaire par heure (UTC) on peut avoir une idée des moments où on a le plus de chance de trouver quelqu'un.

Ensuite regardons le nombre de matchs par jour.

En termes de répartition du nombre de joueurs par partie, cela donne :

Nombre de joueurs Nombre de parties
2 961
3 128
4 4

Enfin, pour la répartition des joueurs par pays, avec la précision de la table fournie par MaxMind, on a :

Envoyer un commentaire

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.