29 points par GN⁺ 2024-04-27 | 13 commentaires | Partager sur WhatsApp
  • À propos de l’affirmation selon laquelle tous les problèmes disparaissent une fois qu’on s’est habitué à Rust
    • Même en se familiarisant avec Rust, les problèmes fondamentaux ne disparaissent pas
    • Un jeu est une machine à états complexe dont les exigences changent sans cesse, ce qui s’accorde mal avec le caractère statique et le contrôle excessif de Rust
    • Le fait de devoir refactorer constamment le code est un problème qu’on se crée soi-même
  • Les gros problèmes de refactorisation causés par le borrow checker
    • Rust force les refactorisations plus souvent que les autres langages
    • Quand les exigences d’un jeu changent souvent, on finit par se battre avec le borrow checker et par devoir restructurer le code
    • Il est difficile d’adhérer à l’idée que la refactorisation produit un bon code. Un bon code naît en répétant les idées et en testant des approches
  • L’indirection ne résout qu’une partie des problèmes et réduit la productivité de développement
    • Utiliser de l’indirection pour contourner les problèmes liés au borrow checker sépare la logique du code et le rend plus complexe
    • Dans un jeu, il faut gérer des événements liés entre eux, des timings précis et beaucoup d’état, et l’indirection rend cela plus difficile
    • En Rust, même un code simple doit être écrit de façon verbeuse pour introduire de l’indirection
  • L’ECS (Entity-Component-System) résout le mauvais problème
    • Les avantages de l’ECS sont en réalité ceux des generational arenas
    • L’ECS est vu sous divers angles : composition dynamique, structure of arrays, solution au borrow checker de Rust, generational arenas créées dynamiquement, etc.
    • Mais il est légitime de se demander si l’ECS est vraiment l’approche la plus adaptée au développement de jeux. Il faut se concentrer davantage sur la logique du jeu que sur la performance ou la composition
  • Les systèmes généralisés ne mènent pas à un gameplay intéressant
    • Des systèmes trop généralisés produisent un gameplay ennuyeux
    • Un bon jeu repose sur des interactions détaillées soigneusement conçues, la synchronisation des VFX, des playtests et expérimentations répétés, ainsi qu’une sortie rapide pour recueillir des retours
    • Rust poursuit des valeurs peu adaptées au prototypage rapide et à l’itération
  • Dans le développement de jeux, ce qui compte, c’est le prototypage rapide et l’itération, alors que les valeurs de Rust vont à l’opposé
    • L’essentiel dans le développement de jeux, c’est le jeu lui-même et l’expérience de jeu, pas un code sans crash
    • La maintenabilité du code de jeu n’est pas une valeur si importante dans l’indé ; ce qui compte, c’est la vitesse d’itération
    • Rust, obsédé par l’évitement des problèmes, passe à côté de ce qui est vraiment important
  • Les procedural macros sont très loin de la réflexion
    • En développement de jeux, il faut écrire du code dans des domaines variés : code système, gameplay, UI, VFX, audio, outils, etc.
    • En Rust, même un simple « affichage d’objet » doit être codé à la main ou nécessite de créer des procedural macros
    • Les procedural macros sont bien plus limitées que les macros déclaratives et allongent aussi le temps de compilation
    • La réflexion de C# est très simple à utiliser et permet de développer vite quand les performances ne sont pas critiques
  • Le hot reloading joue un rôle important pour améliorer la vitesse d’itération
    • Le hot reloading est très utile pour l’UI / rendu en mode immédiat, le débogage et le réglage des constantes de gameplay
    • Rust dispose de hot-lib-reloader, mais ce n’est pas parfait, et cela demande de la planification et de l’anticipation, ce qui limite les usages créatifs
    • Les développeurs de jeux veulent des outils de plus haut niveau qu’un simple rechargement de struct
  • L’abstraction n’est pas un choix, c’est une nécessité
    • Exemple concret : lorsqu’il faut des comportements différents selon l’état de l’UI, Rust oblige à refactorer ou à abuser des clones
    • Il arrive souvent qu’on modifie le code non pas parce que la logique métier change, mais pour satisfaire le compilateur
    • Rust ne dispose pas d’un système de types structurels du genre « type avec ces champs », donc une refactorisation impose de modifier le code à plusieurs endroits
  • La situation de l’interface graphique en Rust est catastrophique
    • Dans l’UI d’un jeu, l’important n’est pas le data binding ou les mises à jour réactives, mais la personnalisation de l’apparence
    • Ce qu’il faut pour l’UI de jeu, c’est une belle GUI, des sprites personnalisés, des animations, des formes vectorielles, des particules, des effets, des flashs, etc.
    • Il n’existe actuellement aucune bibliothèque Rust spécialisée pour les GUI de jeux
  • L’orphan rule devrait être optionnelle
    • L’orphan rule réduit fortement la productivité pour des raisons de sûreté
    • Il devrait être possible de désactiver l’orphan rule dans du code applicatif, par opposition au code de bibliothèque
  • Les temps de compilation se sont améliorés, mais restent lents dès qu’on utilise des proc macros
    • Les proc macros comme serde augmentent fortement les temps de compilation
    • Avec des builds incrémentaux de 20 à 30 secondes ou plus, il devient très difficile d’affiner les réglages
  • L’écosystème Rust pour le développement de jeux semble survendu
    • Il n’y a pas tant de gens que ça qui développent réellement des jeux
    • Il arrive souvent que des projets au site web ou au README impressionnants et très connus ne soient pas à la hauteur dans la réalité
    • Si l’on veut créer de vrais jeux, godot-rust est recommandé. Mieux vaut s’appuyer sur un moteur mature que s’obstiner dans une solution 100 % Rust
  • Comme les jeux sont en mono-thread, les raisons qui rendent l’état global inconfortable sont mal posées
    • Utiliser un état global en Rust est très inconfortable (static mut, AtomicRefCell, Rc, etc.)
    • Mais contrairement à un service backend, un jeu tourne entièrement en mono-thread, donc ces contraintes ne sont pas vraiment nécessaires
    • L’introduction de systèmes parallèles dans Bevy est vue comme une erreur. Cela a été fait pour la performance, mais oblige les utilisateurs à préciser constamment l’ordre d’exécution, ce qui rend le tout plus pénible
  • La vérification dynamique des emprunts provoque des crashs inattendus après refactorisation
    • Après deux ans d’utilisation de hecs, de nombreux cas de crash ont été observés à cause de requêtes qui se chevauchent
    • Avec RefCell, un simple double appel à .borrow_mut() à deux endroits différents peut aussi provoquer un crash inattendu
    • Le problème n’est pas tant la mauvaise qualité du code que le fait que Rust force des refactorisations inutiles
    • Dans les jeux, RefCell est utile, mais Rust en rend l’usage trop difficile
  • Les objets context manquent de souplesse
    • Comme il est difficile d’utiliser un état global en Rust, on adopte souvent un pattern consistant à regrouper des références dans un objet context que l’on transmet partout
    • Mais si l’on n’emprunte que certains champs, on se retrouve avec des erreurs de compilation à cause du partial borrow
    • On conseille alors de découper le context et de modifier la structure, alors qu’on voudrait simplement travailler sur la logique du jeu ; perdre du temps à restructurer le code pour satisfaire le compilateur est du gaspillage

Les points forts de Rust

  • Une fois compilé, le programme fonctionne généralement bien. C’est particulièrement utile pour les outils CLI, le traitement de données ou l’écriture d’algorithmes
  • Le langage offre de bonnes performances sans effort particulier. L’expérience rapportée évoque une vitesse 1,5 à 2,5 fois supérieure à C#
  • Les enums sont bien conçus
  • Grâce à Rust analyzer, l’expérience IDE s’est nettement améliorée
  • Le système de traits est bien conçu. Si l’orphan rule était un peu assouplie, son utilité serait encore bien plus grande

L’avis de GN⁺

  • L’opinion sur Rust est globalement négative, mais comme il s’agit de la conclusion d’un auteur qui a multiplié les essais, elle mérite d’être prise au sérieux. En particulier, l’idée que dans le développement de jeux, le pragmatisme et la vitesse de développement sont cruciaux, et que Rust reste encore insuffisant sur ces aspects, semble pertinente.

  • Je suis d’accord avec l’idée que la sûreté recherchée par Rust peut parfois faire chuter fortement la productivité. En écrivant du code Rust, on passe souvent plus de temps à satisfaire le compilateur qu’à travailler sur la logique elle-même, ce qui semble découler du fait que Rust est fondamentalement un langage spécialisé dans la programmation système.

  • À l’inverse, le développement de jeux se fait le plus souvent dans un environnement mono-thread où le prototypage rapide et l’itération sont essentiels ; des contrôles de sûreté excessifs peuvent donc devenir contre-productifs. On a beaucoup entendu parler de tentatives avortées de développement de jeux en Rust à ses débuts, et il semble que les problèmes de fond ne se soient pas beaucoup améliorés depuis.

  • Bien sûr, des moteurs de jeu récents comme Bevy ont amélioré le confort du développement de jeux en Rust, mais ils semblent encore très loin du niveau de maturité de moteurs comme Unity ou Godot. Comme le suggère cet article, plutôt que de tout construire en Rust pur, utiliser Rust en complément de moteurs existants peut constituer une alternative réaliste.

  • Les avantages mentionnés par l’auteur se ressentent fortement lorsqu’on utilise Rust dans d’autres domaines que le jeu vidéo. En particulier, dans la programmation système ou le développement de serveurs web, la sûreté et les hautes performances de Rust sont de vrais atouts, mais ces qualités semblent offrir bien moins de bénéfices dans le développement de jeux.

  • En fin de compte, Rust n’est pas un langage universel mais un langage spécialisé pour certains domaines ; il faut donc réfléchir avec soin à son adéquation avec la nature de son projet.

13 commentaires

 
coremaker 2024-04-29

Je pense que Rust est un langage conçu pour résoudre les problèmes causés par les différentes fautes des développeurs, à mesure que se raréfient les développeurs capables d’écrire un code intègre au niveau du cœur.

Comme il est plus adapté à un développement précis qu’à un développement rapide,
il ne convient pas aux projets où des demandes supplémentaires des utilisateurs surviennent fréquemment et doivent être exécutées.

Malgré cela, si l’on espère voir apparaître une bibliothèque UI,
c’est sans doute parce qu’on s’attend à ce que son utilité augmente même avec une petite UI simple fonctionnant sur un code robuste.

 
kandk 2024-04-29

Je n’ai jamais fait de développement de jeux, donc je ne sais pas vraiment,
mais j’ai l’impression soit que le mauvais langage a été choisi dès le départ, (si la rapidité d’itération était importante, il aurait fallu choisir un langage de niveau script...)
soit qu’il manquait une compréhension approfondie du système.
Je me dis qu’il aurait sans doute rencontré des problèmes similaires même en choisissant C++.

 
cosine20 2024-04-29

C’est vrai. Bon, si j’avais choisi C++, il y aurait quand même eu l’option Unreal...

 
cosine20 2024-04-29

À notre époque, j’ai l’impression que des langages natifs comme Rust ou C++ sont plus adaptés au développement de middlewares comme les moteurs de jeu qu’au développement de clients de jeu.
Un peu comme il existe très peu de cas de développement web full stack avec des langages natifs.

 
kandk 2024-04-29

C’est une langue qui a été conçue dès le départ pour cet usage, comme remplaçante de C++.
On dirait que l’article a fini par devenir une critique du langage.

 
cosine20 2024-04-29

C'est ça. À l'origine, ça avait commencé pour améliorer le moteur interne de Firefox, non ?
Le contenu de l'article donne l'impression qu'ils ont essayé de développer avec Rust dans un domaine qui ne lui convenait pas vraiment, comme si c'était un remède miracle, et qu'ils en ont bavé haha

 
mammal 2024-04-29

Je suis d’accord à 100 %. Pour la logique de jeu, un langage offrant une bonne productivité semble mieux correspondre au cas d’usage.

 
edunga1 2024-04-28

Comme je débute avec Rust, je m’y reconnais un peu.
C’était vraiment pénible de devoir modifier énormément de code à cause des changements liés au borrowing.
Contrairement à Python ou JavaScript, qui reposent beaucoup sur des expressions implicites, Rust a tendance à être explicite, ce qui peut produire un code verbeux, et comme il oblige aussi le programmeur à faire beaucoup de choix, ça peut être fatigant.
Malgré ça, il y a des concepts qu’on ne trouve pas dans d’autres langages, et je trouve ça rafraîchissant et amusant.

Sans Rust Analyzer ou GitHub Copilot, je pense que j’aurais abandonné plus tôt.

 
botplaysdice 2024-04-28

Le développement de jeux, c’est vraiment du hardcore...

 
steamb23 2024-04-28

Au lieu de tout écrire en Rust, du cœur jusqu’au front-end,
que penseriez-vous d’une approche à la Unity ou avec d’autres moteurs de jeu, où le cœur est écrit en Rust puis combiné avec un langage plus productif ?

 
bus710 2024-04-28

Il y a forcément des limites, puisqu’il a tendance à imposer un cadre très strict.

 
[Ce commentaire a été masqué.]
 
GN⁺ 2024-04-27
Avis Hacker News

Partage de son expérience de développement d’un client de métavers et présentation des problèmes de Rust

  • Il existe très peu d’exemples de développement de jeux 3D de grande ampleur en Rust
  • Le refactoring et le travail de connexion entre les différentes parties du programme sont pénibles
  • Le rendu est presque convenable, mais la stack n’est pas complète et n’est pas fiable
  • Les systèmes de GUI 2D sont faibles et demandent beaucoup trop de code par boîte de dialogue
  • Accord avec l’idée que le système async s’étend même à des domaines où il n’est pas nécessaire

En tant que développeur de jeux avec 20 ans d’expérience, il estime que Rust n’est pas adapté au développement de jeux

  • Le code de gameplay doit être flexible et comporter beaucoup de cas limites pour créer des jeux intéressants
  • Le temps de compilation est important et les changements de structure sont fréquents
  • L’ECS est utile pour certains systèmes, mais difficile à utiliser pour le gameplay ou le code UI

L’écosystème du développement de jeux en Rust repose sur le battage médiatique

  • Il a essayé de développer des jeux en Rust, mais l’expérience a été immédiatement horrible
  • Temps de compilation lents, téléchargements massifs de paquets, difficulté propre à Rust, etc.
  • Certains affirment que les autres outils ne sont pas aussi sûrs que Rust, mais dans le jeu vidéo la sécurité mémoire a rarement été un problème majeur

Comparaison de l’expérience de développement avec Bevy, Unity et Godot

  • Il est difficile de comprendre pourquoi choisir Rust aujourd’hui pour développer des jeux
  • Forcer l’ECS à tout absorber gêne le développement d’un gameplay amusant
  • Compte tenu des performances des PC modernes, il n’est pas nécessaire de trop s’inquiéter de l’optimisation multithread

Le langage Nim pourrait être plus adapté que Rust au développement de jeux

  • Il ne freine pas les développeurs et prend en charge le hot reloading

Rust semble être un langage dogmatique qui impose une manière très spécifique de programmer

  • Il fait passer la sécurité mémoire avant tout, ce qui n’est pas très utile en développement de jeux
  • Le langage idéal pour le développement de jeux devrait être productif, offrir des performances suffisantes et s’adresser à des programmeurs expérimentés capables d’accepter une part de risque

La démo d’outillage d’Allen Blomquist montre que la boucle de feedback du développement est importante

  • Rust ne fournissant pas l’environnement de travail souhaité, retour à Unity

Le problème fondamental de Rust est d’avoir abandonné l’orienté objet au profit de la programmation fonctionnelle

  • Cela peut aider au niveau du cœur le plus bas, mais ce n’est pas approprié aux couches supérieures

Pour le développement de jeux, Rust est le pire choix

  • Les valeurs de Rust — précision, sécurité et recherche d’un code parfait — ne correspondent pas au développement de jeux
  • Les jeux ont une durée de vie courte et des cycles de développement brefs, donc la qualité du code n’y est pas si importante
  • Il peut être utile pour le développement de moteurs de jeu, mais doit être utilisé avec un langage de scripting très flexible

En codant en D, il a réalisé qu’il était bien plus facile de modifier la disposition des données qu’en C

  • Passer entre types par référence et types par valeur est difficile en C, mais facile en D