Vaut-il la peine d'implémenter les mécanismes / règles du jeu séparément du code principal?

25

Je ne sais pas si cela correspond à la portée de cette communauté, ou devrait plutôt aller à Stackoverflow.

Supposons que je souhaite que mon jeu soit facilement extensible dans son cœur, c'est-à-dire que beaucoup de gens, même sans connaissances de programmation décentes, puissent non seulement modifier les règles existantes, mais même y ajouter des mécanismes de jeu totalement nouveaux. Je ne suis pas moi-même un bon programmeur, mais je suis prêt à apprendre, j'ai juste besoin de quelques instructions et de l'assurance que cela peut être fait.

Ce que j'ai pensé, c'est s'il est possible / faisable de mettre en œuvre la mécanique du jeu d'une manière ou d'une autre, séparément du code de l'utilitaire principal? Je veux dire, pour les jeux de table, nous avons ces livres de règles qui ne contiennent pas d'algorithmes réels de toutes les actions, mais décrivent plutôt certains protocoles et limites, référençant fortement le contexte de chacun de ces éléments. Est-il possible de faire quelque chose de similaire pour un jeu PC, comme décrire toutes les règles dans un très haut niveau, facilement lisible (et modifiable) par un langage de programmation humain, qui est ensuite "consommé" et analysé par le code utilitaire dans un instance de travail de la mécanique de jeu?

Cela semble vraiment avoir besoin d'écrire mon propre langage et un compilateur pour cela)) Ce que je ne pourrai pas faire, bien sûr. Mais peut-être existe-t-il une approche plus facile du problème?

Pour info: ma langue de choix pour le code utilitaire sera Python 3.x

c'est
la source
Comme vous êtes inexpérimenté et travaillez en tant que développeur unique, je vous suggère de ne pas essayer de tout mettre en œuvre vous-même. L'utilisation des bibliothèques SDL2 peut vous être très utile dans de nombreux domaines et elles ont des liaisons Python pour que vous puissiez travailler dans la langue avec laquelle vous êtes à l'aise. Pour réaliser ce que vous recherchez, la conception de votre architecture doit être faite très, très, soigneusement et je prévois au moins une réécriture complète même pour une équipe expérimentée. En outre, Python n'est pas vraiment plus facile à apprendre que tout autre langage et, à mon avis, a des problèmes majeurs au niveau intermédiaire.
ttbek
Le concept que vous recherchez est courant en dehors du développement de jeu. Il existe une collection d'outils logiciels appelés moteurs de règles métier qui doivent faire exactement cela. Dans le développement de jeux, vous pouvez également utiliser ces outils. Le GameplayKit d'Apple, par exemple, incluait les classes GKRuleSystem et GKRule dans un but similaire. Il faudrait un certain effort d'extension pour permettre la modification externe de cela, mais pourrait être structuré de manière à changer le comportement sans recompilation de votre code.
Sandy Chapman

Réponses:

34

De manière générale, la facilité avec laquelle tout système peut être étendu dépend du degré auquel ses sous-systèmes sont étroitement ou faiblement couplés . Habituellement, plus les sous-systèmes sont couplés de manière lâche, plus il est facile de les modifier car ils sont isolés et ne nécessitent pas nécessairement une compréhension complète du système dans son ensemble.

Cependant, rien n'est gratuit - un tel système nécessite généralement plus de ressources (diverses combinaisons de temps, d'argent et de compétences) pour être construit. Le degré d'extensibilité que vous avez décrit me semble être en contradiction directe avec le niveau de compétence que vous vous êtes attribué. Cela pourrait être fait, mais créer un logiciel comme vous l'avez décrit est une entreprise très difficile.

La chose la plus proche que je connaisse est Vassal (qui est beaucoup plus programmatique que vous l'avez décrit), ou la création d'un mod pour Tabletop Simulator (qui dépend principalement de l'interaction humaine pour interpréter et appliquer les règles du jeu).

Pikalek
la source
Des conseils solides. J'essaie de garder mon code aussi librement que possible pour faciliter l'extensibilité, mais vous aurez toujours des cas où il est tellement plus facile de coder en dur / coupler quelque chose. Même en tant que développeur professionnel, ce n'est pas une tâche facile et ce n'est certainement pas un bon débutant.
angarg12
TTS prend désormais en charge Lua et l'application des règles n'est pas complètement à la hauteur des interactions humaines maintenant.
Ave
17

Ce que j'ai pensé, c'est s'il est possible / faisable de mettre en œuvre la mécanique du jeu d'une manière ou d'une autre, séparément du code principal de l'utilitaire?

C'est absolument possible. Une façon souvent utilisée dans les jeux est le script Lua .

De l'article lié:

Lua a été initialement conçu en 1993 comme un langage pour étendre les applications logicielles afin de répondre à la demande croissante de personnalisation de l'époque.

De nombreux jeux utilisent Lua. (Je lierais mais la réputation d'un nouvel utilisateur limite mon nombre de liens.)

Les scripts Lua peuvent être compilés au moment de l'exécution. Cela signifie qu'ils peuvent (par exemple) être des fichiers texte situés dans le répertoire "scripts" de votre jeu, facilement modifiables par un modder. Votre jeu les charge et les exécute.

J'ai vu des scripts Lua définir les propriétés des unités en jeu. Voici un exemple aléatoire de TA Spring.

Mais vous voulez "décrire toutes les règles". C'est possible en théorie, car Lua est un langage complet, mais le problème est que vous devez être assez prémonitoire pour que le code du jeu de base sache rechercher des scripts pour étendre son comportement.

Par exemple, vous pourriez développer un jeu de cartes qui sait rechercher des cartes dans un répertoire "scripts / cartes". C'est idéal pour ajouter de nouvelles cartes ou modifier des cartes existantes. Mais si vous souhaitez plus tard étendre votre jeu pour inclure des miniatures sur une grille, vous devrez modifier le code principal - aucune quantité de violon Lua ne vous y amènera tout seul.

Veuillez noter: j'évoque Lua parce que je sais qu'il est couramment utilisé à la fois dans les jeux et dans les logiciels de personnalisation. Je ne dis pas que c'est la seule solution, ni la meilleure pour les besoins de celui qui l'interroge.

Nichevo
la source
7
Cette réponse implique que Lua est le seul langage de script utilisé de cette façon. Il existe de nombreux autres langages de script qui peuvent être intégrés dans les moteurs de jeu. Certains moteurs suivent également leur propre chemin et implémentent leur propre langage de script spécifique au domaine. Je ne recommanderais généralement pas cela (car la construction d'une langue est une tonne de travail), mais il convient de le mentionner.
Philipp
3

Il existe un continuum d'approches et la pertinence de l'une d'entre elles dépendra exactement de ce que vous essayez de faire. Plus précisément, combien de contrôle souhaitez-vous offrir au tweaker?

À l'extrême fin du contrôle, vous pouvez simplement laisser le tweaker modifier le code de l'ensemble du jeu. À ce stade, vous publieriez essentiellement le code de l'utilitaire et au moins un exemple d'utilisation. Un tweaker peut utiliser autant ou aussi peu de code qu'il le souhaite.

Une approche qui offre un peu moins de contrôle serait de "geler" votre code utilitaire (par exemple en le compilant au préalable) et de ne laisser que les tweakers remplir des fonctions spécifiques (rappels), restreignant ce qu'ils peuvent faire. Selon ce que vous voulez faire, cette approche peut prendre plusieurs formes. Une méthode courante serait de mettre toute la partie d'affichage dans le code utilitaire / principal et toutes les mécaniques dans la partie modifiable. Ou, vous voudrez peut-être garder certaines mécaniques dans la partie "gelée" parce que les joueurs ne voudront probablement pas les changer, ou les rendre modifiables est trop compliqué.

À l'extrémité basse du continuum, on laisse uniquement les tweakers changer les valeurs dans une plage fixe. Un fichier de données qui vous permet de sélectionner les couleurs des objets dans le jeu en serait un exemple. Vous pouvez cependant utiliser cette approche tout en offrant beaucoup de personnalisation. Il serait possible de définir une sélection de fonctions et de permettre aux tweakers de les composer pour créer les rappels de l'approche précédente, mais sans leur permettre d'en définir de nouvelles. Ou peut-être que vous sautez la partie de composition et offrez simplement une sélection finie.

Les détails de toutes ces approches et celle qui correspond à votre cas d'utilisation dépendent du type de jeu de base que vous souhaitez créer et du contrôle que vous souhaitez abandonner. Notez que les jeux commerciaux n'utilisent généralement que les deuxième et troisième méthodes car la première permet aux joueurs de créer des jeux entièrement séparés, ce qui introduit des problèmes de licence complexes. Notez que ces approches formant un continuum, la deuxième approche peut également introduire ces problèmes.

Ryan1729
la source
En faire open source est mon objectif, en fait. Ce que je vois comme un problème est de savoir comment implémenter cette extensibilité de la manière la plus simple, afin que les autres joueurs du jeu (qui est MP game, btw) puissent créer leurs propres extensions de l'ensemble de règles de base et les partager avec chacun d'autres, en évitant en quelque sorte les conflits en même temps. Donc, si un utilisateur développe une extension remplaçant certaines règles, et un autre développe une extension différente, comment faire en sorte que le troisième utilisateur qui souhaite utiliser les deux dans ses jeux ne rencontre pas de problèmes de compatibilité? En plus de les forcer à collaborer étroitement.
tis
..et pour l'implémenter de telle manière qui ne nécessitera aucune modification de code utilitaire et donc trop de connaissances en programmation.
ce
1
Je ne pense pas qu'il y aurait un moyen de prévenir les problèmes de compatibilité, (même la définition de la couleur de quelque chose peut provoquer cela!) Je pense que la meilleure chose à faire est de trouver un moyen de détecter les problèmes de compatibilité possibles et d'avoir un bon moyen pour les utilisateurs répondre. Selon la conception de l'interface de code utilitaire et les extensions en question, il peut y avoir un moyen de commander des rappels, etc. qui produit le résultat souhaité. Là encore, il pourrait ne pas y en avoir. Alerter l'utilisateur qu'il pourrait y avoir des problèmes et pourquoi cela semble être une meilleure expérience utilisateur que des choses qui se brisent sans explication.
Ryan1729
2

Il est absolument possible de séparer les règles du système du code qui applique ces règles. Je préfère structurer mon code de cette façon pour les projets complexes, car cela facilite l'ajout de nouvelles règles ou la modification des règles plus tard sans introduire de bogues dans le système sous-jacent. Et les bogues dans un moteur de règles sont détectés plus rapidement que les bogues dans un système où les règles et les autres codes sont mélangés entre eux, car le même moteur de règles est utilisé à plusieurs reprises par chaque règle.

Que cela en vaille la peine dépend de la complexité du système. Comme si je ne m'embêterais pas pour Pac-Man, mais je ne pouvais pas imaginer écrire Dwarf Fortress autrement.

Robyn
la source
Merci, @Robyn. Un conseil de lecture à quelqu'un qui ne sait même pas comment aborder ce design correctement? Existe-t-il des modèles de conception bien établis pour de telles applications? Des livres qui couvrent le sujet?
tis
Pas de livres, désolé. Mais l'idée de base d'un moteur de règles simple: créer une classe Rule qui possède une propriété pour chaque élément d'information dont vous avez besoin pour décrire une règle. Si certaines de ces propriétés contiennent des fonctions lambda, vous pouvez leur affecter des comportements complexes. Créez une classe qui instancie une liste de règles, de sorte que toutes vos règles soient au même endroit. Créez une autre classe qui a une méthode qui prend une liste de règles en entrée et les applique au système.
Robyn
2

C'est définitivement faisable. Si cela en vaut la peine, cela dépend de vos objectifs.

Vous n'avez pas besoin d'inventer votre propre langage ou d'écrire un compilateur pour que cela fonctionne.

Si vous voulez que votre jeu soit facilement extensible, c'est probablement une bonne idée d'y aller.

C'est probablement plus de travail pour vous, au moins à court terme, pour créer des systèmes compréhensibles et rendre les choses faciles à modifier.

Un jeu qui fait cela est Rimworld (je n'ai aucune affiliation) et vous pourriez voir et apprendre de la façon dont ils l'ont fait, en mettant essentiellement beaucoup de données de jeu et de mécanismes dans des fichiers XML qui sont dans les dossiers de jeu pour que quiconque puisse les voir et modifier. Le cœur / moteur du jeu a été créé avec Unity.

Il y a aussi la possibilité d'étendre le jeu plus loin / plus profondément par le codage réel, j'en sais moins à ce sujet mais vous pouvez en apprendre en consultant le forum des mods.

La possibilité de modding rend le jeu plus intéressant pour beaucoup de gens et je pense qu'il a beaucoup contribué à son succès. Cela permet également aux développeurs d'apporter tout le contenu de mod qu'ils souhaitent dans le jeu de base et d'une manière qui accélère le développement et améliore le jeu car ils obtiennent l'aide de beaucoup de gens, et ils peuvent décider de prendre les choses en fonction de ce qui est populaire, ce qui semble fonctionner, etc.

Et bien sûr, en particulier pour un petit studio indépendant, ils ont des centaines de personnes qui proposent des idées et les testent, ce qui représente beaucoup de travail qu'ils ne pouvaient pas faire eux-mêmes, ni probablement embaucher des gens pour le faire.

user985366
la source
Bien que je puisse voir comment les données de jeu peuvent être définies avec xml, je ne peux pas imaginer comment vous pouvez les utiliser pour définir des mécanismes / règles de jeu. Pourriez-vous fournir un exemple / article sur le sujet, peut-être?
ce
Les règles @tis ne sont qu'un autre type de données. Si mon moteur a "If A do B", je peux charger A et B à partir d'un fichier XML, maintenant les utilisateurs peuvent mettre des règles assez arbitraires, un bit supplémentaire qui peut aider est de fournir une liste avec tous les As et Bs possibles que vous supportez en soi , par exemple, "Si état statustype alors movespeed 100", "Si état statustype et time> x then status statustype" Donc, dans votre conception, pensez aux types de règles que vous souhaitez autoriser sur quels types d'objets (état, temps, movespeed) et avec quels types de composition autoriser (et / ou, etc ...). Si état sous l'eau et temps> 5 points de vie -10.
ttbek
1

Vous voudrez peut-être examiner la conception orientée objet . Python a un bon support pour cela.

Des livres épais sont écrits à ce sujet, ce qui peut être effrayant lorsque vous êtes nouveau, mais les principes fondamentaux sont assez faciles.

L'essentiel est simplement d'identifier le type d'objets avec lesquels vous travaillez. Vous ne dites pas à quel genre de jeu vous pensez, mais des choses comme le joueur, le monstre, l'objet, l'équipement, l'arme, l'armure et ainsi de suite sont des objets typiques.

Si vous voulez différents types de jeu, vous voudrez probablement un objet de jeu qui prend en charge la condition de victoire et autres. Peut-être aussi un objet Map?

Parfois, il n'est pas clair si quelque chose mérite d'être un objet ou non, par exemple des dommages. Si vous n'endommagez pas un objet, le code sera plus simple, mais en faire un objet le rendra plus facile à personnaliser.

Sous -classement : les armes et les armures sont des équipements. Les équipements sont des articles. Il existe probablement d'autres types d'articles. Vous trouverez probablement utile de définir un combattant de classe dont les joueurs et les monstres sont des sous-classes.

L'idée est que, par exemple, les armes auront beaucoup de choses en commun avec tous les autres types d'objets, elles ont un poids, une taille et d'autres propriétés comme ça.

Ainsi, le sous-classement vous permet de dire que "les armes sont comme les autres objets, mais en plus vous pouvez les manier, elles affectent les dégâts que vous faites, etc."

Le sous-classement permet également à vos constructeurs de mod de dire "Mon nouveau type d'arme est comme les armes standard, sauf que ..."

Ensuite, vous devez décider quel objet est responsable de quoi. Ce n'est pas aussi facile qu'il y paraît et vous devriez y réfléchir. Faire les mauvais choix n'affectera pas beaucoup le jeu de base, mais il sera plus difficile à personnaliser.

Tant que vous bricolez vous-même, vous pouvez changer les choses, mais au moment où vous publiez quelque chose au public, faire des changements devient beaucoup plus difficile! Les gens feront des mods qui dépendent des choses comme elles sont maintenant. Même des bugs. Les gens écriront des mods qui dépendent des bogues restant dans le code. Si vous changez les choses, ces mods se briseront et des monstres de lynchage apparaîtront chez vous.

Par exemple:

Un joueur brandissant une arme attaque un monstre portant plusieurs armures. Cela a lieu dans un mode de jeu particulier et sur une certaine carte.

Les deux combattants peuvent avoir des compétences comme Coup critique et Esquive.

Maintenant, quel objet est responsable de quoi?

Il n'y a pas de bonne réponse à cela. Cela dépend beaucoup du type de personnalisation que vous souhaitez autoriser.

Si vous n'appelez jamais un objet (par exemple la carte), cet objet ne peut en aucun cas modifier l'attaque.

Après avoir pris toutes ces décisions, documentez-les . Écrivez un "manuel Modders" qui répertorie exactement quelles méthodes moddables chaque objet possède, quels paramètres ils prennent, ce qu'ils doivent renvoyer, et ainsi de suite et ainsi de suite ...

Bonne chance!

Stig Hemmer
la source
Votre contribution est vraiment appréciée, et vous y mettez beaucoup d'efforts, donc ça vaut vraiment un +1, mais je suis au courant de la POO, en général (bien que je manque d'expérience). Mes problèmes actuels concernent l'approche de conception la plus générale que je devrais adopter. Mon jeu n'est pas quelque chose d'aussi énorme que D&D par échelle, mais il est néanmoins TRÈS profond dans sa mécanique. Cela signifie beaucoup de règles complexes, entremêlées à différents niveaux. Ce que je voudrais permettre aux utilisateurs d'étendre de manière significative, pas seulement de modifier légèrement certaines valeurs. Il se peut qu'il n'y ait pas de solution plus simple, en effet ..
c'est le
@tis La clé de tout cela est de prendre la bonne décision sur ce que sont réellement les objets dans votre modèle OO du jeu. L'endroit "évident" pour commencer est avec les "noms" comme arme, armure, etc. n'est pas le seul moyen, et cela peut conduire à un désordre embrouillé de code non personnalisable. Si une règle dit "vous ne tirez que des monstres avec des balles d'argent dans un cimetière à minuit", où appliquez-vous cette règle dans le code? Dans la classe Gun (ou Bullet), dans la classe Monster, dans la classe Fighter de l'utilisateur d'armes à feu, dans la classe Churchyard ou dans la classe Time? La meilleure réponse pourrait être "aucune de ces
réponses
... et repenser l'ensemble du design en termes de classe Rules (qui est probablement vraiment une base de données) et de classe Conflict Resolution. Maintenant, d'autres règles comme "si vous n'avez pas de balles, vous pouvez toujours utiliser votre arme comme un club" et "si Alice jette un sort qui protège partiellement (mais pas complètement) Bob contre les blessures par balle, tandis que Charlie essaie de tirer sur Bob, alors .... "ont un endroit unique et" évident "à implémenter dans le code. Vous trouverez peut-être que votre classe Gun d'origine fait maintenant très peu, sauf produire des effets audio-visuels - et même pas, s'il s'agit d'un jeu basé sur du texte!
alephzero
1

Un moyen simple d'obtenir un support de base pour cela serait de séparer la plupart des valeurs numériques dans un ou plusieurs fichiers texte distincts pour permettre aux personnes intéressées de les modifier dans l'oubli.

Par exemple, vous avez mentionné les jeux de table; si vous aviez un jeu basé sur D&D, vous pourriez avoir un weapon_damagefichier contenant des lignes comme Battleaxe: 1d12. Votre code utilitaire lirait ce fichier et chaque fois que des dommages étaient causés par Battleaxevotre code le ferait generate a number from 1-12, 1 time(s)et les ajouterait. Ajuster la ligne pour lire Battleaxe: 4d6serait à la place generate a number from 1-6, 4 time(s)et les ajouter. De même, vous pourriez avoir un dossier Creatureset à l'intérieur vous avez un fichier pour chaque créature, y compris des lignes comme AC: 12; puis ajouter de nouveaux fichiers dans ce dossier créerait de nouvelles créatures. Cela pourrait même être fait pour des classes de personnages, des types de terrain, une tonne de choses.

Ce style de personnalisation non-code peut toujours être très puissant et couvrir de nombreuses parties de votre jeu. Cependant, cela ne permet pas vraiment à un utilisateur d'apporter des modifications que vous n'avez pas explicitement spécifiées. Par exemple, vous pouvez permettre Sneak Attack: [damage]à n'importe quelle créature ou classe d'être ajoutée [damage]à n'importe quelle attaque qui remplit les conditions d'une attaque sournoise. Vous pouvez même proposer des moyens de modifier les conditions, telles que "chaque fois que vous attaquez furtivement" ou "chaque fois que vous flanquez" ou "chaque fois que vous avez un avantage". Cependant, si un utilisateur décide qu'il souhaite que les attaques furtives soient "Lorsque vous effectuez un jet d'attaque, vous pouvez également lancer furtivement contre la perception de la cible. Si les deux jets réussissent, ajoutez les dégâts d'attaque sournoise"

Si vous vouliez qu'un utilisateur puisse ajouter un comportement complètement nouveau au jeu sans avoir besoin de compétences de codage au même niveau que le développeur, alors comme les gens l'ont mentionné, vous envisagez de créer essentiellement un moteur de jeu ou un langage de programmation distinct. Pour les modifications qui ne nécessitent pas de connaissances en codage, les fichiers de données textuels et les structures de dossiers peuvent toujours fournir de nombreuses options. Si vous souhaitez que les utilisateurs modifient plus que cela, vous devrez leur demander d'apprendre ou de connaître un langage de programmation.

Kamil Drakari
la source
Oui, je dois également leur permettre d'ajouter de nouvelles mécaniques, il ne suffit pas de modifier certaines valeurs. J'ai également pensé que cela pourrait nécessiter un langage séparé, je pensais simplement qu'il y en avait déjà un que je peux utiliser dans mon code utilitaire Python.
ce
@tis Avez-vous déjà réfléchi à ce que Wikipedia a sur le sujet? en.wikipedia.org/wiki/Logic_programming
ttbek
0

[Je suis un développeur de logiciels depuis des décennies, mais sans expérience en développement de jeux, alors peut-être que l'industrie des jeux adopte des approches différentes, peut-être pour de bonnes raisons ...]

Votre approche est absolument logique pour moi. Le noyau fournit les fonctionnalités de base sur lesquelles la mécanique et les règles s'appuient, c'est donc une API qui doit être utilisée par les composants de niveau supérieur.

Et lors de la conception d'une API, ma directive préférée est de créer le langage dans lequel vous souhaitez exprimer votre code de niveau supérieur (bien sûr, avec les limitations de syntaxe de votre langage de programmation).

Donc, une bonne approche serait d'écrire des règles et des mécanismes hypothétiques exactement comme vous aimeriez qu'ils soient exprimés (avec la syntaxe de Python, bien sûr), trouvant ainsi ce que vous voulez que l'API de base fournisse aux règles et aux mécanismes couches.

Et bien sûr, je recommanderais de jeter un œil aux fonctionnalités de script des jeux existants pour avoir une idée de ce qu'ils font.

Ralf Kleberhoff
la source