Ich mache ein Spiel, das mit dem Entity-Component-Paradigma entworfen wurde und Systeme verwendet, um zwischen Komponenten zu kommunizieren, wie hier erläutert . Ich habe den Punkt in meiner Entwicklung erreicht, an dem ich Spielzustände hinzufügen muss (z. B. Pause, Spielen, Levelstart, Rundenstart, Spielende usw.), bin mir aber nicht sicher, wie ich das mit meinem Framework machen soll. Ich habe mir dieses Codebeispiel für Spielzustände angesehen, auf die sich jeder zu beziehen scheint, aber ich denke nicht, dass es zu meinem Framework passt. Es scheint, dass jeder Staat seine eigene Zeichnung und Aktualisierung handhabt. Mein Framework verfügt über einen SystemManager, der alle Aktualisierungen mithilfe von Systemen übernimmt. Hier ist zum Beispiel meine RenderingSystem-Klasse:
public class RenderingSystem extends GameSystem {
private GameView gameView_;
/**
* Constructor
* Creates a new RenderingSystem.
* @param gameManager The game manager. Used to get the game components.
*/
public RenderingSystem(GameManager gameManager) {
super(gameManager);
}
/**
* Method: registerGameView
* Registers gameView into the RenderingSystem.
* @param gameView The game view registered.
*/
public void registerGameView(GameView gameView) {
gameView_ = gameView;
}
/**
* Method: triggerRender
* Adds a repaint call to the event queue for the dirty rectangle.
*/
public void triggerRender() {
Rectangle dirtyRect = new Rectangle();
for (GameObject object : getRenderableObjects()) {
GraphicsComponent graphicsComponent =
object.getComponent(GraphicsComponent.class);
dirtyRect.add(graphicsComponent.getDirtyRect());
}
gameView_.repaint(dirtyRect);
}
/**
* Method: renderGameView
* Renders the game objects onto the game view.
* @param g The graphics object that draws the game objects.
*/
public void renderGameView(Graphics g) {
for (GameObject object : getRenderableObjects()) {
GraphicsComponent graphicsComponent =
object.getComponent(GraphicsComponent.class);
if (!graphicsComponent.isVisible()) continue;
GraphicsComponent.Shape shape = graphicsComponent.getShape();
BoundsComponent boundsComponent =
object.getComponent(BoundsComponent.class);
Rectangle bounds = boundsComponent.getBounds();
g.setColor(graphicsComponent.getColor());
if (shape == GraphicsComponent.Shape.RECTANGULAR) {
g.fill3DRect(bounds.x, bounds.y, bounds.width, bounds.height,
true);
} else if (shape == GraphicsComponent.Shape.CIRCULAR) {
g.fillOval(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
}
/**
* Method: getRenderableObjects
* @return The renderable game objects.
*/
private HashSet<GameObject> getRenderableObjects() {
return gameManager.getGameObjectManager().getRelevantObjects(
getClass());
}
}
Außerdem sind alle Aktualisierungen in meinem Spiel ereignisgesteuert. Ich habe keine Schleife wie die ihre, die einfach alles gleichzeitig aktualisiert.
Ich mag mein Framework, weil es das Hinzufügen neuer GameObjects erleichtert, aber nicht die Probleme hat, auf die einige komponentenbasierte Designs bei der Kommunikation zwischen Komponenten stoßen. Ich würde es hassen, es zu schmeißen, nur um eine Pause zur Arbeit zu bekommen. Gibt es eine Möglichkeit, meinem Spiel Spielzustände hinzuzufügen, ohne das Design der Entitätskomponenten zu entfernen? Passt das Spielstatusbeispiel tatsächlich zu meinem Framework und mir fehlt nur etwas?
EDIT: Ich habe mein Framework möglicherweise nicht gut genug erklärt. Meine Komponenten sind nur Daten. Wenn ich in C ++ codieren würde, wären sie wahrscheinlich Strukturen. Hier ist ein Beispiel von einem:
public class BoundsComponent implements GameComponent {
/**
* The position of the game object.
*/
private Point pos_;
/**
* The size of the game object.
*/
private Dimension size_;
/**
* Constructor
* Creates a new BoundsComponent for a game object with initial position
* initialPos and initial size initialSize. The position and size combine
* to make up the bounds.
* @param initialPos The initial position of the game object.
* @param initialSize The initial size of the game object.
*/
public BoundsComponent(Point initialPos, Dimension initialSize) {
pos_ = initialPos;
size_ = initialSize;
}
/**
* Method: getBounds
* @return The bounds of the game object.
*/
public Rectangle getBounds() {
return new Rectangle(pos_, size_);
}
/**
* Method: setPos
* Sets the position of the game object to newPos.
* @param newPos The value to which the position of the game object is
* set.
*/
public void setPos(Point newPos) {
pos_ = newPos;
}
}
Meine Komponenten kommunizieren nicht miteinander. Systeme übernehmen die Kommunikation zwischen Komponenten. Meine Systeme kommunizieren auch nicht miteinander. Sie haben separate Funktionen und können leicht getrennt gehalten werden. Das MovementSystem muss nicht wissen, was das RenderingSystem rendert, um die Spielobjekte korrekt zu verschieben. Es müssen nur die richtigen Werte für die Komponenten festgelegt werden, damit das RenderingSystem beim Rendern der Spielobjekte genaue Daten enthält.
Der Spielstatus kann kein System sein, da er eher mit den Systemen als mit den Komponenten interagieren muss. Es werden keine Daten festgelegt. Es bestimmt, welche Funktionen aufgerufen werden müssen.
Eine GameStateComponent wäre nicht sinnvoll, da alle Spielobjekte einen Spielstatus gemeinsam haben. Komponenten bilden Objekte und jedes ist für jedes Objekt anders. Beispielsweise können die Spielobjekte nicht dieselben Grenzen haben. Sie können überlappende Grenzen haben, aber wenn sie eine BoundsComponent gemeinsam nutzen, sind sie wirklich dasselbe Objekt. Hoffentlich macht diese Erklärung meinen Rahmen weniger verwirrend.
Status ist ein Wert, der für ein Objekt gilt. Der Spielstatus ist, wie der Name schon sagt, der Status eines "Spiel" -Objekts. Dieses Spielobjekt - oder wahrscheinlicher eine bestimmte Komponente darauf - würde den aktuellen Status verfolgen und alle Objekte erstellen oder zerstören, die zur Erleichterung des aktuellen Status erforderlich sind. Da es sich bei Ihren Komponenten nur um Daten handelt, benötigen Sie ein neues System, um dies zu handhaben, auch wenn möglicherweise immer nur eine Instanz der zugehörigen Komponente vorhanden ist.
Es ist schwer zu kommentieren, wie Sie eine Pause implementieren würden, wenn nicht klar ist, wie Sie die Aktualisierung implementieren. Der Prozess, der Aktualisierungsereignisse ausgibt, kann sich dafür entscheiden, dies nicht zu tun, wenn das Spielobjekt angibt, dass das Spiel angehalten wurde. Wie das Spielobjekt mit dem Aktualisierungsprozess kommuniziert, liegt bei Ihnen. Vielleicht sollte Ihr
getRelevantObjects
Anruf dem Updater ermöglichen, das Spielobjekt zu finden, oder umgekehrt.quelle