Desenvolver um software não costuma ser uma tarefa fácil e exige um grande conhecimento sobre programação, além de tempo investido. Sabendo disso, diversas empresas constroem plataformas que permitem elaborar um programa utilizando o mínimo de código possível.
Crie um jogo 2D rapidamente com a engine Unity, seguindo o conceito de low-code.
Desenvolver um software não costuma ser uma tarefa fácil e exige um grande conhecimento sobre programação, além de tempo investido. Sabendo disso, diversas empresas constroem plataformas que permitem elaborar um programa utilizando o mínimo de código possível.
Isso diz respeito ao conceito de low-code. Através do uso de uma interface gráfica, plataformas criadas seguindo essa filosofia reduzem o tempo de desenvolvimento e o conhecimento necessário para a produção de um software.
Para o desenvolvimento de jogos eletrônicos, existem as engines, também conhecidas como motores de jogos. Elas são plataformas low-code que visam simplificar o desenvolvimento, tomando para si as responsabilidades de renderizar os gráficos, calcular a física, oferecer suporte a diversos outros requisitos de um game e diversas ferramentas que agilizam o processo.
Dentre os motores mais conhecidos estão: Unreal Engine (Final Fantasy VII Remake, Crash Bandicoot 4), Unity (Fall Guys, Genshin Impact), Game Maker (Hotline Miami, Shovel Knight), Source (The Stanley Parable, Portal 2), RAGE (GTA V, Red Dead Redemption 2), Frostbite (Dragon Age Inquisition, Battlefield 5), Havok (No Man’s Sky, Dark Souls, Zelda: Breath of the Wild) e CryEngine (Prey, Warface). Eles podem ser gratuitos, pagos ou até mesmo de uso restrito, onde apenas a empresa criadora pode utilizá-la.
Em 2020, a desenvolvedora Media Molecule lançou um sistema completamente gamificado para o PlayStation 4. O projeto, chamado Dreams, deu a muitos gamers a oportunidade de experimentarem uma plataforma Low-Code e também criou uma comunidade de criadores “semi-profissionais”. O servidor do Dreams permite que você viage no meio de todas as criações e experimente o quanto quiser.
Quer aprender a fazer um jogo como este? Continue lendo o artigo!
Mãos a obra
Neste artigo, você aprenderá a como desenvolver um jogo 2D de plataforma, utilizando a licença gratuita da engine Unity.
Configuração inicial do Unity
- Baixe e instale o Unity Hub (caso não tenha um editor de código, permita a instalação do Visual Studio).
- Crie uma conta e faça login pelo próprio Unity Hub.
- Instale o editor Unity.
- Adicione uma licença de uso:
Criando o projeto
Acesse a área Projects, clique em NEW, selecione o template 2D, nomeie o projeto, selecione uma pasta para salvar e clique em CREATE.
Se estiver tudo certo, seu editor do Unity será iniciado e o projeto será aberto pronto para começar sua criação.
Baixando os assets
Os assets são todos os componentes que compõem os jogos, como personagens, cenários, obstáculos e diversos objetos que podem compor a cena. Você pode criar seus assets do zero, desenhando as texturas, animando e desenvolvendo a lógica ou utilizar os que já foram desenvolvidos por outras pessoas.
O Unity disponibiliza a Asset Store, onde é possível encontrar assets gratuitos ou pagos. Neste tutorial, vamos utilizar modelos gratuitos que estão disponíveis nessa loja virtual e faremos nossas alterações.
Para adicionar um asset ao seu Unity, você deve fazer login na Asset Store, acessar o link onde está disponível e clicar em Add to My Assets. Após este processo, ele estará salvo na sua conta e poderá ser acessado no editor. Vamos utilizar os seguintes assets:
Para adicionar os assets no editor, basta acessar o Package Manager...
... e baixar o pacote em questão.
Após efetuar o download, clique em Import para importar os arquivos para dentro do projeto. Este botão substituirá o antigo botão de Download.
Altere o editor de código - opcional
Caso tenha instalado o Visual Studio durante a instalação do Unity Hub e queira utilizá-lo, pule esta etapa. Se tiver um outro editor e queira utilizá-lo, vá em Edit → Preferences... → ExternalTools → External Script Editor → Selecione o seu editor de preferência.
Contruindo o ambiente
Comece seu desenvolvimento definindo uma proporção de tela que será utilizada no jogo.
No pacote do guerreiro há alguns recursos básicos de ambiente, como chão e paredes, que também conseguimos usar como plataformas. Utilizaremos eles para compor o cenário, através do Tilemap. Clique com o botão direito em uma área vazia na janela Hierarchy e adicione uma Tilemap retangular:
Abra a janela paleta de tiles para “pintarmos” o cenário.
Aparecerão os tiles criados no pacote. Com a ferramenta de pincel é possível selecionar um bloco que queremos utilizar e pintar o cenário de acordo com sua vontade.
Rotacionando uma parede, você pode criar uma plataforma.
Agora, você pode adicionar o personagem na cena.
É possível executar seu jogo e testar a Scene que está sendo editada, basta utilizar os botões de controle localizados na parte superior da tela.
Se tentar testar a Scene, notará que o cenário não tem física.
Importante: lembre-se de desativar o modo de teste clicando novamente no botão de play (►), pois nenhuma alteração feita enquanto o jogo está rodando é salva.
O responsável por gerar a física do nosso personagem é o componente RigidBody2D que já foi adicionado pelo criador do asset HeroKnight. No Unity, para que o objeto com física aplicada não caia infinitamente, é preciso de um colisor que impeça isso.
Adicione um Tilemap Collider 2D ao cenário que criamos. Para isso, selecione o Tilemap (vou renomear o elemento pai do Tilemap de Grid para Environment por questões de organização apenas), clique em Add Component e Tilemap Collider 2D.
Neste momento, o personagem e o cenário têm o comportamento esperado. Porém, ainda restam 2 problemas. O primeiro é que em determinados momentos o personagem fica preso entre os blocos do chão. No segundo, o personagem fica “enganchado” nos cantos das paredes e isso ocorre devido ao atrito existente no colisor.
Para resolver o primeiro problema, marque a opção Used By Composite dentro do Tilemap Collider 2D do Tilemap, adicione o componente Composite Collider 2D e altere o Body Type do Rigidbody 2D criado para Kinematic.
O desenvolvedor do pacote criou um material que resolve o segundo problema. Selecione o Tilemap, e adicione o material Walls_noFriction no Composite Collider 2D.
Criando a pontuação
No jogo criado neste tutorial, existirão bolinhas que deverão ser coletas para a fase estar completa. Vamos cria-las agora. Crie um sprite de círculo, adicione o componente Circle Collider 2D nele e ajuste o tamanho para 0.5. Na pasta assets, crie uma outra chamada Scripts para salvar os códigos com a lógica de funcionamento dos nossos elementos dinâmicos.
Crie a interface que exibirá os pontos coletados criando um Text. Selecione o Canvas criado, altere o UI Scale Mode para Scale With Screen Size e altere o Match para 1.
Personalize a interface conforme sua preferência e visualize-a na janela Game.
Crie um objeto vazio e nomeie como GameController. Aqui armazenaremos informações de controle do jogo, como por exemplo quantos pontos o jogador coletou.
Crie um C# Script dentro da pasta Scripts e nomeie-o como GameController. A partir deste momento, serão introduzidos códigos escritos na linguagem de programação C#.
Para mais informações sobre os scripts do Unity, acesse esta documentação.
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; // Importação da interface public class GameController : MonoBehaviour { public int totalScore; // Variável pública que armazena o total de pontos public Text scoreText; // O componente de texto da UI public static GameController instance; // Instancia para ser chamada por outras classes // Função chamada antes do primeiro frame atualizar void Start() { instance = this; } // Função pública para atualizar o texto da UI public void UpdateScoreText() { scoreText.text = totalScore.ToString(); } }
Adicione o Script criado ao objeto vazio GameController e passe o textScore para ele.
Renomeie o círculo criado anteriormente para Point e habilite a opção isTrigger do seu colisor. Isso permitirá que o jogador atravesse o objeto, perdendo sua física.
Crie um C# Script dentro da pasta Scripts, nomeie-o como Point e adicione-o ao círculo.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Point : MonoBehaviour { // Variável que armazena quantos pontos são adicionados no totalScore ao ser coletado public int Score; // Função que é chamada quando algo atravessa o objeto void OnTriggerEnter2D(Collider2D collider) { // Se a tag do objeto de quem colidiu for igual a Player if(collider.gameObject.tag == "Player") { // Soma o totalScore da classe GameController ao Score GameController.instance.totalScore += Score; // Atualiza o texto da UI através da função da classe GameController GameController.instance.UpdateScoreText(); // Destroy o objeto dono deste Script (Point) Destroy(gameObject); } } }
Adicione o valor do Score como 1 no objeto Point.
A partir de agora sua pontuação já está funcionando. Porém, vamos alterar o HeroKnight para que em seu pulo, ele caia mais rápido. Basta alterar a escala da gravidade para 3 em seu Rigidbody 2D e a força do pulo para 12.
Criando um inimigo
Por enquanto está muito fácil para o nosso guerreiro. Vamos adicionar um inimigo para dificultar as coisas. No segundo pacote de assets, há um canhão e uma munição. Vamos utilizá-los para compor o inimigo.
Adicione 2 Box Collider 2D para compor a hitbox do inimigo. Uma será do tamanho do inimigo e outra será um pouco maior, para simular a distância da espada. Esta segunda terá a opção isTrigger ativada.
No HeroKnight, altere o Sleeping Mode do Rigidbody 2D para Never Sleep para que o trigger do Box Collider 2D do inimigo identifique a colisão do player quando ele estiver parado.
Na pasta Scripts crie um C# Script, nomeie-o para Cannon, adicione-o ao objeto do canhão e passe o objeto da munição.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Cannon : MonoBehaviour { public GameObject bullet; // Variável que armazena o objeto da munição // Variável que armazena a distância da munição em relação ao canhão private float bulletDistance; // Função chamada quando há um objeto dentro do objeto gatilho void OnTriggerStay2D(Collider2D col) { // Se o objeto que está colidindo tem a tag Player if (col.gameObject.tag == "Player") { // Se o jogador clicou if (Input.GetMouseButtonDown(0)) { if (col.transform.position.x - gameObject.transform.position.x > 0) { // Se o jogador está olhando na direção do canhão if(col.GetComponent().flipX == true) { this.DestroyEnemy(); // Chama a função que destrói este objeto e o da munição } } else { // Se o jogador está atrás do canhão // Se o jogador está olhando na direção do canhão if(col.GetComponent().flipX == false) { this.DestroyEnemy(); // Chama a função que destrói este objeto e o da munição } } } } } // Função que destrói este objeto e o da munição private void DestroyEnemy() { Destroy(gameObject); // Destrói o canhão // Calcula distância da munição e do canhão bulletDistance = bullet.transform.position.x - gameObject.transform.position.x; if (bulletDistance >= -25 && bulletDistance < -15) { Destroy(bullet); // Destrói a munição } else if (bulletDistance >= -15 && bulletDistance < -10) { Destroy(bullet, 1f); // Destrói a munição depois de 1 segundo } else if (bulletDistance >= -10 && bulletDistance <= 0) { Destroy(bullet, 2f); // Destrói a munição depois de 2 segundos } } }
Adicione um Box Collider 2D na munição. Na pasta Scripts, crie um C# Script, nomeie-o para Bullet, adicione-o ao objeto da munição e passe o objeto do canhão.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Bullet : MonoBehaviour { // Variável que recebe e armazena o objeto do canhão public GameObject cannon; // Função chamada a cada frame void Update() { // Se a posição x da bala é menor que -20 if (transform.position.x < -20) { // Volta a munição à sua posição inicial transform.position = new Vector3(cannon.transform.position.x -0.75f, cannon.transform.position.y + 0.25f, 0); } // Move a munição para a esquerda transform.position = transform.position + new Vector3(-5 * Time.deltaTime, 0, 0); } }
Até o momento, nosso personagem não morre de fato, apenas é empurrado pela munição do inimigo. Vamos construir a tela de fim de jogo para finalizarmos o funcionamento do canhão.
Desenvolvendo o Game Over
Adicione uma imagem à interface ou faça do jeito que achar melhor. Vou criar uma imagem com opacidade reduzida, uma mensagem e um botão para tentar novamente.
Ficando assim:
Deixe esta “imagem” de fim de jogo oculta por padrão, e iremos exibi-la quando o jogo realmente “acabar”.
Agora vamos voltar ao script GameController e criar as funções RestartGame e ShowGameOver
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; // Importação da interface using UnityEngine.SceneManagement; // Importação do gerenciador de cenas public class GameController : MonoBehaviour { public int totalScore; // Variável pública que armazena o total de pontos public Text scoreText; // O componente de texto da UI public GameObject gameOver; // Recebe e aramazena a tela de fim de jogo public static GameController instance; // Instancia para ser chamada por outras classes // Função chamada antes do primeiro frame atualizar void Start() { instance = this; } // Função pública para atualizar o texto da UI public void UpdateScoreText() { scoreText.text = totalScore.ToString(); } // Função pública que exibe o a tela de fim de jogo public void ShowGameOver() { gameOver.SetActive(true); } // Função pública que recarrega a fase public void RestartGame(string lvlName) { SceneManager.LoadScene(lvlName); } }
Agora, passe a tela de Game Over criada na imagem através da variável gameOver do GameController.
Volte na tela de game over, selecione o botão e adicione a função RestartGame na lista On Click para reiniciar a fase ao clicar no botão. Renomeie a cena e passe o nome dela no parâmetro da função.
Para renomear a cena, basta clicar com o botão direito nela, Save Scene As e escolher o local e o nome, salve como lvl_1.
Implementando o Game Over
Agora que temos a tela criada, precisamos implementar a funcionalidade que chama o fim de jogo quando a munição atinge o personagem.
Altere o Script HeroKnight dentro da pasta dos Assets para implementar a funcionalidade de game over. Adicione esta função ao final da classe HeroKnight:
// Game Over void OnCollisionEnter2D(Collision2D collision) { // Se o objeto que está colidindo tem a tag Bullet if (collision.gameObject.tag == "Bullet") { m_animator.SetTrigger("Death"); // Ativa a animação de morte GameController.instance.ShowGameOver(); // Exibe a tela de fim de jogo Destroy(gameObject, 1.2f); // Destrói o personagem depois de 1.2 segundo } }
Crie uma tag chamada Bullet e adicione no objeto da munição:
Implementando o sistema de vitória
Altere o Script GameController, adicionando algumas variáveis e incrementando a função de atualiza score.
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; // Importação da interface using UnityEngine.SceneManagement; // Importação do gerenciador de cenas public class GameController : MonoBehaviour { public int totalScore; // Variável pública que armazena o total de pontos public Text scoreText; // O componente de texto da UI public GameObject gameOver; // Recebe e armazena a tela de fim de jogo public int pointsToWin; // Recebe e armazena a quantidade de pontos necessários para ganhar public string nextLevel; // Recebe e armazena o nome da próxima fase public static GameController instance; // Instancia para ser chamada por outras classes // Função chamada antes do primeiro frame atualizar void Start() { instance = this; } // Função pública para atualizar o texto da UI public void UpdateScoreText() { scoreText.text = totalScore.ToString(); // Atualiza o texto do score // Se o total de pontos do player é igual a quantidade de pontos para vencer if (totalScore == pointsToWin) { // Carrega a próxima Scene SceneManager.LoadScene(nextLevel); } } // Função pública que exibe o a tela de fim de jogo public void ShowGameOver() { gameOver.SetActive(true); } // Função pública que recarrega a fase public void RestartGame(string lvlName) { SceneManager.LoadScene(lvlName); } }
Informe um valor para as novas variáveis:
Voilà
Neste caso, só há uma fase, então ao coletar todos os pontos, o jogo reinicia a mesma fase. Mas caso fosse preciso criar mais, é necessário apenas alterar a variável nextLevel e colocar o nome da próxima fase.
Criando um menu inicial e exportando o jogo
Altere a variável nextLevel para finalScreen, iremos criar uma Scene de final de jogo. Caso tenha criado mais fases, coloque este nome apenas na última delas.
Duplique uma das Scenes, renomeie para finalScreen e crie a tela de vitória para o jogador que tenha concluído todas as fases. Lembre-se de alterar o botão, neste caso coloquei para redirecionar para o mainMenu (próxima Scene que será criada).
Faça o mesmo para criar uma tela inicial, crie com o nome de mainMenu.
Para finalizar, configure sua build para importar todas as Scenes utilizadas no jogo, caso o contrário haverá um erro.
Quer conversar sobre DX e APIs? Clique aqui e marque uma reunião.
Quer escrever na Prensa?
Junte-se a uma comunidade de Creators que estão melhorando a internet com artigos inteligentes, relevantes e humanos. Além disso, seu artigo pode fazer parte do Projeto de Monetização, e você pode ganhar dinheiro com ele!
Clique aqui para se cadastrar e venha com a gente!