Gestaltung Von Spiel-Objekte
Ich habe vor kurzem angefangen ein kleines Spiel für mein eigenes Vergnügen, mit Microsoft XNA und C#. Meine Frage ist in Bezug auf die Gestaltung einer Spiel-Objekt und die Objekte, die es übernimmt. Ich werde bestimmen, ein Spiel-Objekt als etwas, das sich auf dem Bildschirm gerendert. Also, für dieses, ich entschied mich für ein Basis-Klasse, die alle anderen Objekte, die gerendert werden müssen, Erben, genannt GameObject. Der untenstehende code ist die Klasse, die ich gemacht:
class GameObject
{
private Model model = null;
private float scale = 1f;
private Vector3 position = Vector3.Zero;
private Vector3 rotation = Vector3.Zero;
private Vector3 velocity = Vector3.Zero;
private bool alive = false;
protected ContentManager content;
#region Constructors
public GameObject(ContentManager content, string modelResource)
{
this.content = content;
model = content.Load<Model>(modelResource);
}
public GameObject(ContentManager content, string modelResource, bool alive)
: this(content, modelResource)
{
this.alive = alive;
}
public GameObject(ContentManager content, string modelResource, bool alive, float scale)
: this(content, modelResource, alive)
{
this.scale = scale;
}
public GameObject(ContentManager content, string modelResource, bool alive, float scale, Vector3 position)
: this(content, modelResource, alive, scale)
{
this.position = position;
}
public GameObject(ContentManager content, string modelResource, bool alive, float scale, Vector3 position, Vector3 rotation)
: this(content, modelResource, alive, scale, position)
{
this.rotation = rotation;
}
public GameObject(ContentManager content, string modelResource, bool alive, float scale, Vector3 position, Vector3 rotation, Vector3 velocity)
: this(content, modelResource, alive, scale, position, rotation)
{
this.velocity = velocity;
}
#endregion
}
Habe ich ausgelassen zusätzliche Methoden, die Dinge tun wie drehen, verschieben, und ziehen Sie das Objekt. Nun, wenn ich wollte zu schaffen ein anderes Objekt, wie ein Schiff, würde ich erstellen Sie eine Schiff-Klasse GameObject Erben würde. Beispiel-code unten:
class Ship : GameObject
{
private int num_missiles = 20; //the number of missiles this ship can have alive at any given time
private Missile[] missiles;
private float max_missile_distance = 3000f; //max distance a missile can be from the ship before it dies
#region Constructors
public Ship(ContentManager content, string modelResource)
: base(content, modelResource)
{
InitShip();
}
public Ship(ContentManager content, string modelResource , bool alive)
: base(content, modelResource, alive)
{
InitShip();
}
public Ship(ContentManager content, string modelResource, bool alive, float scale)
: base(content, modelResource, alive, scale)
{
InitShip();
}
public Ship(ContentManager content, string modelResource, bool alive, float scale, Vector3 position)
: base(content, modelResource, alive, scale, position)
{
InitShip();
}
public Ship(ContentManager content, string modelResource, bool alive, float scale, Vector3 position, Vector3 rotation)
: base(content, modelResource, alive, scale, position, rotation)
{
InitShip();
}
public Ship(ContentManager content, string modelResource, bool alive, float scale, Vector3 position, Vector3 rotation, Vector3 velocity)
: base(content, modelResource, alive, scale, position, rotation, velocity)
{
InitShip();
}
#endregion
}
Wieder, ich habe Links jede zusätzliche Schiff-spezifische Methoden, wie das abfeuern einer Rakete. Glaubst du, dass diese Art von design ist gut oder sollte es sich irgendwie verbessert oder vollkommen verändert? Es scheint, wie die Konstruktoren für Unterklassen, die unordentlich ist, aber vielleicht ist das auch der einzige Weg, es zu tun. Ich habe so etwas noch nie getan und ich wundere mich, wenn ich bin Weg von der Spur.
Danke an alle, die linken eine Antwort. Sie waren alle sehr hilfreich. Es scheint ein allgemeiner Konsens darüber, dass eine änderung es um die Verwendung eines MVC-Muster am besten wäre. Ich werde schauen weiter in, wie genau das zu tun. Ich werde auch das entfernen die meisten der Konstruktoren und genau einen Konstruktor, weil alle Argumente, die nach modelResource sind nicht notwendig, um das Objekt zu erstellen, und Sie können alle geändert werden später durch Methodenaufrufe.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Persönlich finde ich die schiere Anzahl der Konstruktoren, haben Sie ein wenig offputting, aber das ist deine Wahl, nichts grundlegend falsch mit ihm 🙂
Im Hinblick auf die Allgemeine Strategie der Ableitung der Objekte im Spiel aus einer gemeinsamen Basis, das ist ein ziemlich üblicher Weg, um Dinge zu tun. Standard, auch. Ich habe eher beginnen Sie mit etwas, das weit eher an MVC, mit unglaublich leichtes "Modell" Spiel-Objekte enthalten nur Daten.
Andere Allgemeine Ansätze, die ich gesehen habe in XNA include /Dinge möchten Sie vielleicht zu berücksichtigen:
Aber wieder, kleine Punkte. Ihr design ist in Ordnung.
Ist nicht nur die Anzahl der Konstruktoren ein mögliches Problem (vor allem zu re-definieren Sie für jede abgeleitete Klasse) - aber die Anzahl der Parameter an den Konstruktor Problem werden kann. Auch wenn Sie die optionalen Parameter null-Werte zulässt, wird es schwierig zu Lesen und warten des Codes später.
Wenn ich Schreibe:
Was bedeutet die zweite NULL tun?
Es macht den code besser lesbar (aber Ausführlicher), eine Struktur zu verwenden, halten Sie Ihre Parameter, wenn der parameter-Liste geht über vier oder fünf Parameter:
Gibt es eine Menge von Möglichkeiten, dies getan werden kann.
Da sind Sie gefragt, ein design-bezogene Frage, ich werde versuchen, einige Hinweise auf, dass, anstatt auf die viel code, den Sie geschrieben, weil andere bereits begonnen haben, auf, die.
Spiele eignen sich sehr auf die Model-View-Controller-Muster. Sie sind explizit reden über den display-Teil, aber denken Sie daran: Sie haben Vektoren in es, etc., und das ist normalerweise Teil von dem, was Sie sind Modellbildung. Denken Sie an die Spielwelt und die Objekte in es als die Modelle. Sie haben eine position, die Sie möglicherweise haben, Geschwindigkeit und Richtung. Das ist das Modell Teil der MVC.
Bemerkte ich, Ihren Wunsch zu haben, das Schiff Feuer. Sie werden wahrscheinlich wollen die Mechaniker um das Schiff Feuer in einer controller-Klasse, etwas, das dauert Tastatur eingeben, zum Beispiel. Und diese controller-Klasse wird das senden von Nachrichten an das model-Teil. Eine solide und einfach denken, werden Sie wahrscheinlich wollen einige fireAction()-Methode auf das Modell. Auf Ihrer Basis-Modell, das könnte eine überschreibbare (virtuelle, abstrakte) Methode. Auf dem Schiff könnte es eine "Kugel" um die Spiel-Welt.
Sehen, wie ich schrieb über das Verhalten Ihres Modells schon so viel, hier ist eine andere Sache, die mir geholfen hat, viele: verwenden Sie die Strategie-Muster, um das Verhalten von Klassen austauschbar. Die Strategie-Muster ist auch toll, wenn Sie denken, dass AI und möchten Verhalten zu ändern, irgendwann in der Zukunft. Sie möglicherweise nicht wissen es jetzt, aber in einem Monat vielleicht möchten ballistischen Raketen als die Standard-Raketen und können Sie leicht ändern Sie später, wenn Sie verwendet hatten, die Strategie pattenr.
So schließlich möchten Sie vielleicht, um wirklich so etwas wie ein display-Klasse. Es werden Grundelemente, wie du Sie genannt hast: drehen, übersetzen, und so weiter. Und Sie wollen daraus ziehen, um weitere Funktionen hinzuzufügen oder zu ändern Funktionalität. Aber denken Sie daran, sobald Sie mehr als ein Schiff, eine Besondere Art von Schiff, ist eine weitere spezielle Art von Schiff, Sie laufen in Ableitung Hölle und Sie repliziert, die eine Menge code. Wieder, verwenden Sie das Strategie-Muster. Und denken Sie daran, es einfach zu halten. Was macht ein Displayble Klasse haben?
Diesem design nicht trennen, die UI-Teile von einem Objekt und dem Verhalten der Teile eines Objekts, das "model" und "view" sozusagen. Dies ist nicht unbedingt eine schlechte Sache, aber vielleicht finden Sie die folgenden refactorings schwierig, wenn Sie weiterhin mit diesem design:
Aber, wenn Sie sind OK mit diese Nachteile und dieses design macht Sinn für Sie, sehe ich nichts Ungeheuer falsch mit ihm.
Ich bin sehr daran interessiert, Ihre Lagerung Methode für die rotation eines Vektors. Wie funktioniert das?
Wenn Sie speichern den Winkel der X -, Y -, Z-Achse (so genannte Euler-Winkel), sollten Sie überdenken diese Idee, wenn Sie möchten, erstellen Sie ein 3D Spiel, da Sie sich in Kürze treffen, nach Ihrem ersten rendering die bösen GIMBAL LOCK
Ich persönlich mag es nicht so viel Konstruktoren es gibt, wie Sie eine 1-Konstruktor und set-alle nicht benötigten Parameter zu null. auf diese Weise wird Ihre Oberfläche bleibt sauberer.
Ich auch stark empfehlen, sich in eine component based design mit Komposition anstatt Vererbung. Der Kern der Idee ist, zu Modell-Objekt basierend auf Ihre zugrunde liegenden Eigenschaften und die Eigenschaften zu tun all die Arbeit für Sie.
In Ihrem Fall, ein GameObject kann Eigenschaften haben, wie zum Beispiel das bewegen, wird renderable, oder einige Zustand. Diese separaten Funktionen (oder Verhalten) kann modelliert werden als Objekte und komponierte in der GameObject zu erstellen, die die Funktionalität, die Sie wünschen.
Aber ganz ehrlich, für ein kleines Projekt an dem Sie arbeiten, würde ich konzentrieren sich auf das Spiel funktional, anstatt sorgen über die details, wie die Kupplung und Abstraktion.
Je nachdem, wie oft die Konstruktoren aufgerufen werden würde, könnte man erwägen, alle zusätzlichen Parameter, die null-Werte zulässt und nur auf der Durchreise zu null für Sie, wenn Sie keine Werte haben. Messier erstellen der Objekte, weniger Konstruktoren
Ich ging diesen Pfad, wenn die ersten Spiele in XNA, aber das nächste mal würde ich mehr machen, von einem model/view-Konzept. Die Modell-Objekte werden würde, was Sie deal mit in Ihre Update-loop, und deine Ansichten verwendet werden würde in deiner Draw-Schleife.
Bekam ich ärger mit dem trennen nicht das Modell von der Ansicht, wenn ich wollte, um meine sprite-Objekt mit 3D-und 2D-Objekten. Es wurde echte chaotisch ganz schnell.
Die Leute hier reden über die Trennung-Modell aus Sicht korrekt sind. Um es mehr in-game-Entwickler orientierten Bedingungen haben, sollten Sie separate Klassen GameObject und RenderObject. Denken Sie zurück zu Ihrem wichtigsten Spiel-Schleife:
Möchten Sie den Prozess der Aktualisierung Ihrer Spiel-Welt und die Darstellung Ihrer aktuellen Rahmen werden als separate wie möglich.
Alternativ können Sie eine Struktur oder Helfer Klasse zu halten alle Daten und haben die vielen Konstruktoren in der Struktur, so dass Sie nur haben Tonnen Konstruktoren in 1-Objekt, anstatt in jeder Klasse, die erbt von GameObject
Ersten Spiel? Start einfach. Ihre Basis GameObject (die in Ihrem Fall ist mehr angemessen bezeichnet DrawableGameObject [Hinweis: die DrawableGameComponent Klasse in XNA]) sollte nur die Informationen enthalten, die gehört auf alle GameObjects. Ihr lebt-und velocity-Variablen gehören nicht wirklich. Wie andere erwähnt haben, die Sie wahrscheinlich nicht wollen, immer mischen Sie Ihre Zeichnung und update-Logik.
Geschwindigkeit sollte in eine Mobile Klasse, die behandeln soll, die die update-Logik zum ändern der position des GameObject. Möglicherweise möchten Sie auch zu prüfen, zu halten Spur von Beschleunigung und stetig zu erhöhen, wie der Spieler hält eine Taste gedrückt und stetig verringern, nachdem der Spieler löst die Taste (statt eine Konstante Beschleunigung)... aber das ist mehr eine game design Entscheidung, als eine Klasse Organisation, die Entscheidung.
Was "lebendig" bedeutet, kann sehr unterschiedlich sein, basierend auf Kontext. Eine einfache Weltraum-shooter, etwas, das nicht lebt, sollte wohl vernichtet werden (möglicherweise ersetzt, mit ein paar Stücke von Weltraummüll?). Wenn es einen Spieler, respawns, Sie gehen zu wollen, um sicherzustellen, dass die Spieler, getrennt von dem Schiff. Das Schiff nicht respawnen, ist das Schiff zerstört und der Spieler bekommt ein neues Schiff (recycling das alte Schiff in den Speicher anstatt es zu löschen und eine neue erstellen wird weniger Zyklen - Sie können einfach verschieben Sie das Schiff in no-man ' s-land oder ziehen Sie es aus Ihrem Spiel-Szene völlig und steckte es zurück nach respawn).
Andere Sache, die Sie sollten vorsichtig sein... nicht lassen Sie Ihre Spieler direkt nach oben oder unten auf Ihrer vertikalen Achse aus, oder Sie laufen in, als Peter Parker erwähnt, Gimbal Lock-Fehler (die Sie nicht wollen, um Durcheinander mit, wenn Sie die Spiele-Entwicklung für Spaß!). Noch besser... starten Sie mit 2D - (oder zumindest begrenzen die Bewegung auf nur 2 Dimensionen)! Es ist viel einfacher, wenn Sie ' re neu in die Spiele-Entwicklung.
Ich würde vorschlagen, nach dem XNA Creators Club Getting Started Guides, bevor Sie eine weitere Programmierung, jedoch. Sie sollten auch prüfen, Blick für einige andere, allgemeinere game development guides, um ein paar alternative Vorschläge.