Erstellen Sie ein verhaltens- / komponentenbasiertes System für Spiele

11

Hintergrund

Ich mache Spieleentwicklung als Hobby und suche nach einer besseren Möglichkeit, sie zu entwerfen. Derzeit verwende ich einen Standard-OOP-Ansatz (ich mache seit 8 Jahren Unternehmensentwicklung, daher erfolgt dies nicht mehr). Nehmen Sie zum Beispiel einen "Bösewicht"

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
}

Das Problem

Nehmen wir an, ich mache einen 2D-Plattformer und brauche den Bösewicht, um springen zu können. Normalerweise füge ich den entsprechenden Code in die Update / GetInput-Methoden ein. Wenn ich dann den Spieler kriechen, ducken, klettern lassen muss, wird der Code dorthin gehen.

Wenn ich nicht aufpasse, werden diese Methoden unübersichtlich, sodass ich am Ende Methodenpaare wie dieses erstelle

CheckForJumpAction(Input input) und DoJump()

CheckforDuckAction(Input input) und DoDuck()

GetInput sieht also so aus

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

und Update sieht aus wie

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

Wenn ich ein anderes Spiel erstelle , in dem der Spieler springen und sich ducken muss, gehe ich normalerweise in ein Spiel mit der Funktionalität und kopiere es. Chaotisch, ich weiß. Deshalb suche ich etwas Besseres.

Lösung?

Ich mag es wirklich, wie Blend Verhaltensweisen hat, die ich an ein Element anhängen kann. Ich habe darüber nachgedacht, dasselbe Konzept in meinen Spielen zu verwenden. Schauen wir uns also dieselben Beispiele an.

Ich würde ein Basis-Verhaltensobjekt erstellen

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

Und damit kann ich Verhaltensweisen erzeugen. JumpBehavior:BehaviorundDuckBehavior:Behavior

Ich kann dann der Sprite-Basis eine Sammlung von Verhaltensweisen hinzufügen und jeder Entität hinzufügen, was ich brauche.

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
    }
}

Wenn ich jetzt Jump and Duck in vielen Spielen verwenden wollte, kann ich das Verhalten einfach überdenken. Ich könnte sogar eine Bibliothek für die üblichen machen.

Funktioniert es?

Was ich nicht herausfinden kann, ist, wie man den Zustand zwischen ihnen teilt. Bei Jump und Duck wirken sich beide nicht nur auf den aktuellen Teil der gezeichneten Textur aus, sondern auch auf den Status des Spielers. (Der Sprung wird mit der Zeit eine abnehmende Menge an Aufwärtskraft aufbringen, während die Ente nur die Bewegung stoppt, die Textur und die Kollisionsgröße des Bösewichts ändert.

Wie kann ich das zusammenbinden, damit es funktioniert? Soll ich Abhängigkeitseigenschaften zwischen den Verhaltensweisen erstellen? Sollte ich jedes Verhalten über das Elternteil wissen lassen und es direkt ändern? Eine Sache, die ich dachte, war, einen Delegaten in jedes Verhalten zu übergeben, um ausgeführt zu werden, wenn es ausgelöst wird.

Ich bin mir sicher, dass es weitere Probleme gibt, über die ich nachdenke, aber der gesamte Zweck besteht darin, dass ich diese Verhaltensweisen zwischen Spielen und Entitäten im selben Spiel problemlos wiederverwenden kann.

Also übergebe ich es dir. Möchten Sie erklären, wie / ob dies möglich ist? Hast du eine bessere Idee? Ich bin ganz Ohr.


quelle
Dies könnte besser unter gamedev.stackexchange.com gefragt werden ?
rcapote
Ich mag es, wohin Sie gehen, aber ich bin mir nicht sicher, wie ich die von Ihnen angesprochenen Probleme angehen soll. Sehr interessant und hat Auswirkungen über die Spieleentwicklung hinaus.
Edward Strange
@rcapote ist diese Seite nicht für Whiteboarding / Diskussionen?
2
@ Joe - nein, nein. Erwähne hier nicht einmal "Diskussion", sonst wirst du aus der Existenz gerissen. Diese Seite ist nur für Frage-> Antwort-> Fertig Art der Interaktion.
Edward Strange
Nun, komponentenbasierte Entitätssysteme sind in letzter Zeit ein Trend in der Spieleentwickler-Community, daher dachte ich, dass Sie dort möglicherweise bessere Aufmerksamkeit erhalten, aber hier werden Sie wahrscheinlich trotzdem gute Antworten erhalten. Hier ist eine interessante Diskussion über gamedev.net über dieses Problem , dass Sie interessant finden könnte: gamedev.net/topic/...
rcapote

Antworten:

1

Schauen Sie sich diese Präsentation an. Klingt ziemlich nah an dem Muster, nach dem Sie suchen. Dieses Muster unterstützt Verhaltensweisen und anhängbare Eigenschaften. Ich glaube nicht, dass die Präsentation dies erwähnt, aber Sie können auch anhängbare Ereignisse erstellen. Diese Idee ähnelt den in WPF verwendeten Abhängigkeitseigenschaften.

Nieldy
quelle
9

Für mich klingt dies wie ein fast lehrbuchartiger Fall für die Verwendung des Strategiemusters . In diesem Muster können Ihre generischen Verhaltensweisen in Schnittstellen definiert werden, mit denen Sie verschiedene Implementierungen von Verhaltensweisen zur Laufzeit austauschen können (denken Sie darüber nach, wie sich ein Power-Up auf die Sprung- oder Lauffähigkeit Ihres Charakters auswirken kann).

Für (ein erfundenes) Beispiel:

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

Jetzt können Sie verschiedene Arten von Sprüngen implementieren, die Ihr Charakter verwenden kann, ohne unbedingt die Details zu den einzelnen Sprüngen zu kennen:

// 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!");
     }
}

Alle Charaktere, die Sie springen möchten, können gerade einen Verweis auf ein IJumpable enthalten und Ihre verschiedenen Implementierungen verbrauchen

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;
    }

}

Dann kann Ihr Code ungefähr so ​​aussehen:

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();

Jetzt können Sie diese Verhaltensweisen problemlos wiederverwenden oder später sogar erweitern, wenn Sie weitere Arten von Sprüngen hinzufügen oder mehr Spiele erstellen möchten, die auf einer einzigen Side-Scrolling-Plattform basieren.

mclark1129
quelle
Das ist zwar nicht genau das, wonach ich suche, aber es ist sehr nah und gefällt mir. Ich werde damit herumspielen, um sicherzugehen. Vielen Dank!
1

Werfen Sie einen Blick auf die DCI-Architektur und sehen Sie sich die OO-Programmierung an, die möglicherweise hilfreich ist.

Das Implementieren einer Architektur im DCI-Stil in C # erfordert die Verwendung einfacher Domänenklassen und die Verwendung von Kontextobjekten (Verhalten) mit Erweiterungsmethoden und -schnittstellen, damit die Domänenklassen unter verschiedenen Rollen zusammenarbeiten können. Die Schnittstellen werden verwendet, um die für ein Szenario erforderlichen Rollen zu markieren. Domänenklassen implementieren die Schnittstellen (Rollen), die für das beabsichtigte Verhalten gelten. Die Zusammenarbeit zwischen den Rollen erfolgt in den Kontext- (Verhaltens-) Objekten.

Sie können eine Bibliothek mit allgemeinen Verhaltensweisen und Rollen erstellen, die von Domänenobjekten aus separaten Projekten gemeinsam genutzt werden können.

Siehe DCI in C # für Codebeispiele in C #.

Ed James
quelle
0

Was ist mit der Übergabe eines Kontextobjekts an ein Verhalten, das Methoden zum Ändern des Status der von einem Verhalten betroffenen Sprites / Objekte bereitstellt? Wenn ein Objekt mehrere Verhaltensweisen aufweist, werden sie jeweils in einer Schleife aufgerufen, sodass sie den Kontext ändern können. Wenn eine bestimmte Änderung einer Eigenschaft die Änderung anderer Eigenschaften ausschließt / einschränkt, kann das Kontextobjekt Methoden zum Setzen von Flags bereitstellen, um diese Tatsache anzuzeigen, oder es kann einfach unerwünschte Änderungen ablehnen.

Jonny Dee
quelle