5 points par GN⁺ 2024-08-05 | 1 commentaires | Partager sur WhatsApp
  • high_impact, qui ressuscite l’architecture du moteur JavaScript Impact de 2010, est un moteur C pour jeux d’action 2D prenant en charge Windows, Mac, Linux et le Web via WASM
  • Impact a été créé au moment où iOS écartait Flash, afin de montrer que les jeux web étaient aussi possibles avec Canvas2D, puis a d’abord été vendu 99 $, avec plus de 3 000 licences écoulées, avant d’être publié en open source gratuit
  • Le nouveau moteur est un petit framework réunissant tilemaps, entités, physique et collisions, animation de sprites, texte et son, avec des backends SDL ou Sokol
  • L’implémentation conserve sa simplicité grâce à un stockage d’entités à taille fixe, des assets QOI/QOA, une mémoire unique de type hunk, des renderers OpenGL et logiciel, ainsi qu’à l’éditeur de niveaux Weltmeister en JavaScript
  • Biolab Disaster et Drop ont pu être portés et exécutés en restant proches de leur code source JS d’origine, et le moteur peut s’étendre à d’autres systèmes via l’ajout de plateformes et de renderers

Présentation de high_impact

  • high_impact est un petit moteur de jeu pour jeux d’action 2D
  • Il est écrit en C et compilé pour Windows, Mac, Linux et le Web en WASM
  • Il s’inspire du moteur de jeu JavaScript Impact de 2010, et son nom fait référence à une époque où le C était considéré comme un langage de haut niveau
  • Il est publié sous licence MIT et son code source est disponible sur GitHub

Pourquoi Impact a été créé

  • En avril 2010, Steve Jobs a publié la lettre ouverte « Thoughts on Flash », annonçant qu’iOS ne prendrait pas en charge Flash
  • À l’époque, Flash était au centre de la culture du jeu web et de l’animation via plugin navigateur, et des sites comme Newgrounds ou Kongregate dépendaient fortement de contenus Flash
  • La prise en charge de Flash sur Android posait de nombreux problèmes, et Adobe est décrit comme n’ayant pas vraiment cherché à corriger ses défauts sur mobile
  • L’idée dominante était que sans Flash, il n’y avait pas de jeux dans le navigateur, mais l’API Canvas2D permettait déjà de dessiner images et formes dans un <canvas>
  • Canvas2D avait été créé par Apple/Safari pour le rendu de widgets desktop, puis pris en charge par Google et Mozilla, tandis que Microsoft Internet Explorer était à la traîne
  • C’est dans ce contexte qu’a été créé Biolab Disaster, en parallèle du développement du moteur de jeu et de l’éditeur de niveaux nécessaires

Ventes et cas d’usage d’Impact

  • Après nettoyage du code et rédaction de la documentation, Impact a été vendu 99 $ ; ce choix payant a suscité des réactions hostiles, mais a tout de même conduit à plus de 3 000 licences vendues
  • De nombreux jeux web ont été créés avec Impact, ainsi que des titres commerciaux multiplateformes
  • En fin de vie, Impact a été publié gratuitement en open source
  • high_impact est un projet qui recrée Impact depuis zéro, mais en C plutôt qu’en JavaScript

Pourquoi le C

  • Le C est vu comme un langage simple mais profond, dont la formule « facile à apprendre, difficile à maîtriser » rappelle celle des jeux
  • L’intérêt pour le C s’est ravivé au fil de plusieurs projets
    • Portage d’un décodeur MPEG1 JavaScript vers la bibliothèque mono-en-tête pl_mpeg
    • Implémentation de la VR dans Quake pour Oculus Rift
    • Création du format d’image QOI et du format audio QOA
    • Réécriture de wipEout
  • À l’origine, Impact n’avait pas l’ampleur de moteurs comme Godot, Unreal ou Unity, mais a servi de base solide à plusieurs jeux
  • Réécrire Impact en C a commencé comme un exercice amusant

Architecture du moteur et assets

  • high_impact est implémenté de la manière la plus simple possible, avec la volonté d’utiliser aussi peu de code que nécessaire
  • Les fonctions de base sont les mêmes que dans le moteur JavaScript d’origine
    • Chargement de tilemaps
    • Création, mise à jour et affichage d’entités, les objets du jeu
    • Gestion de la physique et des collisions entre entités
    • Gestion des collisions avec la carte de collision
    • Animation à partir de feuilles de sprites
    • Affichage de texte
    • Lecture de bruitages et de musique
  • Il s’agit moins d’une bibliothèque que d’un framework, la logique du jeu étant écrite à l’intérieur de celui-ci
  • À la base se trouve un backend platform, actuellement compilable avec SDL ou Sokol
  • Le code du jeu vit dans une ou plusieurs « scene », chaque scene étant une struct contenant des pointeurs de fonction
    • Après l’appel à engine_set_scene(&scene_game), le moteur configure la nouvelle scene
    • scene_game.init() n’est appelée qu’une fois
    • scene_game.update() et scene_game.draw() sont appelées à chaque frame
  • Les tilemaps et entités initiales peuvent être chargés depuis des fichiers .json ou créés dynamiquement
  • Le format JSON a été choisi pour les niveaux afin de conserver une compatibilité descendante avec Impact
  • high_impact utilise QOI pour les images et QOA pour les sons et la musique
    • Le Makefile des jeux de démonstration convertit automatiquement les PNG en QOI et les WAV en QOA
    • Cela évite d’intégrer des bibliothèques séparées de décodage d’image et de son
  • D’autres formats d’assets pourront éventuellement être pris en charge, mais la simplicité de QOI/QOA correspond bien à l’orientation du projet

Système d’entités

  • Toutes les entités partagent la même entity_t struct, qui contient les propriétés dont high_impact a besoin, comme la position, la vitesse ou la taille
  • Comme toutes les entités ont la même taille en octets, leur stockage et leur gestion sont simplifiés
  • Pour déplacer une entité, il suffit de définir sa vitesse ou son accélération, le moteur s’occupant du reste
  • Des macros permettent d’ajouter des propriétés spécifiques au jeu à la struct de base des entités
    • Biolab Disaster utilise une union contenant une struct par type d’entité
    • Drop n’a pas besoin de définir de propriétés supplémentaires
  • Chaque type d’entité doit fournir un entity_vtab_t avec des pointeurs de fonction
    • update est appelée à chaque frame
    • touch est appelée lorsqu’il y a chevauchement avec une autre entité correspondant aux conditions
    • Tous les champs sont facultatifs
  • Le stockage des entités est de taille fixe
    • Le nombre d’entités actives par défaut est de 1 024
    • Il peut être configuré via la définition ENTITIES_MAX
    • Le moteur gère facilement jusqu’à 64k entités au maximum
  • Pour conserver une référence d’entité pendant plus d’une frame, on utilise entity_ref_t
    • entity_ref_t est une struct avec un uint16_t id et un index
    • Elle peut être résolue à nouveau en pointeur avec entity_by_ref()
    • Cela permet de distinguer le cas où une autre entité a repris la même adresse dans le stockage
    • L’indice en uint16_t limite le nombre maximal d’entités actives à 64k
  • Implémenter en C une OOP simple, des classes ou une forme d’héritage simple reste un peu maladroit, mais high_impact essaie de rendre cela aussi confortable que possible
  • Cette approche OOP « naïve », qui regroupe la logique des entités par type au même endroit, s’est révélée claire et efficace dans les jeux réalisés jusqu’ici

Détection de collision et réponse

  • Une gestion simple des collisions consiste à vérifier si l’on peut se déplacer vers une nouvelle position et, sinon, à s’arrêter, mais cela peut produire des comportements étranges avec des objets rapides
  • Dans un platformer 2D, si le joueur se trouve 16 px au-dessus du sol et que son déplacement suivant l’enfonce dans le sol, cela peut donner l’impression d’un atterrissage en douceur : arrêt en l’air, puis descente au frame suivant
  • high_impact trace la boîte de l’entité contre la tilemap afin de calculer précisément le point de collision
  • Cette approche est plus complexe qu’un simple test oui/non, mais donne de meilleurs résultats et permet aussi de gérer les tuiles en pente
  • Un second tracé peut être nécessaire avec la vitesse restante après un choc contre une tuile
    • Par exemple, lors d’un contact oblique avec le sol, vel.y devient 0, mais vel.x est conservé pour glisser le long du sol
  • Les collisions entre entités sont gérées séparément
    • Les particules peuvent entrer en collision avec la tilemap sans entrer en collision avec d’autres entités
    • Les plateformes mobiles peuvent entrer en collision avec d’autres entités sans être déplacées par la réponse à la collision
  • La broad phase de détection de collision trie les entités selon pos.x
    • Comme elles sont déjà presque triées à la frame précédente, le coût du tri par insertion reste faible
    • Après tri, le moteur balaie de gauche à droite et ne teste que les entités comprises entre pos.x et pos.x + size.x
  • Cette méthode de sweep and prune est rapide tant qu’un grand nombre d’entités ne se superposent pas sur des positions x proches
  • Le pire cas survient lorsque beaucoup d’entités sont concentrées sur la même position x, comme dans une tour de caisses empilées
  • Si un autre axe est plus pertinent, comme dans un shoot’em up vertical, l’axe de balayage peut être changé avec #define ENTITY_SWEEP_AXIS y

Rendu

  • high_impact comprend actuellement un renderer OpenGL et un renderer logiciel inachevé
  • Tout le rendu passe par une API très fine, et les appels de dessin réels se font dans une seule fonction, ce qui simplifie relativement l’implémentation d’autres backends
  • Les fonctions essentielles qu’un backend de rendu supplémentaire doit fournir sont l’initialisation, le nettoyage, le réglage de la taille d’écran, la préparation et la fin de frame, ainsi que le dessin de quads
  • Des fonctions mark, reset et create sont aussi nécessaires pour la gestion des textures
  • Les fonctionnalités restent simples : seul le dessin de quads est possible et il n’y a pas d’effets de shaders, mais cela suffit pour l’objectif du moteur
  • Le renderer logiciel fait 140 lignes de code et ne prend en charge que des quads alignés sur les axes
  • Le renderer OpenGL cherche à regrouper tout le rendu d’une frame en un seul appel OpenGL
    • Tous les quads sont réunis dans un grand buffer et envoyés d’un coup via glDrawElements()
    • Toutes les textures sont fusionnées dans un atlas de texture unique pour éviter les rebinding de textures
  • L’atlas de texture est une technique ancienne avec ses défauts, mais elle est utilisée parce que les bindless textures ne sont pas prises en charge partout
  • high_impact ne gère qu’un seul atlas de texture, mais sa taille est configurable par #define
    • Les GPU mobiles prennent généralement en charge des textures de 8k×8k
    • Les GPU desktop récents semblent aller jusqu’à 32k×32k
    • Biolab Disaster et Drop utilisent un atlas de 512×512

Son

  • La sortie audio est gérée par SDL2 ou Sokol, tandis que le moteur s’occupe du chargement, du décodage et du mixage de plusieurs sons
  • Le système audio est séparé entre sound_source_t, qui contient les échantillons, et sound_t, qui représente un son en cours de lecture
  • Ce système est basé sur celui créé lors de la réécriture de wipEout, et peut décompresser du QOA à la demande
  • Tout est alloué statiquement
    • Le nombre de sources chargeables est fixe
    • Le nombre de sons pouvant jouer simultanément est fixe
    • Les sound terminés sont automatiquement libérés puis réutilisés
  • Les sons peuvent être modifiés en volume, en panoramique gauche-droite et en pitch
  • Si le pitch est défini sur une valeur négative, le son est lu à l’envers
  • Le rééchantillonnage nécessaire au pitch variable utilise une méthode de faible qualité par interpolation au plus proche

Gestion mémoire

  • Dans high_impact, on considère qu’il est possible de connaître précisément la quantité de mémoire nécessaire tant que le jeu ne possède pas d’assets créés par l’utilisateur
  • Le moteur alloue statiquement un unique tableau d’octets appelé « hunk », et c’est toute la mémoire utilisée par high_impact
  • La taille du hunk peut être définie via #define ALLOC_SIZE
  • Deux méthodes d’allocation sont utilisées dans ce hunk
    • Un allocateur bump, ou arena, qui grandit depuis le début pour stocker les assets du jeu, les entités et les données de la scene courante
    • Un allocateur temporaire, qui grandit depuis la fin vers le bas et fonctionne comme malloc() et free(), utilisé par exemple pour décompresser une image avant de l’envoyer au GPU
  • L’allocateur bump dispose de plusieurs « high water marks » et revient automatiquement à certains points précis
  • La mémoire allouée par bump n’a pas besoin d’être free() explicitement
  • Les durées de vie conceptuelles sont séparées en game, scene et frame
    • Ce qui est alloué avant la définition de la première scene n’est libéré qu’à la fermeture du programme
    • Ce qui est alloué pendant scene.load() est libéré à la fin de la scene
    • Ce qui est alloué pendant l’exécution de la scene est libéré à la fin de la frame
  • Le load() propre à chaque type d’entité est appelé lors de la première phase, car on ne sait pas à l’avance quelles entités seront utilisées dans une scene
  • Des contextes d’allocation supplémentaires peuvent être encapsulés avec alloc_pool(), qui n’est en interne qu’un raccourci pour bump_mark() et bump_reset(mark)

Éditeur de niveaux Weltmeister

  • Impact d’origine incluait un éditeur de niveaux nommé Weltmeister, et high_impact le reprend également
  • Il reste écrit en JavaScript et réutilise largement le code source original, mais a été mis à jour pour les fonctionnalités des navigateurs modernes
  • Weltmeister fonctionne de manière totalement autonome
    • Il suffit de double-cliquer sur weltmeister.html pour commencer à créer un niveau
    • Autrefois, le chargement et la sauvegarde de fichiers nécessitaient une API backend en PHP ou NodeJS
    • Désormais, FileSystemAPI peut demander l’autorisation d’accéder à un dossier donné
  • Safari et Firefox, notamment, ne prennent pas encore entièrement en charge showDirectoryPicker(), ce qui impose un navigateur basé sur Chrome
  • Weltmeister lit les fichiers source C et collecte les types d’entités
  • high_impact fournit des macros que l’éditeur comprend, mais qui n’ont aucun effet dans le code C
    • EDITOR_SIZE(X, Y) : taille dans l’éditeur, par défaut (8, 8)
    • EDITOR_RESIZE(RESIZE) : redimensionnement autorisé ou non dans l’éditeur
    • EDITOR_COLOR(R, G, B) : couleur de la boîte dans l’éditeur, par défaut (128, 255, 128)
    • EDITOR_IGNORE(IGNORE) : possibilité ou non de créer l’objet dans l’éditeur

Jeux de démonstration

  • Pour vérifier que high_impact fonctionne réellement comme moteur de jeu, deux jeux Impact d’origine ont été portés en C
  • Le portage a davantage consisté à « translittérer » le code source JS existant qu’à le réinventer, tout en réutilisant les assets d’origine
  • Le fait que l’exercice n’ait pas été très difficile peut être vu comme une preuve que high_impact fonctionne comme prévu
  • Biolab Disaster

  • Drop

Extensibilité

  • high_impact adopte une structure de moteur de jeu traditionnelle, où le code spécifique au jeu s’écrit de manière additive
  • Il n’est pas nécessaire de modifier le code source du moteur, mais celui-ci reste suffisamment simple pour pouvoir être changé directement si besoin
  • Les plateformes et renderers sont conçus pour pouvoir être étendus sans modifier le reste du code
  • Si cela vous intéresse, les pull requests ajoutant des renderers Vulkan, DirectX ou Metal, ainsi que des backends de plateforme pour la PSX, la N64 ou la Dreamcast, sont les bienvenues
  • Comme il est écrit en C, l’objectif est qu’il puisse tourner partout

1 commentaires

 
GN⁺ 2024-08-05
Avis de Hacker News
  • Une bonne partie des travaux de programmation dont j’ai le plus appris, je les dois à Impact
    Impact était vraiment en avance sur son temps, et je suis fier d’avoir fait partie de ses 3 000 détenteurs de licence. C’est le meilleur achat que j’aie jamais fait, et le seul jeu que j’aie vraiment mené jusqu’au bout a été réalisé avec Impact
    J’aimais le fait que la licence inclue le code source, et j’ai modifié moi-même le moteur et l’éditeur selon mes besoins. Sous son influence, j’ai passé plusieurs années à créer mon propre moteur de jeu JS, même si j’ai repoussé la finalisation de mes jeux ; j’ai malgré tout beaucoup appris en chemin et créé pas mal de jeux pour des game jams
    J’ai aussi été inspiré par Ejecta, le support iOS natif d’Impact, mais j’étais frustré qu’il ne fonctionne pas sur Android à l’époque ; j’ai donc créé des bindings JVM pour V8 et implémenté une partie de WebGL afin de faire tourner mon moteur sur Android sans webview. Le dépôt de bindings V8 que j’ai publié s’est retrouvé, à ma grande surprise, utilisé dans un logiciel commercial : https://github.com/namuol/jv8
    Inspiré par le modèle économique d’Impact, j’ai même tenté une startup bootstrap qui vendait l’accès à des dépôts GitHub privés, mais ce serait une longue histoire. En tout cas, voir Impact mis à jour pour le web « moderne » via un portage en C me réchauffe le cœur et me réjouit. J’aimerais dire que le web traverse une période étrange, mais je ne me souviens pas d’une époque où il ne l’était pas

    • À l’origine, Impact étant un moteur basé sur JavaScript et le navigateur, on pourrait penser qu’il devrait bien tourner sur Android avec une simple webview
  • CrossCode est un excellent jeu. Je savais qu’il utilisait des technologies web, et je suis toujours resté surpris qu’il offre de si bonnes performances sur le hardware de la Nintendo Switch
    Ce moteur y est probablement pour quelque chose

    • Pour être juste, l’équipe de CrossCode a énormément modifié Impact. Dans certains streams de développement, on voit que Weltmeister, l’éditeur de niveaux d’Impact, a été fortement étendu : https://youtu.be/4lZfnM9Ubeo?t=3215
      C’est justement ce qui est chouette. C’est bien qu’un développeur puisse adapter un moteur à son jeu, et de la même manière, high_impact devrait être vu comme un point de départ pratique plutôt que comme un moteur de jeu « complet » prêt à l’emploi
    • Le portage Switch, comme quelqu’un l’a déjà dit, a demandé énormément d’efforts et n’a plus rien à voir avec le impact.js standard
      Anecdote amusante : tout le monde voulait une version Switch, mais à cause des limites techniques, l’équipe répondait que « CrossCode sortira sur Switch quand les hedgehags apprendront à voler » : https://www.radicalfishgames.com/?p=6581
      Quand le portage a finalement abouti, une quête additionnelle intitulée « A switch in attitude » a été ajoutée et, comme prévu, on y voit des hedgehags volants : https://www.radicalfishgames.com/?p=6668
    • Il existe une présentation sur le processus de portage de CrossCode vers la Switch : https://www.youtube.com/watch?v=KfBzlzvt8RU
    • De mémoire, le portage Switch a nécessité des efforts héroïques
  • « Thoughts on Flash » a peut-être sauvé le web au moment où la plateforme en avait le plus besoin, c’est-à-dire lorsque la domination d’un logiciel unique commençait à s’installer peu à peu
    Il y avait aussi, semble-t-il, de la frustration envers Adobe, qui paraissait négliger le support de MacOS pour privilégier la base d’utilisateurs Windows, bien plus importante. Par exemple, la version Mac était toujours en retard sur la version Windows
    Jobs a peut-être eu le sentiment qu’Adobe devait aussi quelque chose à Apple, autant qu’Apple avait rendu Adobe possible, mais ce n’est guère qu’une supposition. Le jeu lui-même a vraiment l’air très soigné

    • La PSP avait aussi Flash, et c’était plutôt correct. Je me demande combien d’efforts et d’argent Sony a pu y consacrer
    • Cet article m’a donné envie de remettre les mains dans le C. À la base, je suis plutôt du côté ECMAScript, et j’ai un peu fait de Lingo il y a longtemps, mais je suis attiré par les choses sobres en ressources et proches du hardware
      Pas au point d’aller jusqu’à l’assembleur, cela dit ; j’essaie plutôt de réduire différentes couches d’abstraction dans une direction qui me pousse à creuser plus profondément
  • En tant que personne qui aimerait un jour s’éloigner du monde de l’entreprise pour se lancer sérieusement dans des side projects, j’aimerais en savoir plus sur la partie autofinancée grâce à la monétisation
    L’idée de faire payer pour un travail que je faisais à l’origine pour le plaisir me met bizarrement mal à l’aise, mais je sais aussi que cela pourrait me permettre de faire à plein temps ce que j’aime

    • Si c’est un bon travail qui résout le problème de quelqu’un, il est parfaitement légitime d’être rémunéré, et tu le sais probablement déjà
      Il est donc important de comprendre pourquoi cette idée te met mal à l’aise. Les raisons courantes sont par exemple : l’entourage qui décourage souvent, le manque de compétences pour bien exécuter ce qu’on veut faire, la gêne à demander de l’aide ou la peur de déranger, la crainte que son travail soit évalué, ou la perte de la « sécurité » qu’offre le revenu actuel, surtout quand on a des personnes à charge
      Dans la plupart des cas, ces raisons ne sont pas tant de très bonnes raisons que des choses qui demandent un certain réajustement et qui, parce qu’elles ressemblent à un « risque », rendent difficile la sortie de sa zone de confort. Avec cet état d’esprit, chaque opportunité ressemble à un risque, ce qui rend très difficile de trouver le bon moment pour commencer ce qu’on veut vraiment faire
      À ce sujet, il est important de simplement faire ce que l’on trouve amusant et de le montrer au monde, mais transformer cela en gagne-pain est un tout autre défi. La plupart des gens ne parviennent pas à faire de ce qu’ils aiment leur métier, et même quand c’est le cas, les attentes des clients payants et la pression de maintenir le chiffre d’affaires peuvent finir par leur enlever cet amour. Je ne dis pas qu’il ne faut pas le faire, seulement que c’est bon à savoir avant de se lancer
  • J’ai fini par me connecter à mon compte HN que j’utilise presque jamais, tellement j’ai rejoué en boucle à Biolab Disaster il y a quelques années, tout en ayant oublié son nom
    C’est assez surprenant de l’avoir retrouvé par hasard

  • D’habitude, j’aurais formulé ça de façon bien plus négative. Pour moi, un « framework », c’était simplement une bibliothèque qui ne s’intègre pas bien avec les autres
    Cela dit, ça fait plaisir d’entendre une formulation positive aussi convaincante

    • L’explication que j’avais entendue, c’était que j’appelle une bibliothèque, alors qu’un framework m’appelle
    • J’ai étudié le génie logiciel, mais je n’ai vraiment compris la différence entre une bibliothèque et un framework qu’à mon premier poste, quand j’ai développé avec WebObjects
      C’était agréable d’utiliser un framework riche et bien conçu qui gérait vraiment très bien 99 % de ce dont j’avais besoin. Ajouter mon code a aussi été l’une des choses les plus faciles que j’aie faites en développement, et ça fonctionnait tout simplement. C’était magique, et ça me manque encore
    • Je pense qu’il y a toujours un côté négatif
      Dans mon idéal, un framework serait, en interne, une bibliothèque ou un ensemble de bibliothèques qui coopèrent, avec une dimension « framework » aussi réduite que possible
      Par exemple, Qt est un framework et Qt « m’appelle », mais on peut exécuter du code QPainter sans lancer la boucle d’événements de Qt ni réfléchir en profondeur à QObject. Dans l’idéal, on devrait pouvoir utiliser la boucle d’événements sans adopter entièrement les signaux et les slots, même si l’expérience peut être moins agréable
      Ce n’est pas toujours possible, ni toujours utile, mais toutes choses égales par ailleurs, je préfère l’absence totale de framework
      Je comprends pourquoi les moteurs de jeu ont besoin d’une certaine part de framework. Quand on compile pour des plateformes particulières comme les téléphones ou les consoles, le moteur doit intervenir dans le processus de build, parfois même jusque dans des aspects liés à la libc ; on ne peut donc pas simplement produire un exécutable Win32 et dire que c’est un jeu PlayStation
  • Associer 7Zip au format de fichier sans perte QOI donne de meilleures performances qu’un PNG sans perte. Travail impressionnant

    • Coller 7Zip à du BMP ferait aussi mieux, et l’écart serait probablement encore plus grand. Au final, ça revient à la différence entre gzip et un compresseur remplaçant gzip
  • « for No Reason » était peut-être en fait destiné à respecter l’autonomie de la batterie du joueur

  • J’aime bien la partie sur la gestion mémoire. L’allocation par arène est vraiment simple
    Mon petit serveur web expérimental a lui aussi commencé avec des arènes, mais j’ai vite compris que je n’avais tout simplement pas besoin d’augmenter ou de réduire la mémoire
    Aujourd’hui, j’alloue d’un coup toute la mémoire nécessaire au démarrage, puis je la découpe en morceaux pour chaque module. En programmation, on suppose souvent qu’on peut avoir besoin d’une quantité arbitraire de mémoire, mais ce n’est pas forcément vrai
    Beaucoup de choses ont en réalité des limites claires, et pour le reste on peut généralement définir des limites. En les énumérant, on connaît la quantité de mémoire nécessaire. Réfléchir à ces limites à l’avance et les définir est amusant, donne confiance et encourage de saines habitudes d’économie

    • Ça m’agace toujours quand les gens disent que les performances de std::vector sont catastrophiques, surtout dans les jeux
      Si on part d’un vecteur vide et qu’on ajoute des milliers d’éléments sans réserver de mémoire, évidemment que ça peut arriver. Mais, dans beaucoup de cas, on peut déterminer le maximum réellement nécessaire et préallouer, et alors tout va bien
    • La base de données TigerBeetle a été construite de cette façon, et j’aime assez le concept : https://tigerbeetle.com/blog/a-database-without-dynamic-memo...
  • J’aime beaucoup la façon dont une structure de données ENTITY de type polymorphe a été créée avec union. La conception est bonne
    J’aime toujours bidouiller en C. C’est le premier langage que j’ai appris, et j’en ai vraiment bavé pendant des années. Comme le dit l’article original, C est un langage concis, ce qui est chouette, et on peut aller aussi loin qu’on le souhaite si on en a envie
    Le jeu m’a plu parce qu’il avait une ambiance à la Commander Keen d’autrefois, et j’ai beaucoup aimé, à une époque, cette franchise que Carmack créait avant sa période 3D