Créer un système basé sur les comportements / composants pour les jeux

11

Contexte

Je fais du développement de jeux comme passe-temps et je cherche une meilleure façon de les concevoir. Actuellement, j'utilise une approche POO standard (je fais du développement d'entreprise depuis 8 ans donc ça vient de façon non-systématique). Prenons par exemple un "méchant"

public class Baddie:AnimatedSprite //(or StaticSprite if needed, which inherit Sprite)
{
    //sprite base will have things like what texture to use, 
    //what the current position is, the base Update/Draw/GetInput methods, etc..
    //an AnimatedSprite contains helpers to animated the player while 
    //a StaticSprite is just one that will draw whatever texture is there
}

Le problème

Disons que je fais un jeu de plateforme 2D et que j'ai besoin du méchant pour pouvoir sauter. Habituellement, ce que je fais est d'ajouter le code approprié dans les méthodes Update / GetInput. Ensuite, si j'ai besoin de faire ramper, canarder, grimper, etc ... le code y ira.

Si je ne fais pas attention, ces méthodes sont encombrées, donc je finis par créer des paires de méthodes comme celle-ci

CheckForJumpAction(Input input) et DoJump()

CheckforDuckAction(Input input) et DoDuck()

donc GetInput ressemble

public void DoInput(Input input)
{
    CheckForJumpAction(input);
    CheckForDuckAction(input);
}

et la mise à jour ressemble

public void Update()
{
    DoJump();
    DoDuck();
}

Si je vais créer un autre jeu où le joueur doit sauter et esquiver, je vais généralement dans un jeu qui a la fonctionnalité et je le copie. Messy, je sais. C'est pourquoi je recherche quelque chose de mieux.

Solution?

J'aime vraiment comment Blend a des comportements que je peux attacher à un élément. J'ai pensé à utiliser le même concept dans mes jeux. Regardons donc les mêmes exemples.

Je créerais un objet de comportement de base

public class Behavior
{
    public void Update()
    Public void GetInput()
}

Et je peux créer des comportements en utilisant ça. JumpBehavior:BehavioretDuckBehavior:Behavior

Je peux ensuite ajouter une collection de comportements à la base Sprite et ajouter ce dont j'ai besoin à chaque entité.

public class Baddie:AnimatedSprite
{
    public Baddie()
    {
        this.behaviors = new Behavior[2];
        this.behaviors[0] = new JumpBehavior();
        //etc...
    }

    public void Update()
    {
        //behaviors.update
    }

    public GetInput()
    {
        //behaviors.getinput
    }
}

Alors maintenant, si je voulais utiliser Jump and Duck dans de nombreux jeux, je peux simplement apporter les comportements. Je pourrais même faire une bibliothèque pour les plus communes.

Est-ce que ça marche?

Ce que je ne peux pas comprendre, c'est comment partager l'état entre eux. En regardant Jump et Duck, les deux affectent non seulement la partie actuelle de la texture en cours de dessin, mais aussi l'état du joueur. (Le saut va appliquer une quantité décroissante de force ascendante au fil du temps, tandis que le canard va simplement arrêter le mouvement, changer la texture et la taille de la collision du méchant.

Comment puis-je lier cela ensemble pour que cela fonctionne? Dois-je créer des propriétés de dépendance entre les comportements? Dois-je faire connaître chaque comportement au parent et le modifier directement? Une chose que je pensais était de pouvoir passer un délégué dans chaque comportement pour être exécuté lorsqu'il est déclenché.

Je suis sûr qu'il y a plus de problèmes que je regarde, mais le but est que je puisse facilement réutiliser ces comportements entre les jeux et les entités dans le même jeu.

Je vous cède donc la parole. Voulez-vous expliquer comment / si cela peut être fait? As-tu une meilleure idée? Je suis tout ouïe.


la source
Cela pourrait être mieux demandé à gamedev.stackexchange.com ?
rcapote
J'aime bien où vous allez, mais je ne sais pas comment résoudre les problèmes que vous soulevez. Très intéressant et a des implications au-delà du développement de jeux.
Edward Strange
@rcapote n'est pas ce site pour le tableau blanc / discussions?
2
@Joe - non, non. Ne mentionnez même pas "discussion" ici ou vous serez mis hors de vie. Ce site est uniquement pour le type d'interaction Question-> Réponse-> Terminé.
Edward Strange
Eh bien, les systèmes d'entités basés sur les composants sont quelque chose qui a commencé à faire ses preuves dans la communauté des développeurs de jeux récemment, alors je me suis dit que vous pourriez y attirer davantage d'attention, mais vous obtiendrez probablement de bonnes réponses ici de toute façon. Voici une discussion intéressante sur gamedev.net à propos de ce problème qui pourrait vous intéresser: gamedev.net/topic/…
rcapote

Réponses:

1

Jetez un œil à cette présentation. Cela semble assez proche du type de motif que vous recherchez. Ce modèle prend en charge les comportements et les propriétés attachables. Je ne pense pas que la présentation le mentionne, mais vous pouvez également créer des événements attachables. Cette idée est similaire aux propriétés de dépendance utilisées dans WPF.

Nieldy
la source
9

Pour moi, cela ressemble à un cas presque manuel pour l'utilisation du modèle de stratégie . Dans ce modèle, vos comportements génériques peuvent être définis dans des interfaces qui vous permettront d'échanger différentes implémentations de comportements lors de l'exécution (pensez à la façon dont une mise sous tension peut affecter la capacité de saut ou de course de votre personnage).

Pour un exemple (artificiel):

// The basic definition of the jump behavior
public interface IJumpBehavior {
    void Jump();
}

Maintenant, vous pouvez implémenter différents types de sauts que votre personnage peut utiliser, sans nécessairement connaître les détails de chaque saut spécifique:

// This is the jump the character may have when first starting
public class NormalJump : IJumpBehavior {

     public void Jump() {
         Console.WriteLine("I am jumping, and being pretty boring about it!");
     }

}

// This is the jump of a character who has consumed a power-up
public class SuperJump : IJumpBehavior {
    public void Jump() { 
         Console.WriteLine("I am all hopped up on star power, now my jumps can do damage!");
     }
}

Tous les caractères que vous souhaitez avoir la capacité de sauter peuvent contenir une référence à un IJumpable et peuvent commencer à consommer vos différentes implémentations

public class HeroCharacter {

    // By default this hero can perform normal jump.
    private IJumpBehavior _jumpBehavior = new NormalJump();

    public void Jump() {
        _jumpBehvaior.Jump();
    }

    // If you want to change the hero's IJumpable at runtime
    public void SetJump(IJumpBehavior jumpBehavior) {
      _jumpBehavior = jumpBehavior;
    }

}

Ensuite, votre code peut ressembler à quelque chose comme:

HeroCharacter myHero = new HeroCharacer();

// Outputs: "I am jumping, and being pretty boring about it!"
myHero.Jump()

// After consuming a power-up
myHero.SetJump(new SuperJump());

// Outputs: "I am all hopped up on star power, now my jumps can do damage!"
myHero.Jump();

Maintenant, vous pouvez facilement réutiliser ces comportements, ou même les étendre plus tard si vous souhaitez ajouter plus de types de sauts, ou créer plus de jeux construits sur une seule plateforme à défilement horizontal.

mclark1129
la source
bien que ce ne soit pas exactement ce que je recherche, c'est très proche et ça me plaît. Je vais jouer avec pour m'en assurer. Merci!
1

Jetez un œil à l' architecture DCI, une approche intéressante de la programmation OO qui peut vous aider.

L'implémentation d'une architecture de style DCI en C # nécessite l'utilisation de classes de domaine simples et l'utilisation d'objets de contexte (comportements) avec des méthodes d'extension et des interfaces pour permettre aux classes de domaine de collaborer sous différents rôles. Les interfaces sont utilisées pour marquer les rôles requis pour un scénario. Les classes de domaine implémentent les interfaces (rôles) qui s'appliquent à leur comportement prévu. La collaboration entre les rôles a lieu dans les objets de contexte (comportement).

Vous pouvez créer une bibliothèque de comportements et de rôles communs qui peuvent être partagés entre les objets de domaine à partir de projets distincts.

Voir DCI en C # pour des exemples de code en C #.

Ed James
la source
0

Qu'en est-il de passer dans un objet de contexte dans un comportement qui fournit des méthodes pour changer l'état des sprites / objets affectés par un comportement? Maintenant, si un objet a plusieurs comportements, ils sont chacun appelés en boucle, ce qui leur donne la possibilité de changer le contexte. Si une certaine modification d'une propriété exclut / contraint la modification d'autres propriétés, l'objet contextuel peut fournir des méthodes pour définir une sorte d'indicateur pour indiquer ce fait, ou il peut simplement refuser des modifications indésirables.

Jonny Dee
la source