Criando um Arkanoid com Unity: mecânica de blocos, Prefabs e Design
() translation by (you can also view the original English article)



Nesta série de tutoriais, mostraremos como recriar o clássico jogo Arkanoid (ou Breakout) com Unity, usando ferramentas nativas 2D do Unity. Em cada postagem, vamos nos concentrar em uma parte específica do jogo. Nesta, nós vamos lidar com a mecânica de blocos e a criação de Prefabs.
Onde paramos
Nos tutoriais anteriores, você configurou o projeto e programou os comportamentos do bastão e da bola. Se você não tiver concluído os tutoriais anteriores, é altamente recomendável que você faça isso antes de continuar.
Produto final
Dê uma olhada nesta demo para ver o que queremos alcançar em toda a série:
E aqui está o que nós vamos fazer até o final deste post:
Criando o bloco de script
Neste momento, quase toda a mecânica base está pronta. A parte que falta está relacionada aos blocos. Como os blocos são uma parte importante do jogo, precisamos criar um script personalizado para ele.
O bloco de script deve conter informações sobre:
- Total de acertos que ele pode ter.
- Pontos a receber por quebrar.
(Observe que o número de acertos e de pontos podem mudar de acordo com a cor do bloco). Com base nisso, vamos dar ao bloco três variáveis:
- Uma variável para armazenar o número de pancadas que o bloco pode levar.
- Uma variável para armazenar o valor de pontos do bloco.
- Uma variável para armazenar o número de vezes que o bloco já foi atingido.
Os dois primeiros serão public
, desde que você queira modificar seus valores no editor. O terceiro será private
, já que é somente para uso interno.
Então, crie um novo script chamado BlockScript
. Definia as variáveis e inicialize o número de acertos com 0
:
1 |
public class BlockScript : MonoBehaviour { |
2 |
|
3 |
public int hitsToKill: |
4 |
public int points; |
5 |
private int numberOfHits; |
6 |
|
7 |
// Use this for initialization
|
8 |
void Start () { |
9 |
numberOfHits = 0; |
10 |
}
|
11 |
|
12 |
// Update is called once per frame
|
13 |
void Update () { |
14 |
|
15 |
}
|
16 |
}
|
O próximo passo é detectar quando as bolas acertam um bloco. Quando ocorre esta colisão, verificamos se o bloco foi atingido o suficiente para ser destruído, ou se ainda ficará intacto. Por isso, podemos usar um método específico, chamado OnCollisionEnter2D
, que é chamado sempre que uma colisão ocorre com o seu objeto.
Para verificar se esta colisão é entre a bola e o bloco, você deve marcar o objeto bola. No editor, selecione a bola na guia Hierarchy e, em seguida, o Inspector. No topo do Inpector, sob o nome de objeto, há um campo chamado Tag que atualmente está definido como Untagged
. Clique no botão, e um menu drop-down vai abrir com as possibilidades de marcação (tag):



Nós queremos uma tag específica para a bola, clique então em Add Tag para criar uma nova marcação. Uma vez que você pressionar a opção uma nova interface vai aparecer:



Para este tutorial, enfatizaremos apenas a propriedade Element 0. Isso define o nome da marcação, então, digite o nome Ball
para ela.

Agora que você tem a tag Ball
, mude a marca do objeto bola para Ball
.
Abra o arquivo BlockScript
para nós programarmos o método OnCollisionEnter2D
. Para identificar o objeto do jogo, verifique se a marcação do objeto bola é Ball
; se assim for, então, a colisão será entre o bloco e a bola. Adicione o seguinte código no seu script.
1 |
void OnCollisionEnter2D(Collision2D collision){ |
2 |
|
3 |
if (collision.gameObject.tag == "Ball"){ |
4 |
|
5 |
}
|
6 |
}
|
Agora você pode detectar colisões com a bola. Após cada colisão, queremos aumentar o número de vezes que o bloco foi atingido e, se o número de vezes for o mesmo que o número máximo de pancadas que o bloco pode tomar, destruiremos o bloco. Por último, podemos usar o método Destroy.
A modificação no trecho OnCollisionEnter2D
para fazer isso será mais ou menos assim:
1 |
void OnCollisionEnter2D(Collision2D collision){ |
2 |
|
3 |
if (collision.gameObject.tag == "Ball"){ |
4 |
numberOfHits++; |
5 |
|
6 |
if (numberOfHits == hitsToKill){ |
7 |
// destroy the object
|
8 |
Destroy(this.gameObject); |
9 |
}
|
10 |
}
|
11 |
}
|
Agora, adicione o BlockScript
ao objeto Ball (Hierarchy > Inspector > Add Component):



Agora é hora de verificar se está tudo bem. Altere o valor de Hits To Kill no editor para 1
e jogue o jogo. Quando a bola atingir o bloco, o bloco deve desaparecer.
Criando um Prefab
Agora que a mecânica do bloco está pronta, vamos preencher a fase. Como você usará vários blocos para isto, este é um bom momento para introduzir Prefabs do Unity.
Um Prefab é um objeto reutilizável que pode ser inserido diversas vezes na mesma cena. Basicamente, isto significa que se você quiser, por exemplo, alterar o valor de pontos dos blocos azuis, você não precisa fazê-lo para cada bloco azul na cena: se você tem um Prefab de um bloco azul, é só ajustar o valor no Prefab e todos os blocos azuis serão atualizados na cena.
Para criar um Prefab para os blocos azuis, comece renomeando o objeto Block para Blue Block. Em seguida, crie uma nova pasta na pasta Assets chamada Prefabs. Agora, arraste o objeto Blue Blocks para dentro da nova pasta.



Como você deve ter notado, o ícone de cubo no topo do Inspector agora está azul. Além disso, o nome do objeto na cena Hierarchy também está azul. Isto significa que o bloco é agora um Prefab. Bastante simples, não é? De agora em diante, selecionando o Prefab e alterarando seus valores, as alterações serão aplicadas a todos os parâmetros de todos os nossos blocos azuis.
Para testar o Prefab, arraste-o da pasta para a guia Hierarchy. Como você pode ver, agora temos dois blocos azuis, mas eles compartilham a mesma posição, que ficou definida pelo Prefab.



Para ter dois blocos em posições diferentes, basta selecionar um na guia Hierarchy e movê-lo na cena. Desta forma, você altera os valores dessa cópia específica do bloco e não de todos os blocos.



Você pode jogar e testar os Prefabs.
Recriando Prefabs
Agora você criará os Prefabs restantes para os outros blocos (verde, amarelo e vermelho). As principais etapas para cada um são:
- Criar um novo Sprite.
- Adicionar a imagem correspondente.
- Adicionar um Box Collider 2D.
- Adicionar o BlockScript.
- Nomeá-lo de acordo.
- Criar um Prefab.
No final você deve ter quatro Prefabs diferentes (uma para cada tipo de bloco):



A fim de tornar o jogo mais interessante, mude a variável Hits To Kill para cada tipo de bloco da seguinte forma:
- Azul:
1
acerto. - Verde:
2
acertos. - Amarelo:
3
acertos. - Vermelho:
4
acertos.
Adicione alguns blocos e jogue o jogo; verifique se tudo está funcionando como esperado.
Design de fases
Agora é hora de criar sua primeira fase. Usando os Prefabs, preencha a área de jogo com vários blocos. Se você colocou vários blocos como nós fizemos, sua guia Hierarchy provavelmente estará lotada objetos! A fim de manter seu projeto bem organizado, vamos criar objetos vazios para os quatro tipos de blocos e em seguida agrupá-los por cor:



Neste ponto, seu jogo está quase pronto, sua mecânica básica está implementada, e ela deve ser semelhante à seguinte figura:



Sistema de vidas e pontuação
A pontuação e sistema de vidas é uma maneira de testar os jogadores e introduzir novas dinâmicas aos jogos. Neste ponto, o nosso jogo não tem forma alguma para o jogador avançar ou perder. Vamos mudar isso agora.
Abra o PlayerScript
e adicione duas variáveis: uma para a pontuação e outra para o número de vidas que o jogador tem. Deixaremos que o jogador comece o jogo com três vidas e sem pontos:
1 |
private int playerLives; |
2 |
private int playerPoints; |
3 |
|
4 |
// Use this for initialization
|
5 |
void Start () { |
6 |
// get the initial position of the game object
|
7 |
playerPosition = gameObject.transform.position; |
8 |
|
9 |
playerLives = 3; |
10 |
playerPoints = 0; |
11 |
|
12 |
}
|
Precisamos de um método que aumenta o número de pontos que o jogador tem sempre que destrói um bloco. Crie um novo método chamado addPoints
para fazer isso:
1 |
void addPoints(int points){ |
2 |
playerPoints += points; |
3 |
}
|
Agora temos o novo método que está esperando um valor — mas como ele irá recebê-lo? Existem muitos blocos para fazer referências ao bastão do jogador em cada um...
A melhor maneira de resolver isto é enviar uma mensagem do objeto bloco para o objeto bastão. Como fazemos isso? Bem, primeiro você precisa marcar o bastão (Hierarchy > Inspector > Tag) com a tag Player.



Com o bastão marcado, é hora de passar para o script do bloco, onde vamos mudar o método OnCollisionEnter2D
para enviar os pontos para o objeto do jogador: antes que o bloco seja destruído, ele vai procurar um objeto com a marcação Player
usando o método de FindGameObjectsWithTag
; Isso retornará uma matriz de objetos correspondente, uma vez que existe apenas um objeto com essa marca, sabemos que o objeto na posição 0 da matriz é o objeto bastão do jogador.
Agora que você tem a referência do jogador, você pode enviar uma mensagem usando o método SendMessage
. Com isso, você pode chamar um método específico do objeto — neste caso, o método addPoints
.
O seguinte trecho mostra-lhe como isto funciona:
1 |
void OnCollisionEnter2D(Collision2D collision){ |
2 |
|
3 |
if (collision.gameObject.tag == "Ball"){ |
4 |
numberOfHits++; |
5 |
|
6 |
if (numberOfHits == hitsToKill){ |
7 |
// get reference of player object
|
8 |
GameObject player = GameObject.FindGameObjectsWithTag("Player")[0]; |
9 |
|
10 |
// send message
|
11 |
player.SendMessage("addPoints", points); |
12 |
|
13 |
// destroy the object
|
14 |
Destroy(this.gameObject); |
15 |
}
|
16 |
}
|
17 |
}
|
A próxima coisa que precisamos fazer é editar os Prefabs e dar valores específicos de pontos para cada tipo de bloco. Você pode usar os seguintes valores:
- Azul:
10
pontos; - Verde:
20
pontos; - Amarelo:
35
pontos; - Vermelho:
50
pontos;



Agora, vamos mostrar estes pontos e vidas na interface do jogo. No script do jogador, crie um método chamado OnGUI
. Este método irá representar o GUI de seu jogo; é um dos métodos básicos para apresentar informações na área de jogos. (Note que as maiúsculas e minúsculas são diferentes).
Para apresentar os pontos e as vidas, precisamos criar um Label
(rótulo) com o texto desejado. No PlayerScript
, adicione o método OnGUI
e crie este rótulo nele:
1 |
void OnGUI(){ |
2 |
GUI.Label (new Rect(5.0f,3.0f,200.0f,200.0f),"Live's: " + playerLives + " Score: " + playerPoints); |
3 |
}
|
Agora você pode jogar o jogo e o rótulo será apresentado na parte superior esquerda da tela. No entanto, você não programou ainda a exibição de vidas e pontos para atualizar de acordo!
Usando o mesmo PlayerScript
, adicione o seguinte método TakeLife
. O método vai subtrair uma vida do jogador cada vez que ele é chamado:
1 |
void TakeLife(){ |
2 |
playerLives--; |
3 |
}
|
Finalmente, vamos para o BallScript
e, na seção onde você verifica se a bola caiu fora da tela, envie uma mensagem para o objeto do jogador com o métod TakeLife
. O trecho completo é apresentado abaixo:
1 |
// Check if ball falls
|
2 |
if (ballIsActive && transform.position.y < -6) { |
3 |
ballIsActive = !ballIsActive; |
4 |
ballPosition.x = playerObject.transform.position.x; |
5 |
ballPosition.y = -4.2f; |
6 |
transform.position = ballPosition; |
7 |
|
8 |
rigidbody2D.isKinematic = true; |
9 |
|
10 |
// New code - Send Message
|
11 |
playerObject.SendMessage("TakeLife"); |
12 |
}
|
Jogue o seu jogo e verifique se a pontuação e o sistema de vidas funciona conforme o esperado.
Para a próxima
Isto conclui a terceira postagem da série. A mecânica básica do jogo está toda implementada, então da próxima vez vamos adicionar o áudio e novos níveis e exportar o jogo terminado.
Se você tiver quaisquer perguntas ou comentários sobre o que cobrimos até agora, sinta-se livre para deixar um comentário abaixo.