Ist es eine schlechte Idee, Game1 statisch in XNA zu haben?

10

Ist es eine wirklich schlechte Idee, meine Game1Klasse als statisch zu haben? Wie im Moment in meiner Game1Klasse habe ich eine Klasse namens, TileHandlerdie alles behandelt, was mit meinem aktuellen Kachelsatz zu tun hat, und AnimalHandlerdie (überraschenderweise) alle meine Tiere behandelt.

Wenn ich jetzt drin bin AnimalHandlerund überprüfen möchte, ob eine Kachel begehbar TileHandlerist, verursacht dies Probleme, oder ich muss eine Liste begehbarer Kacheln übergeben AnimalHandler, was ich lieber nicht tun würde.

Was einfacher wäre, wäre Game1statisch zu machen und dann AnimalHandlereinfach loszulegen Game1._tileHandler.WalkableTile(position).

Jetzt kann ich nichts sofort Falsches daran sehen oder irgendetwas, das Probleme verursachen würde, aber ich habe gerade erst angefangen, statische Klassen zu verwenden. Sieht jemand, der besser informiert ist, einen riesigen Grund, warum das eine schlechte Idee ist?

Harold
quelle

Antworten:

9

Jetzt kann ich nichts sofort Falsches daran sehen oder irgendetwas, das Probleme verursachen würde, aber ich habe gerade erst angefangen, statische Klassen zu verwenden. Sieht jemand, der besser informiert ist, einen riesigen Grund, warum das eine schlechte Idee ist?

Wenn Sie einen glänzenden neuen Hammer haben, sieht jedes Problem wie ein Nagel aus.

Im Allgemeinen ist an statischen Klassen und / oder Methoden nichts auszusetzen, wenn sie ordnungsgemäß verwendet werden (für Dinge, die keinen Status pro Instanz haben oder davon abhängen). In Ihrem Fall missbrauchen Sie sie jedoch, um eine Abhängigkeit von der einzelnen Instanz auszublenden , und verwechseln dies mit dem Entfernen der Abhängigkeit. Es scheint auch, dass Sie Implementierungsdetails der Game1Klasse verfügbar machen, was im Allgemeinen ebenfalls schlecht ist.

Hier ist der Kern Ihres Problems:

... wenn ich drin bin AnimalHandlerund überprüfen möchte, ob eine Kachel von TileHandlerda an begehbar ist, verursacht dies Probleme oder ich muss eine Liste von begehbaren Kacheln übergeben AnimalHandler, was ich lieber nicht tun würde.

Das Ignorieren der Möglichkeit, dass das AnimalHandlerBenötigen dieser Kacheln selbst ein schlechtes Design sein kann (mit den von Ihnen gewählten Namen ist es schwierig, die Details dieser Klassen zu sagen), für den Moment ... Wenn Sie AnimalHandlereine Liste begehbarer Kacheln benötigen, benötigen Sie eine Liste von begehbare Fliesen. Im Allgemeinen ist es besser, Abhängigkeiten expliziter als weniger zu machen , da Code dadurch selbstdokumentierender wird. Indem Sie die Liste direkt an übergeben AnimalHandler, weisen Sie ausdrücklich darauf hin, dass eine solche Liste erforderlich ist. Wenn Sie stattdessen alles statisch und öffentlich machen, damit Sie einfach auf die statische Liste zugreifen können, die an anderer Stelle im Code enthalten ist , müssen Sie die Abhängigkeit nur ausblenden, ohne sie tatsächlich zu lösen oder zu entfernen.

Für ein kleines Spiel, das nicht skaliert werden muss, ist dies per se kein Problem, aber es kann Sie auf den Weg einer schlechten Angewohnheit führen, sodass Sie in Betracht ziehen sollten, dies nicht zu tun. Denken Sie zumindest beim nächsten Projekt daran, an dem Sie arbeiten.


quelle
Amen! Sie berühren einen großartigen Punkt, über den ich in meiner Antwort nicht wirklich gesprochen habe.
Nate
+1 Abhängigkeiten verstecken und globalen Zustand einführen ist hier wirklich das Problem
Asche999
4

Der Grund dafür, dass das Aufrufen von TileHandler in einem statischen Kontext nicht das bestmögliche Design ist, besteht darin, dass Komponenten Ihres Designs gekoppelt werden, die andernfalls entkoppelt werden könnten.

Wenn Sie sich in Zukunft für mehr als einen TileHandler entscheiden, müssen Sie viel Arbeit leisten, um diese Änderung zu berücksichtigen.

Wenn Sie TileHandler entfernen möchten, müssen Sie viel Arbeit leisten, um diese Änderung zu berücksichtigen.

Angenommen, Sie erstellen in Zukunft eine andere Ebene / Zone, die Kacheln anders behandelt als Ihr aktueller TileHandler. Dann müssen Sie entweder eine Möglichkeit haben, die zu verwendende Tilehandling-Methode anzugeben, oder Sie müssen einen anderen Handler aufrufen.

Wenn der TileHandler als Parameter an Objekte übergeben wurde, die ihn verwenden, können Sie beim nächsten Mal einfach einen anderen übergeben oder einen anderen Kachelhandler für Objekte festlegen, die ihn später verwenden.

Persönlich greife ich in einem statischen Kontext auf viele Dinge in meinen XNA-Spielen zu und gehe davon aus, dass ich nie mehr als eines davon haben werde.

Wenn Sie Ihren Game-Engine-Code in Ihrem nächsten Spiel wiederverwenden möchten, müssen Sie wahrscheinlich einen Großteil der Dinge, die Sie derzeit als statisch geschrieben haben, neu schreiben.

Zusamenfassend:

Um keinen statischen Kontext zu verwenden:

Wenn Sie Objekte so weit wie möglich als Parameter übergeben, werden Spielelemente entkoppelt und Sie können sie einfacher für aktuelle oder zukünftige Projekte ändern / wiederverwenden. Außerdem können Sie die Komplexität großer Codemengen etwas einfacher verwalten (denken Sie an Hunderte statischer Manager in Ihrer Spielklasse, in einem großen Spiel).

Für den statischen Kontext:

Das Deklarieren und Zugreifen auf Objekte aus einem statischen Kontext erleichtert das Schreiben kleiner Spiele, für die nicht Hunderte von statischen Managern erforderlich sind. Vereinfacht viele Methoden und Konstruktoren, indem kein oder mehrere zusätzliche Parameter erforderlich sind, auf die stattdessen statisch zugegriffen wird.

Olhovsky
quelle
2

Ich denke nicht, dass es eine super schlechte Idee für ein einfaches Spiel ist, aber Sie könnten auch einen Blick auf http://www.nuclex.org/articles/4-architecture/6-game-components-and-game-services für werfen Eine bessere Idee, wie man miteinander kommunizierende Spielkomponenten erstellt

smnbss
quelle
Könnten Sie sich Probleme vorstellen, wenn es nicht nur ein einfaches Spiel wäre?
Harold
Lesbarkeit, Testbarkeit und gute Architekturpraktiken des Codes sollten dies vermeiden.
smnbss
2

Dinge wie TileHandler und AnimalHandler würde ich einem Spielbildschirm ein höheres Level hinzufügen. Benötigt Ihr Titelbildschirm Zugriff auf den TileHandler und wird er beim ersten Laden des Spiels initialisiert? Wahrscheinlich nicht.

Schauen Sie sich das XNA State Management-Beispiel an . Es enthält viel Code, aber im Grunde initialisiert das Basisspiel nur einen Stapel von Spielzuständen (oder Bildschirmen). Jeder Bildschirm ist ziemlich unabhängig von den anderen und wird als vereinfachte Version des Spiels ausgeführt. Ihr PlayScreen kann statische Elemente haben, sodass PlayScreen-Komponenten darauf zugreifen können.

Im Basisspiel verwende ich einige statische Elemente, aber es handelt sich um sehr einfache Dinge wie InputHelper-, Log- oder Config-Reader. Sie sind in allen Spielen Standard, sodass die Basis-Engine schnell und einfach portiert werden kann. Auf den Bildschirmen findet die eigentliche Spielelogik statt. So lange Antwort kurz - nein, ich denke, es ist theoretisch keine schlechte Idee, sei einfach vorsichtig, was du statisch machst. Sobald Sie fortfahren und etwas Statisches machen, ist es eine enorme Menge an Arbeit, wenn Sie Ihre Meinung ändern.

Nachsicht
quelle
0

Die hier angesprochenen Punkte sind alle gut. Nach meiner Erfahrung (die zugegebenermaßen mehr auf Geschäftsanwendungen als auf Spiele ausgerichtet ist) gibt es großartige Verwendungsmöglichkeiten für statische Klassen und Mitglieder, und ich habe sie oft verwendet. Ich habe festgestellt, dass ich mit zunehmenden Anforderungen und zunehmender Komplexität diese statischen Klassen recycle und in Instanzklassen konvertiere und sie weitergebe.

Der Punkt, den ich ansprechen möchte, ist, dass, wenn die Verwendung einer statischen Klasse Ihnen hilft, dieses Spiel herauszubringen, Sie es versuchen, aber dennoch die richtigen Dinge tun: Implementieren Sie eine Schnittstelle oder Basisklasse, damit es einfacher ist, sie herauszureißen und zu konvertieren es später zu einer Instanzklasse.

Eine Unze Vorbeugung ist ein Pfund Heilung wert. Stellen Sie also sicher, dass Ihre statische Klasse Sie nicht festhält, was es schwierig macht, sie zu ändern. Es ist ziemlich einfach, eine Methode mithilfe einer statischen Klasse umzugestalten, die eine Schnittstelle implementiert, sodass sie einen neuen Schnittstellenparameter akzeptiert und diese Schnittstelle anstelle der statischen Klassenreferenz verwendet.

Nate
quelle
0

Ja, das ist im Allgemeinen immer eine schlechte Idee.

Wenn Objekte mit sich ändernden Daten (dh alles andere als schreibgeschützte Konstanten und Nachschlagetabellen) in statische Klassen umgewandelt werden, ist ein gutes Design ein Muss.

  1. Es fördert zufällige Abhängigkeiten, die die Modularität zunichte machen und der Wiederverwendung von Code im Wege stehen. Angenommen, Sie wollten einen Editor für Ihr Spiel schreiben - plötzlich würden viele Klassen nach einem schreien Game1, den Sie nicht einfach in eine gemeinsam genutzte Bibliothek verschieben können.

  2. Ihr Code wird nicht mehr testbar. Unit-Tests isolieren einzelne Klassen vom Rest, indem sie ihre Abhängigkeiten verspotten oder simulieren (was so gering wie möglich gehalten werden sollte). Jede statische Klasse ist eine Haftung, da jederzeit auf sie zugegriffen werden kann, der Status über mehrere Tests übertragen wird oder initialisiert werden muss, bevor die Tests erfolgreich sein können.

  3. Es verbirgt Abhängigkeiten. Ähnlich wie beim Anti-Pattern des Dienstanbieters (auch von XNA, Game.Services verwendet) können Ihre Klassen Abhängigkeiten auswählen, die Sie äußerlich nicht sehen.

Dieser Ansatz wird besonders giftig, wenn man statische Klassen mit Güterzuganrufen kombiniert (Dinge wie Game.Instance.ActorManager.Enemies.FindInRange(10)- wegen der zugwagenähnlichen verketteten Symbole so genannt), bei denen Komponenten plötzlich nicht nur eine GameKlasse benötigen , sondern eine mit einer statischen InstanceEigenschaft, die etwas zurückgibt Eine ActorManagerEigenschaft mit einer EnemiesEigenschaft, die ein Objekt mit einer FindInRange()Methode zurückgibt .

Die einzige Entschuldigung, die ich akzeptieren würde, um veränderbare statische Klassen zu schreiben, wäre, dass man noch lernt und noch nicht in der Lage ist, konsequent gutes Design und ein geschultes Auge für das Erkennen von schlechten Entscheidungen anzuwenden.

Cygon
quelle