Join Waitlist We will inform you when the product arrives in stock. Just leave your valid email address below.
Email Quantity We won't share your address with anybody else.
Destaque, Gear VR / Cardboard, Tutoriais, Unreal Engine, Vídeos 360

Criando uma cena 360 de League of Legends na Unreal Engine 4

Aqui estão nossas experiências para montar uma cena de League of Legends na Unreal Engine 4. Como foi um projeto de aprendizagem, muitas das soluções apresentadas podem não ser as melhores maneiras de se resolverem os problemas. Também não é um guia passo a passo de como foi feito tudo e sim mais um resumo das experiências e impressões que tivemos. Outra coisa a ser considerada é que foi utilizado a versão 4.10 da Unreal Engine 4.

O resultado foi esse:

  • Importando o modelo da fase

A princípio encontramos um modelo da fase Summoner em formato .obj (https://sketchfab.com/models/ac0a9c6676e34d1ebb184d8e93443c77), liberado apenas para estudos, com todas as suas texturas. Porém ao importarmos esse modelo para o UE4, percebemos que as normais dos polígonos estavam invertidas. Para inverter essas normais usamos o programa 3D Blender e a ferramenta Flip Direction que se encontra no modo Edit Mode.  Ainda no blender, retiramos algumas partes da fase que não seriam úteis, como algumas partes que serviam de background.

Ao importar o modelo da fase diversos materiais são criados, sendo que cada um possui uma textura de um trajeto ou pedaço específico da fase. Foi necessário configurar o Especular (Specular) e rugosidade (Roughness) desses materiais, pois os mesmos só possuíam a cor difusa ou base color da textura. A técnica de normalMap também foi aplicada, e o artigo mais detalhado sobre isso está neste link

figura0.1normalmaps

Imagem do normal map e a visualização da técnica aplicada no material do piso.

Não foi possível utilizar a técnica de Lightmap por completo, pois é necessário criar uma segunda camada de uv para a malha da fase. Detalhes dessa técnica de lightmap se encontra nesse link.

O background do cenário foi feito a partir do criador de terrenos (landscape) do UE4. As árvores criadas nesse terreno, foram previamente extraídas do modelo da fase e replicadas no modo Foliage.

figura0.2summonermap

Fase Summoner no UE4 com Landscape.

 

  • Como fazer para importar as animações para o Unreal Engine

Tivemos uma certa dificuldade para conseguir os modelos do jogo, pois não sabíamos como converter os arquivos .anm do League of Legends para um arquivo que o UE4 consiga entender. Como a gente fez para exportar todos esses arquivos está discutido em outro artigo e não vou me alongar muito nessa parte.

  • Decidir quais ferramentas utilizar para fazer a cena

Na Unreal Engine tem essa ferramenta chamada Matinee que sua principal função é de compor uma cena de animação. Ela mexe nas câmeras, coloca uns “efeitos especiais” e faz os movimentos dos objetos.

O problema que percebemos é que a Matinee não tem a função de blending para fazer a transição entre as animações. Ela não considera o estado dos campeões, como a velocidade com que estão deslocando para usar como peso para o blending.

Aliás, simular física também é complicado na Matinee. Subir e descer escadas faz essa tarefa ficar muito difícil para animar pois ela simplesmente ignora qualquer tipo de colisão, fazendo com que os personagens atravessem qualquer objeto.

Por esses motivos decidimos que somente a Matinee não daria muito certo para montar a cena. Então pensamos em animar os campeões por blueprints e AI e somente utilizar a Matinee para dar trigger nos eventos.

  • Animando os personagens por blueprints

Essa parte foi um tanto confusa para quem está aprendendo a mexer na Unreal Engine 4. Confuso pois eles não tratam as animações todas em uma única blueprint.

Pelo que entendemos dos exemplos que vimos do Content Examples, eles separam as animações em duas categorias: as ativadas por input de teclado e clique do mouse, que rodam uma vez ao ser ativada e animações ligadas por estado do personagem, como por exemplo andando e pulando. Esses dois tipos ficam em duas blueprints distintas, uma na blueprint do objeto e outra na blueprint animation da mesh respectivamente.

– Animações de Estado

Nessa categoria entram animações que pertencem a um “estado” do personagem, como por exemplo, andando, pulando e nadando. Elas normalmente precisam ficar em loop, então, são melhor representadas por estados do personagem. É precisamente o que a Animation Blueprint faz, cria estados e até mesmo faz o blending de animações com base em variáveis.

No nosso projeto, criamos para a Ashe um Blend Space 1D que faz um bleding de duas animações com base em uma variável. Utilizamos duas animações originais, uma de correndo e outra de parada com a variável Speed. O resultado ficou desse jeito:

Nota do autor: Esse resultado me deixou impressionado na primeira vez que fiz o blending, parece que realmente ela começa a andar com Speed intermediário.

Com essa Blend Space pudemos criar um estado chamado Idle/Running que é alimentado pela variável Speed na blueprint animation. O blueprint animation ficou desse jeito:

BP_Animation_Ashe1

Clicando em Default temos

BP_Animation_Ashe2

E depois em Idle/Running

BP_Animation_Ashe3

E essa blueprint é do Event Graph

BP_Animation_Ashe4

Para testar essa animação, fizemos um copy paste na blueprint de controle do personagem do mapa exemplo ThirdPerson e só troquei o modelo da Ashe e o Blueprint Animation acima.

– Animações Ativadas

Nessa categoria ficam animações que são acionadas e “rodadas” uma vez. Por exemplo ataques com espada e tiro com alguma arma caem nessa categoria.

O blueprint da Ashe que fiz para atirar uma flecha ficou assim:

figura5_BP_Ashe

E como ficou a animação final:

Explicando o blueprint feito:

-> InputActionAttack: O evento que faz o trigger é o clique do mouse esquerdo que está com o nome Attack. Poderia ser qualquer trigger de evento mas pela similaridade com jogos de tiro optamos por colocar como trigger esse input mesmo. Se no seu mapa não tiver essa opção do clique esquerdo do mouse, tem que mexer na configuração em Edit > Project Settings depois ir em Engine > Input e adicionar o input desejado.

-> Deactivate/ToggleActive: Um dos problemas que tive ao fazer a ação de ataque é que a Ashe podia andar enquanto fazia a animação de atirar. Para resolver esse problema resolvemos que enquanto ela está atirando, todos os inputs são ignorados pelo personagem. No final devolvemos o comando com o ToggleActive.

-> Montage Play: Aciona uma animação do tipo Animation Montage . Não sabemos muito bem como funciona esse tipo de função mas sabemos que essa animação é inserida no node Slot lá da blueprint animation. No caso foi inserida a animação de ataque.

-> Delay/SpawnActor Flecha: O delay serve para que o modelo da flecha seja criada no instante em que ela solta. A variável Arrow Socket contém o nome do socket da skeleton da Ashe onde fica a metade do arco, localizando assim onde vai ser criado a flecha.

-> Último Delay: Para que não fique spammando tiros, a Ashe tem que terminar a animação antes que possa atirar novamente. Antes disso podíamos atirar várias flechas como se fosse uma metralhadora.

Talvez por ter um tratamento todo específico, a implantação da animação de ataque na blueprint do objeto foi a melhor abordagem a ser feita.

Essas blueprints ficaram muito modularizadas, utilizamos praticamente 95% delas em todas as outras unidades.

  • Lidando com a Inteligência Artificial e Behavior Trees

Essa parte deu um trabalho grande para implementar. Com as animações prontas tivemos que montar uma IA que fizesse seguir pelo caminho e que fosse comandado para atacar um alvo na hora em que quiséssemos. Tivemos dificuldade para entender como funciona a Behavior Tree, pois não era familiar essa abordagem em árvore.

Para que eles caminhassem pela bottom lane, tivemos que colocar vários target points no mapa e colocar todos eles num array, para que ao chegar num target point ele achava o próximo só aumentando o índice desse array.

Summoners_rift_season_4_map

Para unidades ranged fizemos uma modificação na função MoveTo para que se fosse do tipo ranged, o Acceptance Radius fosse maior fazendo com que a unidade parasse longe da unidade alvo.

Tivemos problemas com a Task MoveTo porque essa task não para de executar enquanto não atingir o ponto ou encontrar um bloqueio no meio do caminho. Logo se eu mandasse ir para um ponto e comandasse para atacar no meio do caminho, ele terminava de percorrer o caminho até o ponto e depois ia fazer o ataque.

Uma solução é tentar fazer com que tenha muito mais target points no caminho mas vimos que os minions dão uma paradinha para cada target point, fazendo com que a movimentação ficasse muito travada. Achamos melhor deixar como está e contornar o problema setando os comandos de ataque um pouco antes deles chegarem no ponto.

A Ai funcionava simulando mais ou menos como o jogo funciona, você tem o alvo e ele ataca ou se move até ele, dependendo se era um TargetPoint ou se era um Pawn ( no caso minions e campeões).

figura5.1_behaviortree

  • Tentativa de integração da AI com a Matinee

Programamos a AI pensando em integrar com a Matinee que ia controlar os eventos de quando atacar e movimentar os personagens. Essa primeira tentativa deu errado pela sua instabilidade, não funcionava muito bem escolhendo personagens aleatórios para as ações e as vezes nem funcionava.

Colocamos umas variáveis booleanas nos campeões para simular mais ou menos como o jogo funciona:

-> IsSelected para avisar que personagem ia fazer uma ação;

-> IsTarget para avisar qual objeto/personagem ia ser o alvo da ação;

figura6_booleans

E criamos dois eventos na Matinee que acionava os eventos de Ataque e Movimento. Ela também setava as duas variáveis para true no momento que chamavam os eventos, sendo tudo mandado para a blueprint do level.

figura7_matineesetando

E a blueprint do level cuidava da lógica necessária para os controladores AI saberem que ações fazer e setava para false os dois booleans.

figura8_setarVariáveisAI

Então funcionava mais ou menos assim:

  1. A Matinee setava IsSelected para true para um campeão que quisessemos fazer uma ação. No caso da figura os red minions foram selecionados.
  2. Também setava IsTarget para true o alvo que ia sofrer a ação. O alvo no caso é a Ashe.
  3. A Matinee dá o trigger do evento de Attack.
  4. No level blueprint ele pega os atores que tem true em IsSelected e IsTarget e coloca na blackboard da AI para que possa executar a ação e depois setava para false os dois.

Para um evento funcionava muito bem, mas conforme colocamos vários eventos ao mesmo tempo em paralelo, não dava tempo para os booleans terminarem de ser setados para false e mesmo a Matinee é meio instável quanto a isso.

Então resolvemos jogar todo esse código fora e fazer tudo no level blueprints mesmo.

  • Fazendo a cena inteira com o level blueprints

Fazendo no level blueprints ficou muito mais fácil a questão de mandar um campeão fazer uma ação, ficando uma função bem mais direta do que estava no código anterior. Colocamos o código empacotado numa função chamada Action.

figura10_função_action

E chamava a função com um delay antes, simulando uma linha do tempo.

(Deveria ter colocado a função Delay dentro do Action porque utilizei em todas as instâncias de Action)

figura9_animação_em_blueprint

Por fim com essa abordagem deu certo e o resultado final foi esse:

  • Gravando em 360

Nessa parte utilizamos esse tutorial para fazer esse tipo de gravação:

Colocamos a PanoCam e PanoCamCapture no mapa e com a Matinee guiamos a sua movimentação por ela. Capturado as cenas, renderizamos no blender pelo Video Editing.

Resumo rápido desse tutorial acima:

Tem que colocar os dois objetos PanoCam e PanoCamCapture no mapa. O PanoCam tira fotos em vários ângulos para montar uma imagem 360 e a PanoCamCapture é o que faz a captura das imagens para salvar. Logo a PanoCam é o que nós movimentamos pela tela e a PanoCamCapture fica em um lugar isolado debaixo do solo.

Depois de alguns ajustes de velocidade da câmera (diminuímos a velocidade em 4x) chegamos na versão final do começo do artigo.

 

Notícia AnteriorPróxima Notícia

Comentários