91 votes

Des modèles de jeux de société à modéliser ?

Pour le plaisir, j'essaie d'écrire un des jeux de société préférés de mon fils sous forme de logiciel. J'espère un jour construire une interface utilisateur WPF par-dessus, mais pour l'instant, je suis en train de construire la machine qui modélise le jeu et ses règles.

En faisant cela, je continue à voir des problèmes qui me semblent communs à de nombreux jeux de société, et peut-être que d'autres les ont déjà résolus mieux que moi.

(Notez que l'IA pour jouer le jeu, et les modèles autour de la haute performance ne sont pas intéressants pour moi).

Jusqu'à présent, mes modèles sont :

  • Plusieurs types immuables représentant des entités dans la boîte de jeu, par exemple des dés, des dames, des cartes, un plateau, des espaces sur le plateau, de l'argent, etc.

  • Un objet pour chaque joueur, qui contient les ressources du joueur (par exemple l'argent, le score), son nom, etc.

  • Un objet qui représente l'état du jeu : les joueurs, le tour de chacun, la disposition des pièces sur le plateau, etc.

  • Une machine à états qui gère la séquence des tours. Par exemple, de nombreux jeux ont un petit pré-jeu au cours duquel chaque joueur lance un dé pour savoir qui passe en premier ; c'est l'état de départ. Lorsque le tour d'un joueur commence, il lance un dé, puis il se déplace, puis il doit danser sur place, puis les autres joueurs devinent de quelle race de poulet il s'agit, puis il reçoit des points.

Existe-t-il un art antérieur dont je peux tirer parti ?

EDIT : J'ai réalisé récemment que l'état du jeu peut être divisé en deux catégories :

  • État de l'artefact de jeu . "J'ai 10 dollars" ou "ma main gauche est sur le bleu".

  • État de la séquence de jeu . "J'ai obtenu deux fois des doubles ; le prochain me mettra en prison". Une machine à états peut être utile ici.

EDIT : Ce que je cherche vraiment ici c'est le meilleur de mettre en œuvre des jeux multijoueurs au tour par tour comme les échecs, le Scrabble ou le Monopoly. Je suis sûr que je pourrais créer un tel jeu en le parcourant du début à la fin, mais, comme pour les autres modèles de conception, il existe probablement des moyens de rendre les choses plus fluides qui ne sont pas évidents sans une étude approfondie. C'est ce que j'espère.

111voto

Andrew Top Points 1709

Il semble qu'il s'agisse d'un fil de discussion vieux de deux mois que je viens juste de remarquer, mais que diable ? J'ai déjà conçu et développé le cadre de jeu d'un jeu de société commercial en réseau. Nous avons eu une expérience très agréable en travaillant avec lui.

Votre jeu peut probablement se trouver dans une quantité (presque) infinie d'états à cause des permutations de choses comme le montant d'argent du joueur A, le montant d'argent du joueur B, etc... Par conséquent, je suis presque sûr que vous voulez rester loin des machines à états.

L'idée derrière notre cadre était de représenter l'état du jeu comme une structure avec tous les champs de données qui, ensemble, fournissent l'état complet du jeu (c'est-à-dire que si vous voulez sauvegarder le jeu sur le disque, vous écrivez cette structure).

Nous avons utilisé le Modèle de commande pour représenter toutes les actions de jeu valides qu'un joueur peut faire. Voici un exemple d'action :

class RollDice : public Action
{
  public:
  RollDice(int player);

  virtual void Apply(GameState& gameState) const; // Apply the action to the gamestate, modifying the gamestate
  virtual bool IsLegal(const GameState& gameState) const; // Returns true if this is a legal action
};

Vous voyez donc que pour décider si un mouvement est valide, vous pouvez construire cette action et ensuite appeler sa fonction IsLegal, en passant l'état actuel du jeu. Si l'action est valide et que le joueur la confirme, vous pouvez appeler la fonction Apply pour modifier l'état du jeu. En vous assurant que votre code de jeu ne peut modifier l'état du jeu qu'en créant et en soumettant des actions légales (en d'autres termes, la famille de méthodes Action::Apply est la seule chose qui modifie directement l'état du jeu), vous vous assurez que l'état du jeu ne sera jamais invalide. En outre, en utilisant le modèle de commande, vous pouvez sérialiser les mouvements souhaités par votre joueur et les envoyer sur un réseau pour qu'ils soient exécutés sur les états de jeu d'autres joueurs.

Il y a finalement eu un problème avec ce système qui s'est avéré avoir une solution assez élégante. Parfois, les actions avaient deux phases ou plus. Par exemple, le joueur peut atterrir sur une propriété au Monopoly et doit maintenant prendre une nouvelle décision. Quel est l'état du jeu entre le moment où le joueur lance les dés et celui où il décide d'acheter ou non une propriété ? Nous avons géré ce genre de situation en ajoutant un membre "Action Context" à notre état de jeu. Le contexte d'action est normalement nul, ce qui indique que le jeu ne se trouve pas dans un état particulier. Lorsque le joueur lance les dés et que l'action "RollDice" est appliquée à l'état du jeu, celui-ci se rend compte que le joueur a atterri sur une propriété non possédée, et peut créer un nouveau contexte d'action "PlayerDecideToPurchaseProperty" qui contient l'index du joueur dont nous attendons une décision. Au moment où l'action "RollDice" se termine, notre état de jeu indique qu'il est en train d'attendre que le joueur spécifié décide d'acheter une propriété ou non. Il est maintenant facile pour la méthode IsLegal de toutes les autres actions de retourner false, sauf pour les actions "BuyProperty" et "PassPropertyPurchaseOpportunity", qui ne sont légales que lorsque l'état du jeu a le contexte d'action "PlayerDecideToPurchaseProperty".

Grâce à l'utilisation des contextes d'action, il n'y a jamais un seul moment dans la vie du jeu de société où la structure de l'état du jeu ne représente pas EXACTEMENT ce qui se passe dans le jeu à ce moment-là. Il s'agit d'une propriété très souhaitable pour votre système de jeu de société. Il vous sera beaucoup plus facile d'écrire du code si vous pouvez trouver tout ce que vous voulez savoir sur ce qui se passe dans le jeu en examinant une seule structure.

De plus, il s'étend très bien aux environnements en réseau, où les clients peuvent soumettre leurs actions via un réseau à une machine hôte, qui peut appliquer l'action à l'état de jeu "officiel" de l'hôte, puis renvoyer cette action à tous les autres clients pour qu'ils l'appliquent à leurs états de jeu répliqués.

J'espère avoir été concis et utile.

18voto

RS Conley Points 6268

La structure de base de votre moteur de jeu utilise le Modèle d'État . Les éléments de votre boîte de jeu sont singletons de différentes classes. La structure de chaque état peut utiliser Modèle de stratégie ou la méthode du modèle .

A Usine est utilisé pour créer les joueurs qui sont insérés dans une liste de joueurs, un autre singleton. L'interface graphique surveille le moteur de jeu à l'aide de la fonction Modèle d'observateur et d'interagir avec lui en utilisant l'un des nombreux objets de commande créés à l'aide de la fonction Modèle de commande . L'utilisation de l'observateur et de la commande peut être utilisée dans le cadre d'un projet de l'UE. Vue passive Mais vous pouvez utiliser à peu près n'importe quel modèle MVP/MVC, selon vos préférences. Lorsque vous sauvegardez le jeu, vous devez saisir un fichier mémento de son état actuel

Je vous recommande de regarder certains des modèles sur ce site. site et voyez si l'une d'entre elles vous attire comme point de départ. Une fois encore, le cœur de votre plateau de jeu sera une machine à états. La plupart des jeux sont représentés par deux états : le pré-jeu/la configuration et le jeu proprement dit. Mais vous pouvez avoir plus d'états si le jeu que vous modélisez a plusieurs modes de jeu distincts. Les états ne doivent pas nécessairement être séquentiels. Par exemple, le jeu de guerre Axis & Battles comporte un plateau de combat que les joueurs peuvent utiliser pour résoudre les batailles. Il y a donc trois états avant le jeu, le plateau principal et le plateau de combat, le jeu passant continuellement du plateau principal au plateau de combat. Bien entendu, la séquence des tours peut également être représentée par une machine à états.

15voto

Pyrolistical Points 12457

Je viens de terminer la conception et la mise en œuvre d'un jeu basé sur l'état en utilisant le polymorphisme.

En utilisant une classe abstraite de base appelée GamePhase qui a une méthode importante

abstract public GamePhase turn();

Ce que cela signifie, c'est que chaque GamePhase contient l'état actuel du jeu, et un appel à l'objet turn() examine son état actuel et renvoie le prochain GamePhase .

Chaque béton GamePhase a des constructeurs qui contiennent les tout le site état du jeu. Chaque turn() a un peu des règles du jeu à l'intérieur. Bien que cela répartisse les règles, cela permet de garder les règles connexes proches les unes des autres. Le résultat final de chaque turn() ne fait que créer le prochain GamePhase et le passage à l'état complet dans la phase suivante.

Cela permet turn() pour être très flexible. En fonction de votre jeu, un état donné peut donner lieu à de nombreux types de phases différentes. Cela forme un graphique de toutes les phases de jeu.

Au plus haut niveau, le code pour le piloter est très simple :

GamePhase state = ...initial phase
while(true) {
    // read the state, do some ui work
    state = state.turn();
}

C'est extrêmement utile car je peux maintenant créer facilement n'importe quel état/phase du jeu pour le tester

Maintenant, pour répondre à la deuxième partie de votre question, comment cela fonctionne-t-il en multijoueur ? Dans certaines GamePhase qui nécessitent une saisie de l'utilisateur, un appel de turn() demanderait à l'actuel Player leur Strategy compte tenu de l'état/phase actuel(le). Strategy est juste une interface de toutes les décisions possibles que a Player peut faire. Cette configuration permet également Strategy à mettre en œuvre avec l'IA !

Andrew Top a également dit :

Votre jeu peut probablement se trouver dans une quantité (presque) infinie d'états à cause des permutations de choses comme le montant d'argent du joueur A, le montant d'argent du joueur B, etc... Par conséquent, je suis presque sûr que vous voulez rester loin des machines à états.

Je pense que cette affirmation est très trompeuse. S'il est vrai qu'il existe de nombreux états de jeu différents, il n'y a que quelques phases de jeu. Pour gérer son exemple, il suffirait d'ajouter un paramètre entier aux constructeurs de ma structure concrète. GamePhase s.

Monopoly

Exemple de quelques GamePhase serait :

  • GameStarts
  • PlayerRolls
  • PlayerLandsOnProperty (FreeParking, GoToJail, Go, etc)
  • PlayerTrades
  • PlayerPurchasesProperty
  • PlayerPurchasesHouses
  • PlayerPurchasesHotels
  • PlayerPaysRent
  • PlayerBankrupts
  • (Toutes les cartes Chance et Community Chest)

Et certains États de la base GamePhase sont :

  • Liste des acteurs
  • Joueur actuel (qui est à son tour)
  • Argent/propriété du joueur
  • Maisons/Hôtels sur les propriétés
  • Position du joueur

Et puis certaines phases enregistreraient leur propre état selon les besoins, par exemple PlayerRolls enregistrerait le nombre de fois qu'un joueur a obtenu des doubles consécutifs. Une fois que nous avons quitté la phase PlayerRolls, nous ne nous soucions plus des lancers consécutifs.

Un grand nombre de phases peuvent être réutilisées et reliées entre elles. Par exemple, la GamePhase CommunityChestAdvanceToGo créerait la phase suivante PlayerLandsOnGo avec l'état actuel et le retourner. Dans le constructeur de PlayerLandsOnGo le joueur actuel sera déplacé sur Go et son argent sera incrémenté de 200$.

8voto

Stefan Points 7940

Bien sûr, il y a beaucoup, beaucoup, beaucoup, beaucoup, beaucoup, beaucoup, beaucoup de ressources sur ce sujet. Mais je pense que vous êtes sur la bonne voie en divisant les objets et en les laissant gérer leurs propres événements/données et ainsi de suite.

Lorsque vous faites des jeux de plateau basés sur des tuiles, vous trouverez agréable d'avoir des routines pour faire le mappage entre le tableau du plateau et les rangées/colonnes et inversement, ainsi que d'autres fonctionnalités. Je me souviens de mon premier jeu de plateau (il y a très longtemps) où je me suis battu pour savoir comment obtenir row/col à partir de boardarray 5.

1  2  3  
4 (5) 6  BoardArray 5 = row 2, col 2
7  8  9

Nostalgie. ;)

De toute façon, http://www.gamedev.net/ est un bon endroit pour obtenir des informations. http://www.gamedev.net/reference/

5voto

Eric Weilnau Points 1968

La plupart des documents que je peux trouver en ligne sont des listes de références publiées. La section des publications de Modèles de conception de jeux propose des liens vers les versions PDF des articles et des thèses. Beaucoup d'entre eux ressemblent à des documents universitaires comme Modèles de conception pour les jeux . Il existe également au moins un livre disponible sur Amazon, Les modèles de conception de jeux .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X