Estou trabalhando em um jogo simples baseado em blocos.
O jogo consiste basicamente em mover blocos na área de jogo, por isso é uma simulação física trivial. Minha implementação, no entanto, está longe de ser ideal e estou pensando se você pode me dar alguma dica sobre como fazê-lo melhor.
Dividi o código em duas áreas: lógica do jogo e interface do usuário, como fiz com muitos jogos de quebra-cabeça:
- A lógica do jogo é responsável pelas regras gerais do jogo (por exemplo, o sistema formal de regras no xadrez)
- A interface do usuário exibe a área e as peças do jogo (por exemplo, tabuleiro e peças de xadrez) e é responsável pelas animações (por exemplo, movimento animado das peças de xadrez)
A lógica do jogo representa o estado do jogo como uma grade lógica, onde cada unidade tem a largura / altura de uma célula na grade. Portanto, para uma grade de largura 6, você pode mover um bloco de largura 2 quatro vezes até que ele colide com o limite.
A interface do usuário pega essa grade e a desenha convertendo tamanhos lógicos em pixels (ou seja, multiplica por uma constante). No entanto, como o jogo praticamente não tem lógica de jogo, minha camada de lógica de jogo [1] não tem muito o que fazer, exceto a detecção de colisão. Veja como funciona:
- O jogador começa a arrastar uma peça
- A interface do usuário solicita à lógica do jogo a área de movimento legal dessa peça e permite que o jogador a arraste para dentro dessa área
- Jogador solta um pedaço
- A interface do usuário encaixa a peça na grade (para que fique em uma posição lógica válida)
- A interface do usuário informa à lógica do jogo a nova posição lógica (por meio de métodos mutadores, que eu prefiro evitar)
Não estou muito feliz com isso:
- Estou escrevendo testes de unidade para a minha camada de lógica do jogo, mas não a interface do usuário, e acabou que todo o código complicado está na interface do usuário: impedindo a peça de colidir com outras pessoas ou o limite e encaixando-a na grade.
- Não gosto do fato de a interface do usuário informar a lógica do jogo sobre o novo estado; prefiro chamar um
movePieceLeft()
método ou algo parecido, como nos outros jogos, mas não fui muito longe com essa abordagem, porque a lógica do jogo não sabe nada sobre o arrastar e ajustar possível na interface do usuário.
Eu acho que a melhor coisa a fazer seria me livrar da camada de lógica do jogo e implementar uma camada de física. Eu tenho algumas perguntas sobre isso:
- Essa camada de física é comum ou é mais típico que a camada de lógica do jogo faça isso?
- O encaixe na grade e o código de arrasto da peça pertenceriam à interface do usuário ou à camada física?
- Essa camada de física normalmente funcionaria com tamanhos de pixel ou com algum tipo de unidade lógica, como minha camada de lógica de jogo?
- Já vi uma detecção de colisão baseada em eventos na base de código de um jogo, ou seja, o jogador apenas arrastava a peça, a interface do usuário renderizava isso obedientemente e notificava o sistema de física, e o sistema físico chamava um método onCollision () na peça uma vez que uma colisão é detectada. O que é mais comum? Esta abordagem ou pedindo a área de movimento legal primeiro?
[1] camada provavelmente não é a palavra certa para o que quero dizer, mas o subsistema parece exagerado e a classe é equivocada, porque cada camada pode consistir em várias classes.
Respostas:
Vou tentar responder a essa pergunta, pois entendo o que você está perguntando, embora não tenha muita experiência em desenvolvimento de jogos, pois ainda estou aprendendo.
A meu ver, você deve separar o código da GUI da lógica do jogo e dos objetos de domínio, ou seja, as peças do quebra-cabeça. Essas são de fato três camadas separadas - e sim,
layer
é um termo apropriado na minha opinião. É frequentemente usado para explicar os conceitos de separar cada nível de objetos de um sistema em subsistemas independentes um do outro.Em relação à programação orientada a objetos, cada objeto deve ser uma classe. Assim, cada peça do seu quebra-cabeça deve consistir em uma classe por si só, e assim no tabuleiro do jogo. O tabuleiro do jogo deve conter X peças do quebra-cabeça, dependendo do tamanho e da capacidade de movimento que você deseja dar ao jogador.
Então, aqui estão meus pensamentos sobre o tópico - espero que ajude:
Nessa arquitetura, a camada da GUI mostraria ao jogador o estado do jogo, a localização de cada peça do quebra-cabeça. A camada da GUI seria responsável por obter as entradas do jogador e passá-la para uma camada subjacente do Game Controller, que seria responsável pela detecção de colisão. Se não houver, a peça pode ser encomendada para se mover nessa direção de entrada. Para fazer isso, basta chamar os
MoveLeft
,MoveRight
, etc. métodos para fazer a peça se mover. Você também pode deixar o tabuleiro saber qual peça você quer mover e, em seguida, ela ordena o movimento da peça, e a peça se move na direção exigida. Essa arquitetura facilita o teste de cada parte do código nas diferentes camadas e permite testes de unidade, testes de integração e testes funcionais.Eu sei que isso pode parecer um pouco confuso à vista, e graças a Deus se não for! Se você precisar de mais detalhes e ajuda, não hesite em perguntar, ficarei feliz em ajudar da melhor maneira possível, embora eu seja iniciante no desenvolvimento de jogos.
Obrigado pela leitura! =)
fonte
Position
função getter de propriedades, de modo que o controlador do jogo agora exige que a GUI exiba essa peça movida para a nova posição.