Anda di halaman 1dari 8

Tetris cumpre o feijão de Java

Quebrar os elementos de jogo Tetris em objetos Java para formar um jogo de


componentes reutilizáveis Java

Scott Clee ( Scott_Clee@uk.ibm.com ), Engenheiro de Software, a IBM

Scott Clee atualmente trabalha como testador FV para o produto IBM CICS. Ele tem
sido um programador Java há quatro anos e gosta de meter em projetos que envolvem
Java diversão. Enquanto seu nome está na luz, ele gostaria de dizer Olá a seus pais,
Stephen e Susan, e seus irmãos, Craig e cristã. Contato Scott em
Scott_Clee@uk.ibm.com .

Resumo: IBM Software Engineer - gamer e no coração - Scott Clee fornece uma
maneira simples de levar o modelo de jogo Tetris e envolvê-lo como um componente
Java Bean reutilizáveis. Uma vez que os elementos do jogo foram divididas em objetos
Java, eles podem ser reagrupados para formar o feijão modelo completo do jogo,
permitindo que seja conectado a virtualmente qualquer GUI Tetris.

Essa versão atualizada permite que você veja o TetrisBean em uso . Basta clicar em
Iniciar e use as setas do teclado para manobrar as peças de Tetris.

Tag isso!

Data: 11 de abril de 2002 (Publicado em 01 março de 2002)


Nível: Introdutório

Atividade: 9.305 visualizações


Comentários:

Um amigo me disse uma vez que sempre que ele aprendeu uma nova linguagem
de programação, ele iria desafiar-se para escrever um jogo de Tetris usando essa
linguagem. Então, essa tradição, eu peguei a mim mesmo a fazer o mesmo quando eu
aprendi a programar usando a linguagem Java. Minha primeira tentativa, apesar de um
jogo completo, era muito básico e muito feio. Como o tempo passou e eu ganhei mais
experiência em Java, design e desenvolvimento, eu sabia que poderia separar o modelo
de jogo a partir do GUI (similar aos componentes Swing) e criar um bean de Tetris.
Então comecei a fazer isso.

Neste artigo, vou orientá-lo através da construção e implementação de feijão Tetris.


Você pode ver o TetrisBean em uso . Basta clicar em Iniciar e use as setas do teclado
para manobrar as peças de Tetris. Pressionando a seta para cima muda a orientação da
peça, pressionando a esquerda e direita setas move a peça de lado e pressionar a seta
para baixo move a peça para o fundo. Dê-lhe uma tentativa!

Peças e partes
Tetris tem vários componentes que podem ser expressas como objetos Java:

• As peças de Tetris
• O conselho de Tetris que detém as peças
• O jogo que controla as peças no tabuleiro, consegue marcar, e assim por diante.

Veremos cada um desses elementos com mais atenção.

Voltar ao topo

As peças de Tetris: Classe TetrisPiece

Os principais elementos de uma peça de Tetris, mostrado na Figura 1, são as seguintes:

• Cada peça é composta por exatamente quatro blocos.


• Cada bloco da peça tem um (x, y) de coordenadas no Conselho de Tetris.
• Cada peça tem um elemento de rotação de 0, 2 ou 4.
• Cada peça pode ser um L, J, S, O, I, Z, ou a forma T.

Figura 1. Quatro elementos são necessários para cada peça de Tetris: blocos, um
(x, y) de coordenadas, um fator de rotação, e sua forma.

O que você pode fazer com um feijão Tetris?


Aqui estão algumas coisas que eu tenho feito desde a criação do feijão Tetris:

• Conectado duas instâncias do feijão juntos para criar um jogo de jogador vs


jogador
• Criado o primeiro jogo Tetris para o Netpad Psion, chamado netris
• Retomado o feijão em um applet para criar um browser compatível com o jogo
Tetris

Os dois primeiros itens podem ser implementados usando um sistema muito simples.
Ao optar por um bloco central de cada peça e seu armazenamento (x, y posição), pode
armazenar o resto dos blocos na peça como coordenadas em relação ao seu redor. Isto
permite-lhe para descrever qualquer estilo de peça simplesmente armazenar a sua forma
de blocos relativa em torno de um pedaço do centro. O ponto central pode ser
armazenado como um java.awt.Point e as coordenadas relativas em um
java.awt.Point matriz. Para tornar mais fácil para coordenar os cálculos, você pode
também armazenar a peça central de um bloco com relação as coordenadas (0,0).

Peças rotativas

Esse sistema também facilita as coisas quando se trata de calcular a rotação das peças.
Usando a manipulação da matriz simples, você pode girar uma peça em 90 graus no
sentido horário, basta trocar a coordenada y, com a coordenada x e x-coordenar com o
negativo da coordenada y. Desde que estejamos usando coordenadas relativas em torno
de um ponto central, podemos fazer o mesmo aqui:

temp = x;
x = y;
y = temp;

Você também pode girar uma peça em 90 graus sentido anti-horário, aplicando três
rotações no sentido horário. (Experimente por si mesmo se você não acredita em mim!)

Finalmente, nem todas as peças têm a mesma quantidade de fator de rotação, de modo
algum controlo terá de ser implementada no método de rotação para compensar isso.

Me dê um L

Porque nós usamos o mesmo TetrisPiece classe para representar todos os tipos de
peças, temos uma maneira de distinguir entre eles. Para fazer isso, usamos alguns
estático int constantes para representar os diferentes tipos e tem uma variável local
para armazenar parte do tipo. Aqui está um exemplo de uma das constantes:

público L_PIECE final static int = 0;

Mover as peças

Porque nós estaremos movendo as peças em torno da placa Tetris, precisamos fornecer
um método de movimento que nos permite fazer isso. Observe que alguns movimentos
podem ser ilegais (como uma tentativa de mover para a direita quando você já está na
medida certa quanto possível), por isso vamos precisar validar todas as solicitações de
mudança. Nós vamos fazer isso contra o conselho de Tetris, que nós vamos guardar
uma referência. Assim, a partir deste construtor da nossa classe terá dois parâmetros: o
primeiro tipo de peça criada e, segundo uma referência para o tabuleiro. No construtor,
vamos chamar um método particular chamado utilitário initalizeBlocks() , que irá
definir os valores das peças é relativo as coordenadas para que o tipo de peça em
questão é.

Uma abordagem simples de verificar a legalidade movimento é para remover a peça do


tabuleiro, em seguida, movê-lo na direção desejada e veja se ele se encaixa. Se isso
acontecer, então colocar a peça na posição de nova diretoria. Caso contrário, desfazer o
movimento e colocá-lo de volta onde estava. Dependendo do resultado, o valor
retornado irá ser true (se o movimento foi bom) ou false (se não fosse).

Um tipo de movimento que precisa de um pouco mais de consideração é que a queda


de um pedaço. A queda significa que a peça será imediatamente suspensa a sua posição
mais baixa na placa. Para fazer isso precisamos de um while de loop que vai continuar
se movendo para baixo até que a peça não pode mover-se mais. A peça será colocada
nessa posição.
Para diferenciar os vários movimentos que podem ser aplicados a uma parte nós vamos
usar alguns extra static int constantes, como mostrado no exemplo a seguir:

LEFT público final static int = 10;

O willFit() método para verificar se uma peça se encaixa será implementado no


TetrisBoard classe mais tarde.

Finalizando TetrisPiece

Finalmente, para encerrar a TetrisPiece classe temos um getters e setters para


algumas variáveis, tais como o ponto central e coordenadas relativas, e um método
estático chamado getRandomPiece() que retornará um TetrisPiece instância do tipo
aleatório.

O código completo, que inclui o TetrisPiece classe, está disponível para download
em Recursos .

Voltar ao topo

O conselho de Tetris: Classe TetrisBoard

Uma placa de Tetris pode ser pensada como uma rede 2D com blocos vazios e blocos
coloridos. Devido aos diversos tipos de peças de Tetris são diferenciadas por int
constantes, tudo o que precisamos fazer é definir um valor para um bloco vazio e
podemos armazenar a bordo como um 2D int array. Usando essa abordagem, um
bloco vazio no conselho será representado por:

público final static int EMPTY_BLOCK = -1;

Para manter as coisas flexível, vamos permitir que o tamanho da placa a ser variável,
mas definir isso no construtor. Assim, o construtor irá aceitar duas int s representa o
número de linhas e colunas. Ela irá então chamar um resetBoard() método que
padrão, todos os valores na matriz 2D para o bloco vazio.

Adição e remoção de peças

Como as peças são adicionados e removidos da placa, nós fornecemos addPiece() e


removePiece() métodos. O addPiece() método funciona tomando um
TetrisPiece() e definir os valores de todas as posições no tabuleiro que ocupa ao de
seu tipo. O removePiece() método é semelhante, exceto os valores de bordo são
definidas ao do bloco vazio.

Notificar os usuários da mudança

Para manter os usuários atualizados quando acontece alguma coisa na placa, uma
BoardEvent será acionado quando as peças são adicionados ou movidos. Para as
classes de ouvir este evento, precisamos de um BoardListener interface, cuja
boardChange() método é chamado quando o evento é acionado. Esses eventos podem
ser usados por uma placa GUI Tetris para ser notificado quando a tela precisa ser
atualizado. Para armazenar os ouvintes, vamos usar um java.util.Vector e fornecer
métodos relevantes para adicionar e remover os ouvintes e os eventos de disparo.

Ocasionalmente, pode não ser apropriado para o fogo BoardEvent é quando você está
adicionando ou removendo pedaços, por exemplo, quando uma queda peça é solicitada
(lembre-se este movimento usa um while de loop para soltar a peça). Neste caso, um
evento só é necessária quando a peça atinge o fundo. Para facilitar isso, vamos criar o
addPiece() método para que ele tenha um parâmetro boolean, que fará com que os
eventos a ser acionado somente se o valor for true .

Removendo linhas concluída

Um fator importante no jogo de Tetris é que quando uma linha é completada,


desaparece e todas as linhas acima, suspenso. Para fazer isso, vamos proporcionar um
removeRow() método que aceita o índice da linha para remover como um parâmetro.
Após a linha foi removida, uma BoardEvent será demitido.

Finalizando TetrisBoard

Uma parede de cem metros de Tetris?


Um dia eu gostaria de ligar o feijão para o sistema de iluminação de um prédio e jogar
Tetris para o lado do edifício. Eu tenho vontade de fazer isso desde que li em um jornal
sobre alguém fazendo o mesmo.

Além dos getters e setters necessários para acessar variáveis privadas, precisamos de
mais um método: o willFit() método discutido anteriormente. Este método leva
TetrisPiece como um parâmetro e retorna um valor booleano para determinar se a
peça se encaixa neste quadro. Por eu apenas significa que a peça está dentro dos limites
da placa e os blocos na placa correspondente ao local onde a peça iria caber estão
definidos para o valor bloco vazio. Se este for o caso, então o valor true é retornado.

Isso completa a TetrisBoard classe. Novamente, a fonte completo, que inclui esta
classe está disponível para download em Recursos .

Voltar ao topo

O modelo de jogo Tetris: Classe TetrisGame

Agora que nós criamos as duas principais componentes utilizados em um jogo de


Tetris, tudo o que temos a fazer é colocá-los juntos com um pouco de lógica do jogo e
estamos fora.

O interior da classe GameThread


Uma boa maneira de controlar o fluxo do jogo é incorporá-lo em uma classe interna
estendendo java.lang.Thread . Uma vantagem dessa abordagem é que podemos
acrescentar uma chamada de sono thread para controlar a velocidade do jogo. Outra é
que porque o segmento do aplicativo principal agora é liberado, não deve ter nenhum
problema de pintura quando uma GUI é anexado, o que pode acontecer às vezes, se o
segmento principal fica amarrado e não tem tempo suficiente para pintar.

A lógica da discussão será implementado dentro de um while loop dentro do run()


método. O loop continuamente criar peças e deixá-los no tabuleiro de jogo até que não
cabem mais peças. Neste ponto, uma variável boolean local chamado fPlaying será
definido como false , encerrando o ciclo e disparar um GameEvent para indicar o final
do jogo.

Dentro do while é um loop if verifica na afirmação de que o valor do boolean


fPaused . Se este for definido como true , o loop continuará funcionando, mas todo o
jogo a lógica será contornado, dando a impressão de uma pausa. Quando o boolean é
alterado novamente para false o jogo vai continuar.

Porque estamos preocupados apenas com um pedaço cair de uma vez, vamos criar uma
variável chamada fCurrPiece que irá armazenar uma referência a ele. Se esta variável
for definida como nula, isso significa que a peça anterior não podia descer mais
nenhuma e foi deixado em sua posição final na placa. Neste ponto, precisamos criar
uma nova peça e posicioná-lo no centro da parte superior do tabuleiro. Por todo o
tempo que o fCurrPiece variável é nula, tudo o que temos a fazer é deixá-lo cair em
uma posição e dormir o segmento para um determinado período de tempo.

Quando uma peça não pode mover qualquer coisa, precisamos de determinar se temos
todas as linhas concluída. Uma maneira fácil de fazer isso é usar um par de nested for
loops onde o exterior através de obras acima dos índices de linha e um controlo interno
entre eles. Se encontrar uma linha completa, podemos chamar o removeRow() método
implementado no TetrisBoard classe e passá-lo o índice da linha completa. Como
todas as linhas acima agora será deslocado para baixo por um, nós vamos precisar
verificar que a linha novamente. Para incentivar a realização de várias linhas de uma só
vez vamos armazenar a contagem das linhas de adjudicação concluídos e um
incremento de pontuação alta, respectivamente.

Outro elemento importante do jogo Tetris é o fato de que, como mais linhas forem
concluídas as peças caem mais rápido. Este recurso pode ser implementado, verificando
o número de linhas concluído até agora e diminuindo o atraso do sono discussão nesse
sentido.

Isso é tudo que existe para o GameThread classe interna, mas há uma outra classe
interna teremos que implementar. Porque não haverá uma carga de eventos disparados
que por sua vez, exigirá ouvintes a ser armazenada, seria puro para nós, para mantê-los
todos em um só lugar. Nós vamos fazer isso usando o EventHandler classe interna.

O interior da classe EventHandler


Esta classe irá armazenar referências para os ouvintes que estão interessados nos
eventos que fogo. Além de fornecer add e remove os métodos para os ouvintes,
também haverá métodos de utilidade para disparar os eventos.

Essa classe cuida dos seguintes tipos de eventos:

• GameEvent , que é acionado sempre que o jogo começa ou pára. Tem um valor
para indicar um jogo START ou END .

• BoardEvent , que é acionado sempre que alguma coisa mudou na placa. No


EventHandler classe de Adicionar / Remover chamadas ouvinte são repassados
aos TetrisBoard classe.

• ScoreEvent , que é acionado sempre que as alterações da pontuação.

Existem muitos outros tipos de eventos que poderiam ter despedido, mas para manter
as coisas simples que eu preso a esses acima. Um outro acontecimento óbvio que
poderíamos implementar é LineEvent , que seria demitido quando uma linha ou várias
linhas estão concluídas e, potencialmente, poderia ser utilizado para acionar uma
animação de tela.

Finalizando TetrisGame

Agora que você terminou a classes internas, é preciso descrever o resto do TetrisGame
classe. Tal como acontece com todos os feijões Java, precisamos de um construtor de
argumento zero. Neste construtor vamos criar uma instância do EventHandler classe e
uma instância do TetrisBoard classe. O TetrisBoard classe terá um tamanho padrão
de 10x20.

Para controlar o estado do jogo nós vamos usar alguns iniciar, parar, pausar e métodos.
O startGame() método irá repor todas as variáveis do jogo e fogo tanto um
ScoreEvent (como já foi redefinido para zero) e um GameEvent (com um tipo de
parâmetro de START ). Também irá criar e lançar uma GameThread . O stopGame() irá
alterar o método fPlaying variável para false , fazendo com que o GameThread ao fim
e um fogo GameEvent com o tipo de parâmetro END . O setPause() método só dar
uma pausa no jogo se realmente está sendo jogado.

Para além de todos os getters e setters necessários, não há mais um único método de
execução, que é o move() método. Este método tem como parâmetro a direção do
movimento, que é uma constante da TetrisPiece classe. Supondo que um jogo está
em jogo e não parou, o move() método tenta fazer a jogada. Se o movimento é uma
gota ou uma solicitação de queda e é vencida, então fCurrPiece é definida como nula
ea peça fica em sua posição atual diretoria. O GameThread então cuida da criação de
uma nova peça para nós.

E isso é tudo para o TetrisGame . Novamente, esta classe está disponível como parte
da fonte completo para download em Recursos .

Agora para ficar completo, poderíamos criar um BeanInfo classe e estas classes jar
com um manifesto de arquivo apropriado, mas por agora não precisamos fazer. O que
nós precisamos, no entanto, é uma interface gráfica simples para testar o nosso feijão
para fora, e um é fornecido em Recursos . Esta é uma classe muito simples que usa uma
classe interna para desenhar o tabuleiro Tetris e contém uma lógica de coordenação das
teclas. A interface gráfica em si é exibido em um javax.swing.JFrame , embora possa
ser uma alternativa java.applet.Applet .

Para testar o feijão Tetris, descompacte o código fonte , mantendo intacta a estrutura do
diretório. (Isto é necessário porque eu coloquei as classes de feijão em uma
TetrisBean pacote que eles precisam estar em um diretório TetrisBean.) Adicione o
caminho onde você descompactou os arquivos de origem no seu classpath java e
compilar os arquivos. Agora tudo que você tem a fazer é executar "java Scottris" e você
está no seu caminho!

Meu próprio pequeno disclaimer: Eu entendo que existem muitas formas este feijão
Tetris poderia ser aplicada, mas o que eu te dei aqui é uma abordagem muito simples
que espero que stoke o fogo criativo. Não hesite em melhorá-la.

Anda mungkin juga menyukai