🤔 Para Refletir :
"Mais vale um jogo pequeno completo, do que vários jogos grandes incompletos."
- Eliyud

Desenvolvendo um jogo de quebra-cabeças - Parte II

Mayleone Feminino

Conde
Membro
Membro
Console.Write("Hello World!");
Juntou-se
25 de Outubro de 2016
Postagens
267
Bravecoins
3.023
Jigsaw-Puzzle-PNG.png

<< Parte 1
No tutorial anterior nós começamos a desenvolver o jogo de quebra-cabeças recortando as peças de acordo com um tamanho em grade, e criando diversos comandos para gerenciar o game, porém nesse tutorial iremos desenvolver a parte prática do jogo, acompanhe:


Script da peça:
Temos agora as peças e grade em cena, mas elas não possuem nenhuma interação com o usuário.
Vamos então criar o script responsável por "controlarmos" as peças, crie um novo c# script com o nome de "PieceScript".
Vamos então criar nossas variáveis públicas (que serão acessadas a partir de outra classe), portanto terão como atributo "HiddenInInspector": duas variáveis do tipo Vector2 uma chamada "startPosition" e outra com o nome de "endPosition", e duas variáveis do tipo bool, uma chamada "canMove" que vai verificar se essa peça pode se mover e outra "cancelPiece" que vai verificar se essa peça parou de ser manipulada.
Como variáveis privadas nós teremos a variável do tipo SpriteRenderer com o nome de "sprite" e uma outra do tipo float chamada "timeToLerp" para criarmos um efeito "Lerp" ao soltar a peça, essa variável irá iniciar com o valor 20.
Dentro do Start do script inicie a variável ''sprite'' com a obtenção do componente "SpriteRenderer" do objeto:

Untitled%2B24.png


A variável "startPosition" vai ser responsável por informar ao programa qual é a posição em que a peça foi instanciada, portanto, salve esse script e volte ao script "CropTexture" e antes de criar a grade dentro do método "CreatePiece", através da variável "quad" obtenha o script "PieceScript" e faça acesso à variável "StartPosition" definindo a variável "position":

Untitled%2B25.png


Já a variável "EndPosition" é responsável por informar ao programa qual é a parte da grade correta para que a peça seja posicionada, então é crucial que você vá ao método "CreateGrid" e através do parâmetro "quad" faça acesso ao script "PieceScript" e à propriedade "endPosition" da peça, fazendo com que receba a posição (transform.position) da grade que acabou de ser criada:

Untitled%2B27.png


Salve o script.
Vamos agora criar um script chamado "GameManager" que vai conter a score atual do jogador, o score que ele deve obter e a peça atual que está sendo manipulada.
Crie esse script com três variáveis públicas e estáticas, uma do tipo GameObject chamada "currentPiece" e duas do tipo int uma chamada "currentScore" e "scoreTotal". Salve o script:

Untitled%2B28.png


Volte para o script "CropTexture" e no método "StartComponents" faça com que "currentScore" inicie em zero e com que "scoreTotal" receba a quantidade de peças vezes ela mesma:

Untitled%2B29.png


Salve esse script e volte para o script "PieceScript".

Clicando na peça:
Após fazer esses pequenos ajustes, vamos fazer de fato a peça ser "levada" pelo mouse, ao clicar na mesma.
Defina o evento "OnMouseOver" no script "PieceScript" para ser disparado quando o ponteiro do mouse estiver sob o objeto da peça. Dentro do método crie uma condição que vai verificar o lado do mouse que foi pressionado, caso for o esquerdo(0) e cancelPiece for false e currentPiece for null (não há no momento nenhuma outra peça sendo manipulada pelo mouse), faremos com que currentPiece receba esse gameObject(essa peça) e que canMove fique true.
Caso o lado do mouse direito for pressionado (1), cancelPiece for false e canMove for true, iremos fazer com que cancelPiece receba true, pois com o lado direito do mouse nós iremos "soltar" a peça:

Untitled%2B30.png


Agora dentro do Update do script nós vamos criar uma validação se "canMove" for true, e caso for, a peça poderá seguir o ponteiro do mouse.
Primeiro faça com que a sortingOrder do sprite fique igual a 1 (para ficar sobre todas as outras peças), e então crie uma variável local chamada mouseP para receber a posição do mouse de acordo com o mousePosition.
vamos ajustar o eixo 'z' da posição do mouse para as definições da tela do jogo(Mundo do Unity) e não com relação à tela do computador, para isso, basta fazer com que mouseP.z receba a posição "z" da peça menos a posição "z" da câmera.
Então finalmente faça com que o transform.position do objeto(peça) receba a posição do mouse (mouseP) com relação ao mundo dentro do Unity:

Untitled%2B31.png


Através desses comandos, é possível que o sprite do objeto siga o ponteiro do mouse pela tela.

Faremos agora a função de cancelamento da peça, caso o jogador queira "largá-la".
Crie um método sem retorno chamado "CancelPiece" e dentro dele faça com que currentPiece receba 'null' (pois não estamos mais manipulando nenhuma peça), e faça com que a posição da peça volte para sua posição inicial com uma certa suavização utilizando o método "MoveTowards", saindo da posição atual onde o objeto se encontra, tendo como destino o Vector "startPosition" num tempo de acordo com a variável "TimeToLerp" multiplicado por time.DeltaTime.
Faça também com que a variável "canMove" fique false e depois uma validação se a posição do objeto é igual à posição "startPosition", caso for, faça com que o sortingOrder volte a ser 0 e que cancelPiece volte a ficar false:

Untitled%2B32.png


Dentro do Update faça com que CancelPiece seja chamado se "cancelPiece" for verdadeiro:

Untitled%2B33.png


Salve o script e o adicione ao prefab "Piece". Agora ao testar o jogo, você percebe que pode fazer com que a peça siga o mouse ao clicar na mesma, e se clicar com o lado direito, a peça se 'solta' e volta para seu ponto de origem suavemente:

Untitled%2B34.png


Clicando na grade:
Agora que podemos transitar com a peça pela tela através do mouse, vamos criar o script da grade que irá verificar se a peça que estamos manipulando faz parte daquele pedaço da grade.
Crie um novo C# script com o nome de "GridScript".
Dentro do Update desse script, vamos verificar se o mouse está sob o colisor desse objeto (grade) , então crie uma validação através do BoxCollider2D do objeto, e do método "OverlapPoint, passando como argumento a posição do mouse de acordo com o mundo dentro do Unity.
Caso o mouse esteja sob esse collider, chame o método "Check" que iremos definir a seguir.

O método "Check" deve ser sem retorno, e dentro dele vamos verificar se o botão esquerdo o mouse foi pressionado (0) e se currentPiece não é nulo, ou seja, temos alguma peça sendo manipulada no momento.
Caso ambas sentenças forem verdadeiras, iremos criar uma segunda condição que verifica se "endPosition" de "currentPiece" é igual a posição dessa parte da grade, caso sim, iremos posicionar a peça exatamente na mesma posição que esse pedaço da grade, faremos com que o sortingOrder de "currentPiece" volte a ser 0, destruiremos o script "PieceScript" do "currentPiece" para que não possamos mais clicar na peça e movimentá-la, faremos com que currentPiece volte a ser nulo, incrementamos o score do jogador e por fim, destruímos o objeto da grade (Para evitar de clicar nela novamente e melhorar a performance do jogo, já que não iremos mais usar esse script).

Caso a peça corrente não tenha como 'destino' essa parte da grade, apenas faça com que ela "volte" para seu local de origem fazendo com que "cancelPiece" fique true.
O script deve estar assim:

Untitled%2B36.png


Salve o script e adicione-o no prefab "Grid". Teste o jogo e veja que agora é possível encaixar as peças:

Untitled%2B37.png


Verificando final de jogo:
Para verificar o final do jogo é bem simples: Primeiro crie um Canvas com um text ancorado e devidamente dimensionado com o texto "Congratulations":

Untitled%2B38.png


E por padrão deixe-o desativado.
Agora vá para o script "GameManager" e crie uma variável pública do tipo "Text" chamada "text" (referencie a biblioteca "UI" dentro do script!)
Agora dentro do Update crie uma validação se currentScore for igual a totalScore, o gameObject de "text" irá ser ativado:

Untitled%2B39.png


Agora anexe esse script no objeto "GameManager" e faça com que o text do canvas seja armazenado na variável "text" desse script.
Teste o jogo e tente montar o quebra-cabeças: Perceba que quando você o completa o jogo "se encerra" e a mensagem de congratulações aparece na tela:

Untitled%2B40.png


Mostrando imagem original:
Outro sistema que podemos fazer é o de mostrar a imagem como ela é quando montada, ao clicar num botão.
É muito fácil criar esse sistema, basta criar uma imagem dentro do Canvas e a posicionar, ancorar e redimensionar da forma que achar melhor:

Untitled%2B41.png


Desative a imagem também.
Agora vá para o script "CropTextures" crie uma variável pública do tipo Image chamada "img" (referencie a biblioteca UI) e no método "StartComponents" faça com que ela receba a textura da imagem do quebra-cabeças de acordo com sourceTexture, igual já fizemos anteriormente:

Untitled%2B43.png


Salve o script e anexe a imagem na variável "img"do script do GameManager.
Crie agora um Button dentro do Canvas com o Texto "View Image" e o ancore e posicione da forma que achar melhor.
Crie um novo C# script chamado "ButtonScript" e crie uma variável pública do tipo "Image" chamada "img" e uma variável private booleana chamada "isEnabled" iniciando em "false".
Agora defina um método público sem retorno chamado "ClickViewImage" e faça com que a variável "isEnabled" receba seu oposto. Após isso, faça com que a "img" seja ativada se isEnabled for true e desativada se isEnabled for false:

Untitled%2B44.png


Salve o script e o adicione no botão dentro do Canvas, anexando a imagem desativada dentro da variável "img". Dentro do evento "OnClick" clique no sinal de mais (+)  e em "None" adicione o próprio objeto do botão, e após isso em "No Function" vá em "ButtonScript >> ClickViewImage" para esse método seja disparado quando clicarmos no botão.
Teste o jogo e clique no button: Perceba que quando faz isso, a imagem original do quebra-cabeças aparece no canto da tela, e ao clicar novamente no button, ela é desativada:

Untitled%2B46.png


Isso pode auxiliar o jogador a ver como a imagem é de fato para poder montar o quebra-cabeças.

Final:
E chegamos (ufa) a mais um final de tutorial por aqui! A sugestão que eu ainda tenho para melhorar o jogo é criar um menu que possibilite o jogador a escolher com qual imagem ele quer jogar(uma gama de opções de imagens, ao invés de uma) e a dificuldade através da escolha da grade.
Esse tutorial foi muito trabalhoso de fazer (acho que foi o mais de todos) portanto, se gostou e se te ajudou em algo (mesmo se não for com relação ao desenvolvimento de um quebra-cabeças, mas ao aprender sobre algum comando que você não sabia) deixe o seu feedback, isso é muito importante para me motivar a continuar postando tutoriais e aulas aqui.
Por fim, caso queira, aqui está o link do código fonte no gitHub: https://github.com/mayleone1994/PuzzleGame

Até mais!
 
Voltar
Topo Inferior