Você está na página 1de 16

Oh My Spikes - Crie um jogo do zero usando o App

Inventor
por Sajal Dutta

Hoje vamos fazer um jogo do zero inspirado nos jogos de spike recentemente
populares . Vamos chamá-lo de Oh My Spikes . Antes de começarmos, você pode querer
ver como ficará o jogo final. Isso o ajudará a seguir o tutorial facilmente.

Isso é o que queremos alcançar

1. Você controla um pássaro tocando em qualquer lugar da tela. Quando você toca, o
pássaro sobe; se não o fizer, o pássaro começa a descer / cair.

2. Seu objetivo é conduzir o pássaro para a esquerda ou direita sem bater em


nenhum pico. Se você conseguir levar o pássaro para a borda esquerda ou direita,
você marca uma pontuação. Quando isso acontece, o pássaro vai para a direção
oposta. Isso continua até você atingir um pico. Vamos primeiro projetar a
interface. Baixe o projeto barebone que já tem o layout da IU, mas sem
blocos. Importe-o e dê uma olhada nos diferentes componentes existentes. Você
pode alterar a aparência e comportamento da maneira que quiser mais tarde. É
assim que o meu se parece ...
Temos os seguintes componentes na Tela1:

1. Um componente Canvas que renomeamos para GameCanvas com Height e


Width ambos definidos como Fill parent.

2. Temos um componente ImageSprite para representar nosso objeto principal do


jogo, que é um pequeno pássaro. Nós o chamamos de BirdSprite. A propriedade
speed deste sprite é definida como 5, significando 5 pixels.

3. Outro sprite de imagem chamado PlaySprite para representar nosso botão


reproduzir / repetir.

4. SpikesBottom e SpikesUp também são sprites de imagem para picos na parte


superior e inferior, conforme os nomes implícitos.

5. Spike1, Spike2, Spike3 e Spike4 são sprites de imagem que serão colocados em
locais aleatórios durante o jogo.

6. Um componente Label denominado ScoreLabel para exibir a pontuação.

7. Quatro componentes de som para reproduzir efeitos sonoros. ScoreSound é


usado quando o jogador faz uma pontuação. FlapSound é quando o jogador toca
na tela para o pássaro bater e subir. DeathSound é usado quando o pássaro bate
em qualquer uma das pontas e morre. Finalmente, o ClickSound é para clicar no
botão Reproduzir/Tentar novamente (play/retry).

8. Nós temos uma TinyDB componente chamado ScoreDB para armazenar a melhor
pontuação.

9. Existem quatro componentes do Relógio. O MoveClock é usado para controlar


quanto tempo o pássaro pode voar quando o jogador toca na tela. Quando o
MoveClock é disparado, paramos de voar. TimerInterval do MoveClock é definido
como 300 milissegundos no modo de exibição de design. yClock é para controlar
a localização do pássaro no eixo y, que tem um intervalo definido como
0. ContinuousFlapClock é para fazer o pássaro bater sem parar. FlapClock
serve para fazer o pássaro bater uma vez quando ele pula. Na verdade,
poderíamos usar um relógio de flap, mas para simplificar e evitar muitos blocos
redefinindo suas propriedades, usamos dois. Agora, vamos definir algumas
variáveis de que precisaremos ao longo do jogo. Vou explicar para que servem em
breve.
DB_SCORE_TAG : Para salvar e ler a melhor pontuação.

STATE_MENU , STATE_READY , STATE_GAME - Um jogo tem estados. Quando você


estiver na tela do menu, pronto para iniciar o jogo e realmente jogar o jogo. Essas
variáveis são constantes, o que significa que não alteraremos seus valores. É por isso que
usamos todas as letras maiúsculas para defini-los.

state - Mantém o estado atual, qualquer um dos três estados acima.


isFalling - Quando o jogador não está tocando, o pássaro começa a descer.
score - pontuação atual no jogo.
bestScore - Melhor pontuação do jogador.
headerLeft - A direção do pássaro no eixo x, tanto para a esquerda quanto para a direita.
temp - Para usar em um escopo menor. Você pode usar variáveis locais se preferir.
isOnLeft - Se os obstáculos / espinhos estão atualmente no lado esquerdo da tela.
SPIKES_Y_POS - Esta variável contém uma lista de listas. Temos 4 sprites de imagem
(espinhos de obstáculo) que são colocados em cada lado dependendo da direção do
pássaro. Se quisermos colocar as pontas à esquerda, podemos usar 0 como ax, se
quisermos à direita, podemos usar a largura da tela menos a largura da ponta
para x. Como a posição x de nossos obstáculos está à esquerda ou à direita, tudo o que
precisamos são valores no eixo y. Criamos 10 locais para esses sprites, colocando-os em
várias posições no modo de exibição de design com espaços adequados entre eles, e
então verificamos no dispositivo se eles parecem bons o suficiente. Então nós
copiamos Y valores da visualização do projeto para SPIKES_Y_POSvariável. Como temos
4 sprites de obstáculo, escolhemos 4 valores no eixo y, um para cada sprite. É por isso
que cada lista contém 4 itens. O primeiro é para Sprite 1, o segundo é para Sprite 2 e
assim por diante. Você pode tentar adicionar mais ou até mesmo randomizar. Em vez de
ter uma lista de listas predefinidas, você pode criar uma lista vazia e depois adicionar itens
a essa lista. Se você está se perguntando por que alguns deles têm -100, é porque nem
sempre queremos mostrar todos os 4 sprites de obstáculo. Então, nós os colocamos fora
da tela. Você pode usar -30 pois cada pico tem 30 pixels de altura. Eu escolhi -100 porque
por algum motivo era mais visível aos meus olhos ver na janela do Blocks quando eu
estava testando.

Vamos inicializar/configurar (initialize/setup) diferentes componentes. Vá para a janela


Blocos. Arraste o bloco Screen1.Initialize na janela Viewer e faça como eu fiz
em Screen1.Initialize . Você também terá que criar alguns procedimentos conforme
mostrado abaixo:
Vamos decompô-los. A tela é inicializada quando o aplicativo é carregado e devemos fazer
o seguinte quando isso acontecer:

1. Queremos que nossa etiqueta de pontuação fique visível. Portanto, definimos sua
visibilidade como verdadeira (true) . Você também pode fazer isso no modo de
exibição de design.

2. Quando mostramos o aplicativo pela primeira vez, não mostramos o


pássaro. Portanto, ele também não deve ser ativado. Você também pode fazer isso
no modo de exibição de design. Eu posso já ter feito isso na visão de design; mas
eu não gosto de ir e voltar para verificar, então refiz.

3. Não queremos que nossos relógios façam nada ainda, então os desativamos, o
que você também pode fazer na visualização de design.

4. Queremos que a altura da tela seja igual à altura do dispositivo menos a altura do
rótulo da pontuação, que é 30. Mostramos a melhor pontuação na tela do menu ou
como jogar, se o jogador ainda não tiver jogado.

5. Lemos o melhor formulário de pontuação TinyDB usando a tag que definimos


antes. Se não houver melhor pontuação, obtemos um texto vazio porque não
colocamos nada no bloco “valueIfTagNotThere“. Obviamente, o tag não estará lá
se não tivermos salvado nenhum placar ainda.

6. Se encontrarmos a melhor pontuação, nós a mostramos. Caso contrário,


informamos ao jogador como jogar este jogo. Você pode criar uma tela com
instruções detalhadas se preferir e mostrá-la em seu lugar.

7. Finalmente chamamos três procedimentos. O procedimento SetupHeader define a


localização do cabeçalho no centro em relação ao eixo x e um pouco abaixo do
topo da tela usando sua altura. Se você não tem certeza sobre esta fórmula
matemática simples de obter o centro de dois pontos, procure no google ' fórmula
do ponto médio' (‘midpoint formula‘). O cabeçalho não contém nada além do
nome do jogo, que é um sprite de imagem e não se move ou interage. É por isso
que, na visualização de design, desabilitamos isso. Depois de definirmos sua
posição, nos certificamos de que está visível.
O procedimento SetupPlayButton coloca o botão de reprodução no centro da
tela. O procedimento SetupGameVisibility leva uma variável booleana como
parâmetro. Chamamos a variável de visibilidade. Se for verdade, mostramos os
componentes do jogo, caso contrário, ocultamos. O motivo pelo qual usamos o
blocl not da gaveta do Logic (Logic drawer) para definir a visibilidade do botão
de jogo é porque quando o jogo começa, não queremos mostrar o botão de jogo,
mas os itens / componentes do jogo. Quando o jogo termina, queremos ocultar
todos os componentes do jogo, exceto o botão play/retry, que também é o mesmo
quando o jogo é iniciado. É por isso que chamamos esse procedimento com um
argumento falso de Screen1.Initialize, pois queremos mostrar apenas os itens da
tela do menu, não os itens da tela do jogo. Pelo jeito que eu sempre estou usando
“tela”, embora haja apenas uma tela (Screen1) Estou fazendo isso para diferenciar
quando apenas os itens de menu (botão Play, score player) são visíveis nos itens
do jogo. Agora temos que definir o que acontece quando o jogador pressiona o
botão play.

Quando o usuário/jogador (user/player) toca no botão de reprodução, primeiro


reproduzimos um som de clique . Em seguida, configuramos o jogo que explicarei um
pouco. Também iniciamos nosso ContinuousFlapClock , pois queremos que o pássaro
bata asas continuamente. Voltaremos a isso também. Aqui está o procedimento
SetupGame
Discutiremos 4 chamadas de procedimento em SetupGame posteriormente. Vamos
primeiro explicar o que acontece no início. Então o jogo está prestes a começar.
Queremos redefinir o valor da pontuação para 0 . Em seguida, mostramos a pontuação
que acabamos de definir como 0. Fazemos isso porque anteriormente a tela do menu
poderia ter mostrado a melhor pontuação ou um tutorial. Mudamos o estado para pronto, o
que significa que o jogo está aguardando o primeiro toque do jogador para começar.
Certificamo-nos de que a etiqueta da pontuação está visível e o cabeçalho invisível.
Queremos colocar os obstáculos de forma aleatória. Não queremos começar o jogo com
picos à esquerda ou à direita o tempo todo, nem queremos apenas alternar. Portanto,
escolhemos um número entre 1 e 2, inclusive. Se o sistema nos der 1, definimos
o isOnLeft para verdadeiro, caso contrário, falso. Agora vamos examinar os 4
procedimentos.
Em SetupTopBottomSpikes , definimos os valores X dos sprites superior e inferior para o
centro no eixo x usando uma fórmula simples de ponto médio. Como o SpikesUp deve
estar no topo, definimos Y como 0; e para o outro, definimos a height da tela (screen)
para que apareça na parte inferior. Lembre-se de que na tela, o ponto (0, 0) está no canto
superior esquerdo da tela.
Em SetupPlacements, certificamo-nos de que a velocidade do pássaro é 5. Você saberá
por que tivemos que fazer isso daqui a pouco. Em seguida, determinamos onde devemos
colocar todos os 4 picos de obstáculo em termos de eixo y. Como temos uma lista de
posições predefinidas contidas na variável SPIKES_Y_POS, só precisamos escolher uma
da lista. Portanto, geramos um número entre 1, que é o índice do primeiro item da lista, e
o tamanho (size) da lista, que é 10, pois temos 10 itens/listas, o que significa que obtemos
um número entre 1 e 10, inclusive. Depois disso, obtemos a lista no índice que obtivemos
aleatoriamente. A razão pela qual escolhemos um número aleatório entre 20 e metade da
altura da tela, para não colocar as pontas sempre no topo da tela. Isso garantirá que não
tenhamos a parte inferior da tela sempre disponível em telas maiores. Não queremos usar
o mesmo conjunto de blocos várias vezes para obter um item da lista; em vez disso,
criamos um procedimento chamado GetListItem que podemos usar facilmente em vez de
usar o mesmo conjunto de blocos e fazer com que pareça muito ocupado.

Como SPIKES_Y_POS é uma lista de listas, o valor da lista também é uma lista. Agora, se
quisermos a lista que contém [-100, 140, 210, 365] que está no índice 1 da lista pai,
devemos dar GetListItem 1 como o parentIndex e, em seguida, se quisermos obter o
número 210, que está em índice 3 da lista de filhos, devemos
fornecer 3 como childIndex . Em seguida, verificamos se devemos colocar os obstáculos
à esquerda usando o valor da variável isOnLeft que determinamos
no procedimento SetupGame.

Agora você deve estar se perguntando por que estamos alterando o valor de isOnLeft
novamente para oposto. É porque SetupGame é chamado apenas uma vez quando o
usuário inicia um jogo, mas este SetupPlacements será usado cada vez que o jogador
saltar de uma borda. Se o jogador rebater na borda esquerda, precisamos colocar os
obstáculos à direita e vice-versa. Depois disso, também alteramos o rumo ao oposto da
direção atual do pássaro no eixo x. O rumo definido como 0 faz com que o pássaro se
mova para a direita. Também definimos a imagem que corresponde à direção do
pássaro. Uma vez que definimos isOnLeft como falso, o que significa que o pássaro deve
se mover para a direita, definimos seu X para a borda direita (largura da tela) menos sua
largura. Colocamos um pixel extra (+1) porque acho a aparência melhor assim. Você não
precisa adicionar esse 1.

O nome da imagem “SpikeLeft.png” pode confundir você, mas pequenos picos nessa
imagem estão apontando para a esquerda, portanto, deve ser usada quando os obstáculos
são colocados no lado direito. Na outra parte, fazemos exatamente o oposto.
A direção 180 faz com que o pássaro se mova para a esquerda. Definimos os obstáculos
' X como -1, mas você pode defini-lo como 0. Fica a seu critério. Exatamente o mesmo
motivo pelo qual foi adicionado 1 ao colocá-los à direita.
Depois de chamar SetupPlacements, chamamos SetUpBirdPosition no procedimento
SetupGame. Em SetupBirdPosition, dependendo da direção que definimos
em SetupPlacements, mudamos onde o pássaro deve ser inicialmente colocado quando
o jogo está no estado pronto, que na verdade é o lado oposto de onde colocamos os
pontos de obstáculo. Você pode usar o título de propriedade da ave se preferir em vez de
usar outra variável (headingLeft) como eu fiz. Mas você tem que fazer uma comparação e
ver se é 0 (direita) ou 180 (esquerda).

O valor de Y não depende do título. Só precisamos ter certeza de não colocá-lo muito para
cima ou muito abaixo, onde ele toca a ponta inferior e morre imediatamente. No final
de SetupGame, chamamos SetupGameVisibility e passamos true como um argumento,
o oposto do que fizemos quando chamamos este procedimento de Screen1.Initialize. É
porque desta vez queremos que as entidades / componentes do jogo fiquem visíveis e o
botão de jogo invisível.
Estamos prontos. O pássaro deve bater continuamente, mas o que exatamente o faz
bater? Se você se lembra, no evento PlaySprite.Touched, habilitamos o
ContinuousFlapClock. No modo de exibição de design, definimos o intervalo do
temporizador deste relógio para 300 milissegundos. Assim, uma vez habilitado, a cada 300
milissegundos, o App Inventor invocará o evento Timer deste relógio automaticamente. E
isso é o que fazemos quando é acionado

Simplesmente chamamos outro procedimento que definimos denominado ChangeImage.


Este procedimento precisa saber a direção do pássaro. É por isso que habilitamos
ContinuousFlapClock depois de chamar SetupGame. Se o procedimento ChangeImage
constatar que o títuloLeft está definido como verdadeiro, ele verifica se a imagem atual
é BirdLeftOne.png, em caso afirmativo, ele a altera para BirdLeftTwo.png para fazer o
pássaro parecer estar batendo as asas. Se for a segunda imagem, muda para a
primeira. Ele faz o oposto se o headerLeft for falso. Agora, estamos esperando que o
jogador toque para começar a jogar. Como iniciamos o jogo e o controlamos depois de
iniciado? Bem, fazemos isso sempre que há um toque na tela. O App Inventor
chama Screen1.Initialize no início de um lançamento de aplicativo, da mesma forma que
ouve qualquer toque em uma tela através do evento GameCanvas.Touched sempre que
o jogador toca a tela.

Nós apenas nos importamos com o toque do usuário quando nosso jogo está pronto
(ready) ou no estado de jogo (game). Quando no estado pronto e o usuário toca pela
primeira vez, mudamos o estado para o estado de jogo. Paramos de bater continuamente
no pássaro desativando o relógio. Habilitamos yClock . Veremos em breve o que ele
faz. Também habilitamos o pássaro para que ele agora possa se mover em uma direção
dependendo de sua direção atual. Sempre que há um toque, fazemos o pássaro pular, o
que significa que alteramos seu valor Y. Para mover ao longo do eixo x, definimos a
direção do pássaro; e na visualização de design, também definimos a velocidade
como 5. No procedimento JumpBird, reproduzimos o som do flap. Definimos isFalling
como falso já que estamos pulando, não caindo. Mudamos a imagem como explicamos
para o movimento contínuo. Habilitamos MoveClock e FlapClock.
Se você se lembra do que mencionei sobre os relógios que temos no início deste tutorial,
você sabe que o MoveClock controla por quanto tempo o pássaro pode voar quando o
jogador toca na tela. Quando o MoveClock é disparado, paramos de voar e definimos
isFalling como true para que o pássaro desça. No evento Timer do FlapClock, mudamos
a imagem do pássaro atual e desabilitamos o cronômetro, pois não queremos que ele
balance continuamente. O que faz o pássaro realmente se mover para cima ou para
baixo? A resposta é yClock . Novamente, yClock deve controlar a localização do pássaro
no eixo y, que tem um intervalo definido como 0 . Então, quando está habilitado, ele
dispara continuamente e faz isso

Se nosso pássaro cair, aumentamos seu valor de Y, uma vez que a posição de Canvas '(0,
0) está no canto superior esquerdo. Se o Y for igual à altura da tela, o pássaro estará na
parte inferior. Fazemos o oposto se estamos subindo. Você pode estar se perguntando por
que não habilitamos / desabilitamos yClock no procedimento JumpBird. É porque quando
estamos no estado de jogo, não temos a intenção de desativar o yClock. O pássaro está
constantemente se movendo para cima ou para baixo. Além disso, o procedimento
JumpBird, como o próprio nome indica, não deve fazer o pássaro cair também. Estamos
perto. O pássaro pula quando o jogador toca e cai se o jogador não tocar. Agora
precisamos lidar com o que acontece quando nosso pássaro atinge a borda esquerda ou
direita.
Sempre que o pássaro atinge a borda esquerda ou direita, o jogador faz uma pontuação.
Então, tocamos o som da partitura. Chamamos SetupPlacements para colocar 4
obstáculos de espinhos no outro lado. Explicamos o que esse procedimento faz há um
tempo. Adicionamos 1 à pontuação e atualizamos o rótulo da pontuação para exibir a nova
pontuação. Infelizmente temos que fazer sua fofura morrer se bater em qualquer um dos 6
pontos (topo, fundo e 4 pontos de obstáculos). Para fazer isso, precisamos verificar se ele
está colidindo com algum deles
Veremos o procedimento EndGameState em breve. Por enquanto, pense, é o fim do
jogo. Se o pássaro colidir com a ponta superior ou inferior, fazemos o pássaro morrer
imediatamente. Para os picos de obstáculo, damos uma pequena vantagem. Chamamos
o procedimento isDead. Se o pássaro colidir com qualquer um dos quatro obstáculos,
verificamos primeiro se ele está se movendo para a esquerda e não muito longe (menos
do meio da tela), e então vemos se ele cruzou o obstáculo no meio, se cruzou, deixamos
ele ao vivo. Depois que ele estiver no meio e colidir com qualquer outro acima ou abaixo,
também não o matamos. Aumentamos sua velocidade para atingir a borda mais rápido
para que não continue colidindo. É por isso que tivemos que redefinir a velocidade
para 5 no procedimento SetupPlacements. Fazemos a mesma coisa para a borda
direita. IsDead retorna true se precisarmos terminar o jogo, caso contrário, retorna false.
Infelizmente, o pássaro morreu. Deixe o mundo saber. Toque o som da morte. Precisamos
mostrar a tela do menu. Desta vez, vamos mudar a imagem do PlaySprite para repetir a
imagem (RetryButton.png). Se a pontuação atual for maior do (heigher) que a melhor
pontuação, se houver, definimos bestScore como pontuação (current score) atual . Em
seguida, salvamos (save) no banco de dados. Escondemos todos os componentes do
jogo. Desativamos o que não é visível. Mudamos o estado. Se não jogamos antes ou
não marcamos nem 1, não temos a melhor pontuação. Nesse caso, apenas mostramos a
pontuação atual. Caso contrário, mostramos ambos, lado a lado.

Se você ainda está a trabalhar e não pulou nenhuma parte deste tutorial, aposto que
realmente vai fazer algo incrível algum dia. Você percebeu que acabamos de fazer um
jogo? Seja parabenizado por seus esforços para chegar até aqui. Lembre-se de que este é
um tutorial para você começar. Ninguém pode impedi-lo de aprimorar o jogo ou começar
algo completamente novo.
Fonte:

http://imagnity.com/android/oh-my-spikes-create-a-game-from-scratch-using-app-inventor/

Você também pode gostar