I. Introduction▲
La conception de notre moteur dépend énormément des scripts. Non seulement pour le comportement de l'application et l'intelligence artificielle, mais aussi pour toute la logique du jeu qui est implémentée à l'aide des scripts. À cause de cela, il était clair que nous devions choisir le langage de script avec précaution. Il devait être rapide et facile à utiliser. À la fin, nous avons décidé d'utiliser Mono. Voici la raison.
II. Liste des langages▲
Voici la liste des langages que nous avons analysés :
Nom | Typage | Licence | Utilisé dans… |
Lua (LuaJIT) | Dynamique | MIT | World of Warcraft, Freelancer et plein d'autres |
JavaScript (v8) | Dynamique | BSD | ? |
Angelscript | Statique | zlib | Penumbra, Overgrowth, autres |
Python | Dynamique | Python | Battlefield 2, Eve Online, autres |
Tcl | Tout est chaîne de caractères | BSD | ? |
Squirrel | Dynamique | MIT | Left for Dead 2, Portal 2, Alien Swarm |
JVM | Statique | GPL | ? |
Mono | Statique | MIT, LGPL | SecondLife, Unity3D |
III. Réduire le choix▲
Nous avons décidé de regarder de plus près Angelscript, Lua et Mono. Ces trois langages sont reconnus, possèdent des implémentations stables et ont déjà été utilisés dans de nombreux jeux. J'ai écrit un petit programme test dans chaque langage pour avoir une idée de la documentation, des bibliothèques et bien sûr, des performances. Ce genre de test est souvent biaisé et dans de nombreux cas problématique par rapport aux informations fournies, mais au moins, il fournit une première impression générale des performances pour une configuration spécifique du langage/interpréteur/compilateur.
Le test a été réalisé sur mon Core i5 avec les plus hauts paramètres d'optimisation disponibles. Les résultats sont des moyennes de nombreuses exécutions afin d'éliminer la plupart des mises en cache et des trucs Just In Time (JIT).
Configuration du langage | Recherche de chemin A* | Appel au script | Appel de fonction C |
Référence C++ (GCC 4.7.2) | 0,3 ms | < 0,001 µs | < 0,001 µs |
C#/Mono 2.10 | 3,0 ms | 0,14 µs | 0,01 µs |
Lua/LuaJIT 2.0 | 3,3 ms | 0,06 µs | 0,05 µs |
Angelscript 2.25.1 | 9,7 ms | 0,17 µs | 0,09 µs |
IV. Lua▲
Lua semble être le choix par défaut dans le monde du jeu vidéo. Lua est très léger dans tous les aspects. La syntaxe est incroyablement simple et l'interpréteur tient dans 120 ko. Il est bien documenté, couramment utilisé et son développement est toujours actif dans une université du Brésil. De multiples bibliothèques existent afin de faciliter l'enregistrement des fonctions C. Le débogage est possible, mais n'est pas supporté directement. Nous devrions sûrement implémenter notre propre débogueur.
LuaJIT semble être l'un des meilleurs compilateurs JIT. Même lors de l'utilisation de structures de données plus complexes, il atteint les performances d'un code C# compilé avec Mono, ce qui est très impressionnant si vous gardez à l'esprit que Lua est aussi dynamique qu'un langage peut l'être : tout est conservé dans des tables, même les variables locales et les fonctions ne sont que des entrées dans la table.
Et cela nous amène au problème principal avec Lua : il est extrêmement puissant dans le sens où vous pouvez implémenter virtuellement n'importe quel paradigme (grâce aux toutes puissantes tables), mais la syntaxe est réduite à un simple ensemble d'opérateurs et de mots clés qui deviennent pénibles à utiliser dès que vous voulez faire des choses plus avancées. Lua est totalement capable de faire de la POO, mais le code devient tellement embrouillé que vous ne voulez pas le faire. Regardez les équivalents Lua de ces exemples Moonscript. Pour être juste, l'implémentation du test de recherche de chemin A* possède le même nombre de lignes que les implémentations C# ou C++ (voir les implémentations C# et Lua).
Conclusion : léger, rapide et mature. La syntaxe est belle tant que vous ne touchez pas aux métatables.
V. Angelscript▲
Angelscript est un langage de script relativement méconnu. Il possède une syntaxe à typage statique presque identique au C++. Ces types statiques permettent à la machine virtuelle d'être remarquablement plus rapide que l'interpréteur par défaut de Lua. Récemment, un premier compilateur JIT pour Angelscript a été développé, mais je n'ai pas été capable de le lancer pour un autre script que le « Hello World ».
Angelscript est activement développé par une seule personne depuis 2006, donc certains pourront argumenter sur la maturité de la bibliothèque. Toutefois, cela fonctionne sans aucun problème dans mes tests. La documentation est complète, mais n'aide pas toujours pour certains détails. Le langage ne possède pas son propre débogueur, mais comme pour Lua, fournit des informations sur l'exécution en cours (pile d'appels et autres) rendant l'écriture d'un débogueur facile. Angelscript est utilisé dans certains projets indépendants comme Amnesia : The Dark Descent ou Overgrowth.
Conclusion : une syntaxe sympa mais plus lent que les autres candidats sans compilateur JIT stable.
VI. Mono▲
Mono est l'implémentation de la CLI (Microsoft .NET) par Novell. Cela signifie que ce n'est pas un langage, mais une machine virtuelle qui peut exécuter n'importe quel bytecode .Net. J'ai utilisé le C#, mais il existe d'autres compilateurs .Net pour F#, Python, C++, Java, Lua, Ruby, Scala et plein d'autres.
La CLI possède une interface unifiée qui permet à tout langage supporté d'utiliser un autre code .Net (même les classes peuvent être utilisées à partir d'autres langages) et nous permet de fournir une unique bibliothèque de scripts sans nous soucier du langage que nous utilisons réellement.
Mono est un projet énorme, actuellement en développement, qui possède presque 100 000 commits venant de plus de 500 développeurs. Nous pouvons espérer des améliorations continues pour les prochaines années. Dans le monde de Linux, il est largement utilisé pour l'exécution d'applications .Net. En contraste avec cela, seulement un petit nombre de projets utilise Mono pour les scripts (Unity3D et Secondlife). Toutefois, Mono encourage officiellement l'utilisation de Mono pour les scripts. La documentation est un peu éparpillée pour certains points, mais devrait être assez correcte pour travailler avec obsolète ou non existante dans la plupart des cas importants et vous devez souvent chercher sur Google ou StackOverflow. Dans certains cas, j'ai dû lire le code source pour comprendre pourquoi une fonction faisait ce qu'elle faisait. Le débogage peut être facilement réalisé avec MonoDevelop qui fournit un débogueur complètement fonctionnel avec toutes les fonctionnalités que nous pouvons souhaiter.
C#/Mono a eu les meilleurs résultats en performances brutes par rapport à tous les langages/configurations testés et n'est « que » dix fois plus lent que l'implémentation de référence en C++. Le .Net de Microsoft semble même être plus rapide.
Conclusion : c'est un monstre de six millions de lignes de code. Toutefois, il est rapide, stable et supporte beaucoup d'autres langages.
VII. Remerciements▲
Merci à Upvoid de nous avoir permis de traduire leur journal de développement. N'hésitez pas à découvrir leur projet : Upvoid Engine, un moteur de jeu orienté pour les mondes ouverts et les terrains voxel destructibles.
Merci à Winjerome pour ses corrections et ced pour sa relecture orthographique.