Quels sont les défis et les avantages de l'écriture de jeux avec un langage fonctionnel?


81

Bien que je sache que les langages fonctionnels ne sont pas les langages les plus couramment utilisés pour l'écriture de jeux, ils présentent de nombreux avantages qui semblent intéressants dans n'importe quel contexte de programmation. Je pense que la facilité de la parallélisation pourrait être très utile, car nous nous concentrons sur de plus en plus de processeurs.

De plus, avec F # en tant que nouveau membre de la famille .NET, il peut être utilisé directement avec XNA, par exemple, ce qui abaisse un peu le seuil, par opposition à LISP, Haskell, Erlang, etc.

Si quelqu'un a de l'expérience dans l'écriture de jeux avec du code fonctionnel, quels sont les avantages et les inconvénients? Pour quoi était-il adapté, quoi non?

Edit: Trouver qu'il est difficile de décider qu'il existe une seule bonne réponse à cette question est probablement mieux adapté en tant que publication dans un wiki de communauté.


3
avec l'un de mes jeux préférés (Rogue) écrit dans LISP, cette question (et son potentiel de réponse) m'intéresse beaucoup.
Justin L.

Je ne savais pas que Rogue était écrit en LISP, mais trouvez cela intéressant. Jeu classique. :)
McMuttons

2
Vous ne savez pas de quoi vous parlez. Rogue a été écrit en C. roguebasin.roguelikedevelopment.org/index.php?title=Rogue
Mason Wheeler le

2
Je suis sûr que vous avez raison sur le fait que Rogue soit en C, puisqu'il a été écrit sous Unix, mais il existe certainement plusieurs clones de Rogue dans Lisp: cl-user.net/asp/root-dir (pas le lien direct du jeu) , il avait tellement de caractères spéciaux qu'il semble avoir rompu le lien).
Cyclope

Réponses:


57

Je travaille actuellement sur un jeu à Haskell. Je ne peux pas parler de la programmation fonctionnelle en général, mais de Haskell en particulier:

Le bon

Ce sont les choses impressionnantes qui font que Haskell se démarque vraiment.

  • La pureté signifie que le raisonnement à propos de votre code est beaucoup plus facile. Vous n'avez pas à vous soucier de la valeur "actuelle" d'une variable ni à savoir si l'utilisation d'une fonction donnée sera en conflit avec votre état global d'une manière ou d'une autre. Cela signifie également que le parallélisme et la concurrence sont beaucoup plus faciles à utiliser (et dans de nombreux cas, triviaux). Ces choses peuvent être une aubaine pour les développeurs de jeux.
  • Haskell rend très facile l'écriture à un niveau très élevé en utilisant des abstractions de votre propre création. Il est souvent plus facile d'écrire du code très générique que du code spécialisé en Haskell, et les avantages en découlent: moins de temps de développement et une meilleure compréhension du code. C'est plus vrai dans Haskell que dans n'importe quel autre langage que je connaisse, utiliser une interface revient à utiliser un langage entièrement nouveau (tout en conservant les avantages du reste de l'écosystème Haskell). Ce que la plupart des langues appellent des fonctionnalités linguistiques, Haskell appelle une bibliothèque et ne se sent pas forcé. Si jamais vous vous retrouvez à raisonner sur votre jeu en psuedocode, vous pourriez probablement simplement écrire une interface simple et en faire du code réel, et cela en vaut généralement la peine.
  • Cela pourrait entrer en conflit avec d'autres réponses, mais Haskell gère mieux le code impératif que toute autre langue que je connaisse. Les contraintes de pureté impliquent que Haskell opère une séparation entre les concepts "d'évaluation" (expressions réductrices) et "d'exécution" (effets secondaires). Vous pouvez contrôler quand et comment les effets secondaires sont effectués avec une facilité inégalée par les langages dits "impératifs". Malgré ce que j'ai déjà dit à propos de la pureté, certaines liaisons C sont encore très impératives (OpenGL, je vous regarde), aussi ce contrôle fin du code impératif est-il le bienvenu. Même les programmeurs C les plus aguerris vont probablement l'apprécier une fois qu'ils s'y seront habitués.
  • GHC génère des binaires assez rapides. Ils ne sont pas aussi rapides que les fichiers binaires générés à partir des compilateurs C courants, mais ils ont un ordre de grandeur et sont beaucoup plus rapides que ceux que vous obtiendriez avec un langage interprété. Même si vous ne pouvez pas écrire votre jeu dans d'autres langages de haut niveau comme Python, car il serait trop lent, il y a de bonnes chances que vous puissiez le faire en Haskell.
  • Bien qu'il n'y ait pas beaucoup de bibliothèques liées au jeu dans Haskell, comme indiqué dans "The Bad" ci-dessous, l'interface de fonction étrangère de Haskell est la plus simple que j'ai jamais utilisée. Vous pouvez vous lier à C en écrivant presque exclusivement en Haskell.

Le mauvais

Ce sont des choses qui ne sont pas bonnes mais qui peuvent être contournées sans trop d'effort.

  • Le temps et les efforts nécessaires pour apprendre Haskell peuvent être assez longs si vous êtes très habitué à travailler avec des langages non fonctionnels. Le langage lui-même n’est pas très difficile, mais lorsque vous prenez en compte des extensions de langage communes et le nombre considérable de bibliothèques (rappelez-vous, beaucoup de choses que vous pourriez considérer comme des fonctionnalités de langage dans d’autres langages sont des bibliothèques en Haskell), cela semble beaucoup plus inquiétant. À mon avis, ça vaut le coup, mais d’autres peuvent ne pas être d’accord.
  • Certaines personnes se plaignent souvent de la paresse. Si vous savez ce que vous faites, vous ne causerez pas de fuites d'espace difficiles à localiser (je n'ai pas créé de fuite d'espace depuis quelques années maintenant), mais les débutants ont bien plus de problèmes avec cela. Il serait insensé de vouloir abattre ces personnes et de prétendre que ce n'est pas un problème, mais j'affirmerai que c'est un problème qui est facilement résolu avec l'expérience.
  • Il n'y a pas beaucoup de bonnes bibliothèques pour créer des jeux à Haskell, et peu de Haskellers y écrivent des jeux, il est donc difficile de trouver des ressources et de l'aide à cet égard.

Le moche

Ce sont des choses qui nécessiteraient des efforts considérables à surmonter.

  • Si vous écrivez un jeu qui consomme beaucoup de ressources, le récupérateur de déchets de GHC pourrait bien vous mordre beaucoup. Il s’agit d’un GC générationnel, arrêtez le monde, vous pouvez donc parfois perdre quelques images. Ce n'est pas grave pour certains jeux, mais c'est un problème majeur pour d'autres. À l'instar d'autres développeurs de jeux utilisant Haskell, nous aimerions voir un GC en temps réel implémenté pour GHC, mais à ma connaissance, aucun effort n'est encore consenti. Actuellement, je ne m'inquiète pas de travailler autour de cela (et je n'ai encore vu aucune image perdue), mais au moins une autre équipe a eu recours à la boucle de rendu principale en C.

2
Que pensez-vous de FRP?
Wei Hu

4
@Wei Hu: Je suis un grand fan de l'idée de FRP et l'ai moi-même longuement étudié, notamment en créant quelques sémantiques différentes et en écrivant quelques implémentations. Les meilleures implémentations ont encore de graves bogues sémantiques et / ou d’implémentation. Je dirais qu'ils sont viables pour le développement de jeux, mais ne présentent pas (encore) beaucoup d'avantages par rapport aux approches traditionnelles.
Jake McArthur

1
Un utilisateur anonyme a tenté d’éditer cette réponse en effaçant la partie «laide». "Le ramasse-miettes de Haskell est maintenant concurrent, parallèle et générationnel à partir de 2011 ( ghc.haskell.org/trac/ghc/blog/new-gc-preview )"
Jari Komppa Le

1
Malheureusement, ce n'est pas vraiment vrai. Le GC simultané s'est avéré trop compliqué pour justifier la légère amélioration globale, et il n'a pas été fusionné.
Jake McArthur

1
@ Hi-Angel Il y a un vieux backend GHC qui a généré C, mais ce n'est pas différent du générateur de code natif ou du backend LLVM. Il nécessite toujours le runtime GHC. En outre, un backend C n’a rien de spécial qui permettrait d’éviter plus facilement un ramasse-miettes. S'il était si facile et si économique d'éliminer le GC, les autres moteurs le feraient probablement aussi.
Jake McArthur

19

Au cours de la dernière année, j'ai développé un moteur de jeu commercial à Haskell. Pour nous, l'expérience a été extrêmement positive. Notre monde de jeu est complexe et Haskell a facilité la modélisation du processus de conversion d’un format d’éditeur à un format de moteur de jeu. Je détesterais penser à quoi ce code ressemblerait dans un langage impératif.

Des fuites d’espace ont parfois été signalées, et bien qu’elles aient causé quelques problèmes, dans l’ensemble, elles ont été modestes (par exemple, par rapport à des impasses dans des projets Java de taille similaire) et une fois résolus , ils sont restés fixes.

Nous utilisons un PRF semblable à Yampa, et il y a certes une courbe d'apprentissage associée, mais une fois que c'est terminé, l'expérience est très positive. Les bibliothèques ne nous ont pas posé de problème - tout ce dont nous avions besoin était disponible. Les retards de la collecte des ordures posaient un problème particulier, car ils concernaient une plate-forme intégrée. Nous avons utilisé du C ++ pour gérer l'animation. La performance a également été un problème avec cela étant une plate-forme intégrée (= processeur lent). Nous avons fait du C et nous étudions également les technologies Haskell émergentes telles que l'accélération. L'animateur C ++ était une décision de conception très tôt et les endroits où le code est trop lent ne sont que de très petites zones. À long terme, nous voulons traduire tous nos C en Haskell.

Haskell a rendu le travail difficile facile, et toutes les difficultés que je viens de mentionner ont été minimes par rapport à la grande quantité de code complexe que nous avons produit, propre, maintenable et pratiquement incassable. Le parallélisme sera très prochainement un problème dans le développement de jeux, et nous sommes extrêmement bien placés pour le gérer. Une partie de ce que j'ai dit peut ne pas s'appliquer à de petits projets, car nous sommes sur le long terme, donc les coûts de démarrage tels que les courbes d'apprentissage, le soutien des bibliothèques, etc., sont beaucoup moins problématiques.


7
Cela fait presque 5 ans que vous avez posté cette réponse; Seriez-vous prêt à le mettre à jour? Comment le moteur de jeu commercial a-t-il fonctionné? Quelles pièces ont prouvé leur valeur? Avez-vous pu profiter du parallélisme comme vous l'espériez?
Levi Morrison

17

Dave mentionne d'excellents points, bien que je dois souligner que Haskell a résolu ses deux problèmes. L'apatridie peut être contournée à l'aide de la monade d'état (EDIT: pas vraiment - voir ci-dessous pour plus de détails) , et le séquencement peut être traité à l'aide de la monade IO (EDIT: ou de toute autre monade, d'ailleurs ...) .

Les défis que vous aurez à relever (et sur lesquels j’ai essayé d’apprendre la programmation de jeux et Haskell) vont plus dans ce sens. (Celles-ci sont toutes spécifiques à Haskell, étant donné que je n'ai pas encore approfondi d'autres langages de PF.)

  • Courbe d'apprentissage de la PF: La PF nécessite un changement complet de mentalité par rapport à la programmation itérative. Apprendre à penser en termes de cartes et de plis plutôt que de boucles nécessite un entraînement mental si vous n’êtes pas habitué.
  • Mathy courbe d'apprentissage: Haskell est à la fois béni et maudit par la sophistication mathématique de ses concepteurs, car après avoir appris les bases de la PF, vous êtes coincé avec des monades, des morphismes, des flèches et de nombreuses autres considérations qui, sans être difficiles en eux-mêmes, sont très abstraits.
  • Monades: ces chiots ne sont pas particulièrement difficiles à comprendre, surtout si vous acceptez l'affirmation d'Eric Raymond selon laquelle ils sont un "hack pour transformer la composition d'une fonction en un moyen de forcer l'enchaînement des appels de fonctions". Malheureusement (bien que cela s'améliore à mesure que Haskell gagne en popularité), de nombreuses explications sur les monades visent la plupart des programmeurs ("elles sont monoïdes dans la catégorie des endofoncteurs!"), Ou à une analogie totalement inutile , L'exemple douloureusement précis de Brent Yorgey, "les monades sont comme des burritos !" Vous pensez qu'il rigole? Que personne ne puisse jamais proposer une analogie aussi maladroite dans un tutoriel? Repensez-y .)
  • Écosystème: si vous avez réussi à surmonter toutes les difficultés de la route, vous serez confronté à la réalité quotidienne du travail avec un langage encore largement expérimental. Dieu vous aide quand vous arrivez ici. C’est là que j’ai commencé sérieusement à jongler avec Scala, ou F #, ou un autre langage où il existe au moins une garantie d’interopérabilité avec d’autres bibliothèques. Il était une fois, j'ai demandé à Haskell de lier et de charger les bibliothèques OpenGL sous Windows. Cela m'a fait me sentir plutôt bien. Ensuite, les liaisons OpenGL ont été rééditées et ont tout cassé. C'est la vie dans le pays Haskell. Honnêtement, ça peut être pénible. Vous voulez un wrapper pour le moteur Bullet? C'est dans Hackage - en abandonwareà partir de novembre de l'année dernière. Vous aimez Ogre3d? Le piratage n'a des liaisons que sur un sous-ensemble de la bibliothèque . L’essentiel est que si vous vous en tenez à une langue hors du commun, pour le développement de jeux, vous passerez beaucoup plus de temps à travailler à la plomberie que si vous ne faisiez que suivre le troupeau et rester bloqué avec C ++.

Le revers de la médaille, c’est que les choses s’améliorent rapidement. Et tout dépend vraiment de ce que vous voulez de l'expérience. Vous voulez créer un jeu et le mettre sur votre site Web pour rechercher la gloire et la fortune? Tenez-vous en C ++ ou en Python. Mais si vous voulez apprendre quelque chose de nouveau qui nécessitera d'innover vos processus, essayez un langage fonctionnel. Ayez juste beaucoup de patience avec vous pendant que vous apprenez.

Antti Salonen a un blog intéressant qui détaille sa liaison avec la programmation de jeux Haskell. Cela vaut la peine d'être lu.

Edit (un an plus tard): Maintenant que j’ai étudié la monade d’État de plus en plus, je me rends compte que ce n’est pas une bonne solution pour un état destiné à persister en dehors d’une fonction particulière. Les solutions réelles à l'apatridie se trouvent dans Haskell dans IOVar, ST, MVar (pour la sécurité des threads), ou via quelque chose comme Yampa, qui utilise Arrows et FRP pour gérer un état interne qui est néanmoins masqué par le développeur. (Cette liste est en ordre de difficulté, bien que les trois premiers ne soient pas particulièrement difficiles une fois que vous avez compris les monades.)


1
Quelques bonnes pensées, même si elles sont assez spécifiques à Haskell, je pense que ce sont des pensées qui s’appliquent à la plupart des langues marginales. Comme vous l'avez mentionné brièvement, je pense que c'est là que des langues comme F # ont le potentiel de briller. Gestion de l'état / de l'interface utilisateur avec C #, par exemple, puis création de modules logiques en F # pour des algorithmes tels que potentiellement recherche de chemin, AI, etc.
McMuttons

5

Objective Caml!

L'utilisation de langages fonctionnels peut être un avantage énorme dans la plupart des types de développement logiciel, principalement parce qu'ils réduisent considérablement le temps de développement. Je peux voir un grand potentiel pour écrire un back-end de serveur dans un jeu, ou les couches d'IA et de logique sur le client, dans un langage fonctionnel. Et comme tout le monde le sait, LISP a été utilisé pour les scripts NPC.

Si j'essayais d'écrire l'interface d'un jeu dans un langage fonctionnel, je choisirais certainement Objective Caml , un langage hybride. C'est un descendant de ML, qui permet de mélanger des styles itératifs et fonctionnels, possède un système objectif avec des objets dynamiques. (Caml est le langage sur lequel F # est modelé.)

Les liaisons OpenGL semblent fonctionner parfaitement et les gens créent des jeux dans OCaml depuis longtemps. La langue peut être compilée et est potentiellement très rapide (il est célèbre que C a été conquis il y a longtemps par certains points de repère, mais comment les choses se passent-elles maintenant).

Il y a aussi des tonnes de bibliothèques. De l'informatique aux liaisons à toutes sortes de bibliothèques.



3

En ce qui concerne les avantages, consultez Clean Game Library (http://cleangl.sourceforge.net/) et consultez le jeu de plateforme. Une fois que vous avez compris la syntaxe (je vous encourage à essayer), vous verrez toute l'élégance des constructions et à quel point la source correspond aux concepts qu'ils expriment. De plus, l'abstraction de l'état et la nécessité de le passer explicitement rendent votre code beaucoup plus convivial.

D'autre part, cela nécessite un changement de paradigme majeur. Une grande partie de ce que vous avez l'habitude de faire sans y penser n'existe soudainement plus et vous aurez du mal à le résoudre, tout simplement parce que vous pensez de manière erronée.


2

De mon point de vue, les plus grands défis seront:

  • Apatridie des langages fonctionnels: L'idée dans les jeux est que chaque entité a un état et que cet état est modifié d'une image à l'autre. Il existe des mécanismes pour imiter ce comportement dans certaines langues (par exemple, les fonctions avec un schéma "!" Dans les plt), mais cela semble un peu anormal.
  • Ordre d'exécution : Dans les jeux, certaines parties de code dépendent d'autres parties de code à terminer avant l'exécution. Les langages fonctionnels ne donnent généralement aucune garantie quant à l'ordre d'exécution des arguments d'une fonction. Il existe des moyens d’imiter ce comportement (par exemple, " (begin..." dans le schéma Plt).

N'hésitez pas à étendre cette liste (et peut-être à ajouter des points positifs ^^).


1
L'ordre d'exécution peut varier dans un langage non strict comme Haskell, mais cela ne pose pas de problèmes de création de parties de code qui dépendent d'autres parties de code. Vous pouvez le considérer comme une évaluation à la demande. Un calcul n'est pas effectué tant que le résultat n'est pas nécessaire. Je pense que la seule façon dont cela pourrait vous causer du chagrin est en termes de performance. Par exemple, il peut être difficile d'obtenir une bonne mise en cache dans certains cas, car vous ne pouvez pas contrôler l'ordre dans l'évaluation autrement qu'en spécifiant les dépendances entre les calculs.
Jason Dagit

1

Vous pouvez écrire votre code en C / C ++ et utiliser un langage incorporé tel que Embedded Common Lisp pour vos scripts. Bien que les compiler sur une plate-forme différente puisse être difficile. Vous pouvez regarder Lisp In Small Pieces pour apprendre à écrire votre propre langage de script. Ce n'est vraiment pas si difficile, si vous avez le temps.


0

J'ai écrit des jeux simples dans LISP et c'était amusant mais ce n'est pas quelque chose que je recommanderais. La programmation fonctionnelle est tout au sujet du résultat final. C'est donc très pratique pour traiter des données et prendre des décisions, mais j'ai trouvé qu'il était difficile de faire du code propre et simple, comme une boucle de contrôle de base.

Je n’ai pas appris le F #, alors c’est peut-être beaucoup plus facile de travailler avec.


Ma pensée initiale pourrait être d’écrire l’échafaudage et la gestion d’états avec un langage impératif, puis de faire la logique de jeu et autres avec des bits fonctionnels. Avec .NET et C # / F #, cela serait très facile, par exemple, car ils utilisent les mêmes bibliothèques et peuvent se parler sans aucune pénalité que je sache.
McMuttons

-1

les aspects positifs seraient la performance et la portabilité et les aspects négatifs, la gestion de la complexité . Les jeux d'aujourd'hui sont très complexes et nécessitent des outils ou un langage de programmation permettant de mieux gérer la complexité, tels que la méthodologie orientée objet ou la programmation générique, difficile à implémenter en programmation fonctionnelle. la langue.


11
Vous plaisantez j'espère? FP est la programmation générique sur les stéroïdes. Pouvoir généraliser à la fois les types de données et les fonctions confère à la PF un réel pouvoir pour gérer la complexité.
Personne

Je conviens que l'un des plus grands atouts de FP est sa capacité à générer du code généralisé.
McMuttons
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.