Artigo original: The Ultimate Beginners Guide To Game Development In Unity
Tradução em português europeu
O Unity é uma ótima ferramenta para criar protótipos de tudo, desde jogos até visualizações interativas. Neste artigo, analisamos tudo o que precisas saber para começar a utilizar o Unity.
Primeiro, um pouco sobre mim: sou um programador amador em Unity, modelador 3D e designer gráfico, que já trabalho com Unity e Blender há mais de 5 anos. Agora, sou aluno de Matemática Financeira na Universidade College Dublin e, ocasionalmente, faço design gráfico, protótipos para a web e protótipos de jogos como freelance.
![Q-bD3OdyDZX2X2cmqgyyRIFwRpy9mngdYAtC](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/Q-bD3OdyDZX2X2cmqgyyRIFwRpy9mngdYAtC.png)
Introdução
Este artigo é para aqueles que nunca utilizaram o Unity, mas que tenham alguma experiência em programação ou design/desenvolvimento para a web. No final deste artigo, deves ter uma boa compreensão geral do motor (em inglês, engine), assim como de todas as funções e código necessários para começar a criar um jogo básico.
Por que o Unity?
Se quiseres criar jogos
Existem apenas algumas opções quando falamos de desenvolvimento de jogos independentes. As três escolhas principais, se quiseres desenvolver jogos, são o Unreal, o Unity ou o GameMaker.
O Unity é provavelmente a opção menos restritiva entre as 3 plataformas. Este fornece-te um produto muito cru logo à partida, mas é muito flexível, bem documentado e altamente extensível para criar basicamente qualquer género de jogo que possas imaginar.
Existem bastantes jogos muito bem-sucedidos, como o Escape from Tarkov (Atirador), Monument Valley (Puzzle) e o This War of Mine (Estratégia/Sobrevivência), todos criados com o Unity.
Na realidade, o motor em que crias o teu primeiro jogo provavelmente não é muito importante. Por isso, o meu conselho é que escolhas um e sigas com esse.
Se quiseres criar protótipos de experiências de utilizador
Visto que o Unity é apenas um motor com algumas físicas, animações e renderização 3D em tempo real, também é um ótimo espaço para criar protótipos completos e interativos para estudos de Experiências de Utilizador (UX – do inglês, User Experience).
O Unity tem suporte total para Realidade Virtual e Realidade Aumentada. Ele pode, então, ser uma ótima ferramenta para explorar arquitetura, automatizações e simulações com os clientes.
Secções deste artigo
- Por que o Unity?
- Janela de edição do Unity
- Objetos de jogo do Unity
- Componentes incorporados do Unity
- Criar componentes personalizados
- Estrutura de MonoComportamento
- Manipular GameObjects
- Raycasting
- Deteção de colisão
- Características avançadas
- Conselhos para iniciantes
- Bons recursos e comunidades
- Conclusão
Janela de edição do Unity
A janela de edição é dividida em várias secções. Vamos abordar isto muito brevemente porque vamos referir esta janela constantemente ao longo deste artigo. Se já te sentires à vontade com isto, podes passar esta parte à frente!
Vista da cena: permite a colocação e o movimento de GameObjects na cena
Vista do jogo: permite visualizar como o jogador verá a cena a partir da câmara
Inspetor: fornece detalhes sobre o GameObject selecionado na cena
Recursos e projeto: todos os pré-fabricados, texturas, modelos, scripts e outros estão armazenados aqui
Hierarquia: permite colocar e estruturar GameObjects dentro da cena
Agora, estamos prontos para começar!
Objetos de jogo do Unity
O que são os GameObjects
Os GameObjects são o bloco de construção principal para tudo no motor de jogos Unity. O nome quase que revela tudo:
Tudo o que colocares dentro de uma cena no Unity deve estar envolvida por um "game object" (objeto de jogo).
Se tiveres experiência em design para a web, podes pensar em GameObjects muito como elementos <div>! Recipientes extremamente aborrecidos, mas altamente extensíveis, para criar funcionalidades ou visuais complexos.
![vlXNfFyr4lsQgC-DL05daoOtSWT35ZFUcA1l](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/vlXNfFyr4lsQgC-DL05daoOtSWT35ZFUcA1l.png)
Praticamente tudo, desde efeitos de partículas, câmaras, jogadores, elementos de Interface de Utilizador, … (a lista continua) é um GameObject.
Criar hierarquia
Tal com uma <div> em desenvolvimento para a web, um GameObject também é um recipiente. Tal como colocas <div>s umas dentro de outras para criar layouts variados e desejáveis ou abstrações, podes querer fazer o mesmo com os objetos de jogo.
A lógica por trás da colocação de game objects uns dentro de outros é muito parecida com o que é feito em desenvolvimento para a web, vou fornecer alguns exemplos…
Desorganização e eficiência
Analogia com a web: tens muitos elementos semelhantes que podem ser gerados dinamicamente em tempo real em resposta a interações de utilizadores e desejam manter as coisas organizadas.
Tradução do Unity: estás a criar uma cópia do Minecraft e tens muitos blocos na cena, então precisas de adicionar e remover 'pedaços' de blocos da cena por questões de desempenho. Então, faz sentido ter cada pedaço associado a um GameObject pai vazio, visto que remover o pedaço pai remove todos os blocos filhos.
Posicionamento
Analogia com a web: queres manter a posição do conteúdo contido 'relativo' ao recipiente e não à página da web.
Tradução do Unity: criaste um conjunto de drones ajudantes que pairam à volta do jogador. Preferias claramente não escrever código para indicar aos drones para seguir o jogador. Então, em vez disso, instancias os drones como filhos do game object do jogador.
Componentes incorporados do Unity
O Modelo de componente do ator
Os GameObjects por si só são bastante inúteis — tal como vimos, são praticamente apenas recipientes. De maneira a fornecer funcionalidade, temos de adicionar componentes, que são essencialmente scripts escritos em C# ou em Javascript.
O Unity funciona com base num modelo de componente de ator – simplificando, os GameObjects são os atores e os componentes são os teus scripts.
Se já tiveres alguma vez criado uma aplicação para a web, estarás à vontade com a ideia de criar pequenos componentes reutilizáveis, tais como botões, elementos de formulário, layouts flexíveis que têm várias diretrizes diferentes e propriedades personalizáveis. Depois, podes montar estes pequenos componentes em páginas da web maiores.
A grande vantagem dessa abordagem é o nível de reutilização e canais de comunicação claramente definidos entre elementos. Tal como em desenvolvimento de jogos, queremos minimizar o risco de efeitos secundários indesejados. Pequenos erros tendem a ficar fora do controlo se não tivermos cuidado e são extremamente difíceis de depurar. Por isso, criar componentes pequenos, robustos e reutilizáveis é crucial.
Componentes chave incorporados
Acho que está na hora de mostrar alguns exemplos dos componentes incorporados fornecidos pelo motor de jogos Unity.
- MeshFilter: permite-te atribuir materiais a uma malha (em inglês, mesh) 3D para um GameObject
- MeshRender: permite-te atribuir materiais a uma malha 3D
- [Box | Mesh]Collider: ativa a deteção do GameObject durante colisões
- Rigidbody: aciona uma simulação física realista para ser aplicada num GameObjects com malhas 3d e aciona eventos de deteção em colisões de caixas
- Light: ilumina partes da tua cena
- Camera: define a vista do jogador para ser anexada a um GameObject
- Vários componentes de tela da Interface de Utilizador para exibir Interfaces Gráficas de Utilizador
Existem muitos mais, mas estes são os principais que precisas conhecer. Uma dica é que podes aceder a todos os documentos através do manual do Unity e na referência de scripting off-line, onde quer que estejas:
![CNB5Rb4DWImRiHh04xThXYtZnojyCj5OJJ1f](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/CNB5Rb4DWImRiHh04xThXYtZnojyCj5OJJ1f.png)
Criar componentes personalizados
Os componentes incorporados controlam primeiramente a física e o visual, mas, para realmente criar um jogo, vais precisar de aceitar inputs do utilizador e manipular esses componentes padrão assim como os próprios GameObjects.
Para começar a criar componentes, vai até ao GameObject desejado > Add Component (Adicionar componente) > escreve o nome do teu novo componente na barra de pesquisa > new script (novo script) (C#).
Como recomendação geral, eu desaconselho utilizar Javascript no Unity. Não foi mantido atualizado com todas as coisas boas que vieram com o ES6 e a maioria das coisas mais avançadas depende de coisas em C# transferidas para Javascript… Por experiência própria, torna-se simplesmente numa solução alternativa gigantesca.
Estrutura de um MonoComportamento
Funções-chave
Todos os componentes herdam da classe do MonoComportamento. Ela inclui vários métodos predefinidos, principalmente:
- void Start(), que é chamado quando um objeto que contém o script é instanciado na cena. Isso é útil sempre que queremos executar algum código de inicialização (por exemplo, definir o equipamento de um jogador após este ser colocado num jogo).
- void Update(), que é chamado a cada frame. É aqui que fica a parte do código que envolve o input do utilizador, atualizando várias propriedades como o movimento de um jogador na cena.
Variáveis do inspetor
Por vezes, queremos tornar os componentes o mais flexíveis possível. Por exemplo, todas as armas podem ter um dano diferente, cadência de tiro, se tem visão etc. Embora todas as armas sejam essencialmente a mesma coisa, podemos querer ser capazes de criar rapidamente diferentes variedades no editor do Unity.
Outro exemplo onde podemos querer fazer isso é quando criamos um componente da Interface de Utilizador, que acompanha os movimentos do rato do utilizador e coloca o cursor na janela. Aqui, podemos querer controlar a sensibilidade dos movimentos do cursor (se o utilizador está a utilizar um joystick ou controlador x um rato de computador). Então, faria sentido ter essa variável fácil de alterar, tanto no modo de edição como durante o tempo de execução.
![ARiWcy5AEsVyRicp7demoZnzQR0MjPQnFzXJ](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/ARiWcy5AEsVyRicp7demoZnzQR0MjPQnFzXJ.png)
Podemos fazer isso facilmente ao declará-las como variáveis públicas no corpo do componente.
![dMqFuop796E9p2Y4urYkJtsuM3Rh6oM07cIJ](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/dMqFuop796E9p2Y4urYkJtsuM3Rh6oM07cIJ.png)
Aceitar inputs de utilizador
Como é óbvio, queremos que o nosso jogo responda a inputs de utilizador. Uma das maneiras mais comuns de se fazer isso é utilizar os seguintes métodos na função Update() de um componente (ou noutro local que queiras):
- Input.GetKey(KeyCode.W): retorna verdadeiro quando a tecla W está a ser pressionada
- Input.GetKeyDown(KeyCode.W): retorna verdadeiro quando a tecla W é pressionada pela primeira vez
- Input.GetAxis("Vertical"), Input.GetAxis("Horizontal") Retorna entre -1,1 a partir do movimento de input do rato
Manipular GameObjects
Assim que recebermos inputs do utilizador, vamos querer que os GameObjects na nossa cena respondam. Existem vários tipos de respostas que podemos considerar:
- Translação, rotação, escala
- Criar GameObjects
- Enviar mensagens a GameObjects/componentes existentes
Transformações
Todos os GameObjects têm uma propriedade transform, que permite que várias manipulações úteis sejam realizadas no game object atual.
![cqutjhXkSZxKNCywMSjGbxewqeDo5GCp0R-d](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/cqutjhXkSZxKNCywMSjGbxewqeDo5GCp0R-d.png)
Os métodos são bastante auto-explicativos, basta observar que utilizamos gameObject em minúsculas para nos referirmos ao GameObject que detém essa instância em específico do componente.
Por norma, é boa prática utilizar local[Position,Rotation] em vez da posição/rotação global de um objeto. Isso, geralmente, torna mais fácil mover objetos num modo que faça sentido, pois o eixo do espaço local estará orientado e centrado no objeto pai e não na origem do mundo e direções x, y e z.
![sgr4nHfYLQYqjEEPSxlxPA0BhCrNjgzzvOmW](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/sgr4nHfYLQYqjEEPSxlxPA0BhCrNjgzzvOmW.png)
Caso precises de fazer a conversão entre espaço local ou global (que é geralmente o caso), podes utilizar o seguinte:
![vNEw9xUc-B2vZOaeAqXcQn5W-lxfmJbLiEZw](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/vNEw9xUc-B2vZOaeAqXcQn5W-lxfmJbLiEZw.png)
Como podes imaginar, existe alguma álgebra linear bastante simples atrás disso, indicada pelo 'Inverse' no nome do método.
Criar GameObjects
Visto que os GameObjects são basicamente tudo na tua cena, podes querer ser capaz de gerá-los na hora. Por exemplo, se o teu jogador tiver um género de um lançador de projéteis, podes querer ser capaz de criar projéteis na hora, que vão ter a sua própria lógica encapsulada para voar, efetuar dano etc…
Primeiro, precisamos de introduzir a noção de um Prefab. Podemos criar esses ao arrastar qualquer GameObject na hierarquia da cena para a pasta dos assets.
![BEBGqpePGsVgtEY5y89WrnLAbdZjPHZiagjZ](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/BEBGqpePGsVgtEY5y89WrnLAbdZjPHZiagjZ.png)
Isso, basicamente, armazena um template do objeto que tínhamos na cena, com todas as mesmas configurações.
![wFLWTKOYgxfMEAEzUjgMsTCETSmTA3JIPLGp](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/wFLWTKOYgxfMEAEzUjgMsTCETSmTA3JIPLGp.png)
Assim que tivermos estes componentes prefab, podemos atribuí-los a variáveis de inspeção (como abordamos anteriormente) em qualquer componente na cena. Então, podemos criar GameObjects como especificado pelo prefab a qualquer altura.
Podemos realizar 'Instanciação' do prefab e manipulá-lo para a localização desejada na cena e estabelecer as relações hierárquicas necessárias.
![xAzUlbgEAIkyS8bsX8W0xlVI0YiSTiVyMljj](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/xAzUlbgEAIkyS8bsX8W0xlVI0YiSTiVyMljj.png)
Aceder a outros GameObjects e componentes
Por vezes, precisamos de comunicar com outros GameObjects assim como os seus componentes associados. Assim que tiveres uma referência a um game object, isso fica muito simples.
ComponentName comp = some_game_object.GetComponent<ComponentName>();
Depois disso, podes aceder a quaisquer métodos/variáveis públicos do componente de maneira a manipular o GameObject. Essa é a parte mais direta, no entanto. Obter realmente a referência para o GameObject pode ser feito de várias formas diferentes…
Aceder através de variável de inspeção
Esta é a maneira mais direta. Cria simplesmente uma variável pública para o GameObject, tal como demonstramos anteriormente com os prefabs, e arrasta-a manualmente para o componente através do inspetor. De seguida, acede à variável tal como acima.
Aceder através de tags
Podemos atribuir tags a GameObjects ou prefabs através do inspetor e depois utilizar as funções find do game object para localizar as referências para eles.
![9Ur13zYuVV3r17CGo9hDMnyCoG44jTXCwv4g](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/9Ur13zYuVV3r17CGo9hDMnyCoG44jTXCwv4g.png)
Isso é simplesmente feito como abaixo.
GameObject some_game_object = GameObject.FindGameObjectWithTag(“Brick”);
Aceder através do atributo transform
Se quisermos aceder a componentes em algum objeto pai, podemos simplesmente fazer isto através do atributo transform.
ComponentName comp = gameObject.transform.parent.GetComponent<ComponentName>();
Aceder através de funções SendMessage
Como alternativa, se quisermos enviar uma mensagem a muitos outros componentes ou desejarmos enviar uma mensagem a um objeto que está bastante acima na hierarquia, podemos utilizar as funções de envio de mensagem, que aceitam o nome da função, seguido pelos argumentos.
gameObject.SendMessage("MethodName",params); // Mensagem de Broadcast
gameObject.SendMessageUpwards("MethodName", params); // Apenas recebido por componentes que estão hierarquicamente acima.
Raycasting
Podes ter ouvido falar disso antes, quando as pessoas comparam jogos de FPS que são 'baseados em físicas' ou 'baseados em raios'. Raycasting é essencialmente como ter um laser que, quando entra em contacto com um 'collider' ou 'rigidbody', retorna um 'hit' e passa de volta os detalhes do objeto.
Existem dois cenários onde isto é útil (existem provavelmente muitos mais):
- Se estivesses a desenhar um sistema de armas para um jogo, poderias utilizar raycasting para detetar a colisão e até mesmo personalizar o comprimento do raio de modo a que as armas corpo-a-corpo 'atinjam' apenas a curtas distâncias.
- Criar um raio desde o ponteiro do rato até um ponto num espaço 3D, ou seja, se desejares que o utilizador seja capaz de selecionar unidades com o seu rato num jogo de estratégia.
![GcxZnE2hbosbWwoDp94ecEd1g8aVlwrFKOhB](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/GcxZnE2hbosbWwoDp94ecEd1g8aVlwrFKOhB.png)
Como podes ver, o código para isso é um pouco mais complicado. A coisa principal a compreender é que, para criar um raio para onde o rato está a apontar num espaço 3D, é necessária a transformação ScreenPointToRay. A razão para isso é que a câmara está a renderizar um espaço 3D como uma janela 2D no ecrã do teu computador. Então, existe naturalmente uma projeção envolvida para transferir de volta para 3D.
Deteção de colisão
Anteriormente, mencionamos os componentes Collider e Rigidbody, que podem ser adicionados a um objeto. A regra para colisões é que um objeto na colisão deve ter um rigidbody e o outro deve ter um collider (ou ambos terem os dois componentes). Repara que, ao utilizar raycasting, os raios vão interagir apenas com objetos com componentes collider anexados.
Assim que fizermos a configuração dentro de qualquer componente personalizado anexado ao objeto, podemos utilizar os métodos OnCollisionEnter, OnCollisionStay e OnCollisionExit para responder a colisões. Assim que tivermos a informação de colisão, podemos obter o GameObject responsável e utilizar o que aprendemos anteriormente para interagir também com componentes anexados a ele.
![ppKZgvdAjKDqbW80Nin2wG9izk08UjyuaqAt](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/ppKZgvdAjKDqbW80Nin2wG9izk08UjyuaqAt.png)
Uma coisa a ter em conta é que os rigid-bodies fornecem físicas como gravidade aos objetos. Então, se desejares desligar isto, vais precisar de marcar o is_kinematic.
![I9UU3oy-UoVWOwjhXUy9PRiGDT5eFO4O9-IB](https://www.freecodecamp.org/portuguese/news/content/images/2024/05/I9UU3oy-UoVWOwjhXUy9PRiGDT5eFO4O9-IB.png)
Características avançadas
Não vamos abordar nada disto para já, mas talvez num artigo futuro — isso é apenas para ficares a par da sua existência.
Criar interfaces gráficas de utilizador (GUI)
O Unity tem um motor de UI completo para definir a GUI do teu jogo. Por norma, esses componentes funcionam de maneira muito semelhante ao resto do motor.
Estender o editor do Unity
O Unity permite-te adicionar botões personalizados aos teus inspetores para que possas afetar o mundo no modo de edição. Por exemplo, para ajudar com a construção do mundo, podes desenvolver uma janela personalizada de ferramentas para criar casas modulares.
Animação
O Unity tem um sistema de animação baseado em gráficos que te permite juntar e controlar animações em vários objetos, tais como jogadores a implementar um sistema de animação com base nos ossos.
Materiais e PBR
O Unity funciona num motor de renderização com base em físicas que permite ter luzes em tempo real e materiais realistas. A realidade é que vais aprender primeiro modelação 3D ou vais utilizar modelos já feitos e otimizados por alguém, de modo a criares algo que realmente tenha bom aspeto.
Dicas para principiantes
Se estiveres a planear criar o teu primeiro jogo, não subestimes a complexidade e o tempo que leva a escrever até o mais trivial dos jogos. Lembra-te que a maior parte dos jogos lançados na Steam têm equipas a trabalhar neles durante anos a tempo inteiro!
Escolhe um conceito simples e divide-o em pequenos objetivos alcançáveis. É altamente recomendado dividir o teu jogo em tantos componentes independentes quanto possível, pois é muito menos provável encontrares erros se mantiveres os componentes simples em vez de blocos de código monolíticos.
Antes de avançares para a escrita de qualquer código para qualquer parte do teu jogo, pesquisa o que outras pessoas fizeram antes para resolver o mesmo problema — é provável que tenham uma solução bastante mais otimizada.
Bons recursos e comunidades
O desenvolvimento de jogos tem uma das melhores comunidades de todas. Existem muitos profissionais altamente habilitados na indústria, que fornecem conteúdo gratuitamente ou por quase nada. É uma área que requer modeladores 3D, artistas conceptuais, designers de jogos, programadores e assim adiante. Abaixo, coloquei os links para alguns recursos gerais ótimos (em inglês) que encontrei para cada um desses campos:
Arte Conceptual
- Feng Zhu Design School (mais de 90 horas de tutoriais de arte conceptual)
- Tyler Edlin Art (ótima comunidade de arte BST com feedback de profissionais em desafios mensais)
- Art Cafe (entrevistas e workshops com artistas conceptuais famosos)
- Trent Kaniuga (ilustrador e artista 2D que também está a criar o seu próprio jogo)
Modelação 3D
- CG Cookie (melhores princípios básicos de malhas 3D no Blender – eles têm muitos outros excelentes conteúdos para o Blender)
- Tor Frick (modeladores de Hard Surface e escultores no Blender)
- Gleb Alexandrov (pequenos tutoriais potentes sobre renderização no Blender)
Desenvolvimento de jogos
- DoubleFine Amnesia Fortnight (programadores de jogos que fazem maratonas de duas semanas a programar e gravam todo o seu processo de design)
- GameMakers Toolkit (examina princípios de design de jogos)
Programação
- Série Handmade Hero no canal Molly Rocket (como criar um jogo e motor a partir do zero em C)
- Jonathan Blow (programador independente que faz livestreams do seu desenvolvimento de jogos)
- Brackeys (bons tutoriais de Unity)
Conclusão
Espero que tenhas gostado deste tutorial! Também faço um pouco de design gráfico, assim como protótipos de jogos e Interfaces de Utilizador.
Se o tutorial foi do teu agrado, dá uma vista de olhos ao portfólio do autor! Ele também está presente no LinkedIn.