Estou criando um jogo projetado com o paradigma de entidade-componente que usa sistemas para se comunicar entre componentes, conforme explicado aqui . Cheguei ao ponto do meu desenvolvimento em que preciso adicionar estados de jogo (como pausa, execução, início de nível, início da rodada, final do jogo etc.), mas não tenho certeza de como fazê-lo com minha estrutura. Eu olhei para este exemplo de código nos estados dos jogos aos quais todos parecem fazer referência, mas não acho que isso se encaixa na minha estrutura. Parece que cada estado lida com seu próprio desenho e atualização. Minha estrutura possui um SystemManager que lida com toda a atualização usando sistemas. Por exemplo, aqui está minha classe RenderingSystem:
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());
}
}
Além disso, toda a atualização no meu jogo é orientada a eventos. Eu não tenho um loop como o deles que simplesmente atualiza tudo ao mesmo tempo.
Gosto da minha estrutura porque facilita a adição de novos GameObjects, mas não apresenta os problemas encontrados por alguns designs baseados em componentes ao se comunicar entre componentes. Eu odiaria jogá-lo apenas para fazer uma pausa no trabalho. Existe uma maneira de adicionar estados de jogo ao meu jogo sem remover o design do componente da entidade? O exemplo do estado do jogo realmente se encaixa na minha estrutura, e só estou perdendo alguma coisa?
Edição: Eu não poderia ter explicado o meu quadro o suficiente. Meus componentes são apenas dados. Se eu estivesse codificando em C ++, provavelmente seriam estruturas. Aqui está um exemplo de um:
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;
}
}
Meus componentes não se comunicam. Os sistemas lidam com a comunicação entre componentes. Meus sistemas também não se comunicam. Eles têm funcionalidade separada e podem ser facilmente mantidos separados. O MovementSystem não precisa saber o que o RenderingSystem está renderizando para mover os objetos do jogo corretamente; ele só precisa definir os valores corretos nos componentes, para que, quando o RenderingSystem renderize os objetos do jogo, ele tenha dados precisos.
O estado do jogo não pode ser um sistema, porque ele precisa interagir com os sistemas e não com os componentes. Não está definindo dados; está determinando quais funções precisam ser chamadas.
Um GameStateComponent não faria sentido porque todos os objetos do jogo compartilham um estado de jogo. Componentes são o que compõem os objetos e cada um é diferente para cada objeto diferente. Por exemplo, os objetos do jogo não podem ter os mesmos limites. Eles podem ter limites sobrepostos, mas se compartilharem um BoundsComponent, serão realmente o mesmo objeto. Felizmente, essa explicação torna minha estrutura menos confusa.
Estado é um valor que se aplica a um objeto. O estado do jogo, como o nome sugere, seria o estado de um objeto 'Jogo'. Esse objeto Jogo - ou, mais provavelmente, um componente específico - rastreará o estado atual e criará ou destruirá os objetos necessários para facilitar o estado atual. Como seus componentes são apenas dados, você precisará de um novo sistema para lidar com isso, mesmo que possa haver apenas uma instância de seu componente associado.
É difícil comentar sobre como você implementaria a pausa quando não está claro como você implementa a atualização. O processo que emite eventos de atualização pode optar por não fazê-lo, se o objeto do jogo indicar que o jogo está em pausa. A forma como o objeto do jogo se comunica com o processo de atualização depende de você; talvez sua
getRelevantObjects
ligação permita que o atualizador encontre o objeto Jogo ou vice-versa.fonte