domingo, 20 de janeiro de 2013

Knight's Trial - Flamethrower, crítico e mira

Boa noite pessoal, tudo bem?

Nessa ultima semana (13-01-2013 a 19-01-2013) a gente tem trabalhado em cima de alguns detalhes do jogo. Na verdade a gente ta trabalhando em cima de uma coisa BEM legal, mas quando estiver mais encaminhada eu mostro pra vocês. Mas, enquanto a coisa BEM legal não aparece haha, estou fazendo alguns ajustes em detalhes do jogo, e trabalhando em cima de umas possibilidades que estamos estudando, mas falo disso em outro post se tudo se confirmar. Hoje no entanto, quero mostrar o seguinte:

Update visual de Flamethrower

A primeira coisa que quero mostrar pra vocês é que finalmente melhoramos a arte da magia Flamethrower! Estava bem porca pra ser sincero, não temos muito a manha dos particle effects ainda, e o novo também não tá exatamente como a gente gostaria, MAS, vejam o videozinho e digam o que acham =).


Danos Críticos

Pra quem prestou atenção no vídeo e já jogou o jogo em algum momento, pode ter percebido outro detalhe que implementamos recentemente. Adicionamos danos críticos, por enquanto o sistema é meio simples, ainda não acho que a arte do "crítico" seja final, mas digam o que acham! Essa é definitivamente a mudança mais ridícula de se fazer, como jogar um dado mesmo... se o valor (de 1 a 100) for menor que 20 por exemplo, um crítico acontece... e um fator divertido no jogo, que possibilita inclusive uma profundidade maior nos itens, que podem dar ao invés de puro aumento de dano, aumentar a chance de danos críticos.


Slow Motion

Outro detalhezinho que também já tinha sido implementado alguns dias atrás é o Slow Motion. Nós diminuimos a velocidade do jogo por um tempo bem breve quando o jogador consegue atingir 3 inimigos ou mais em um só hit, e da um efeito diferenciado, tipo potencializa o impacto, é algo +- assim:


O slow motion na verdade é só o começo de algo que a gente quer adicionar já faz algum tempo. Queremos criar esse tipo de "mini objetivo" durante a partida pro jogador, tipo acertar vários inimigos de uma vez, jogar inimigos pra fora da arena e tudo o mais, dando pequenas recompensas (XP, achievements, gold), incentivando que ele jogue um pouco mais estratégicamente e não puro hack'n'slash. Um exemplo bem recente desse tipo de coisa (que existe em varios jogos) é Diablo 3, quando você elimina muitos monstros com uma só habilidade, ou em muito pouco tempo... é algo desse tipo.

Orientação do Personagem

Bom, essa é uma mudança que não é válida para mobile. Basicamente, agora o jogador pode controlar com o mouse a orientação do personagem ao invés de simplesmente mirar as mágias e elas sairem na direção do click. Não só era horrível você estar andando pra frente e soltar um Frostbolt pra trás e ele sair atravessando você toscamente, como tornava habilidades como o Flamethrower um tanto difíceis de usar, uma vez que só atiravam para a frente. Como agora é possível rotacionar o torso do personagem, você pode lançar chamas para todos os lados sem mudar sua direção de movimento. (Da pra ver isso no vídeo do Flamethrower, la em cima, o Flamethrower antigo ainda não tinha essa funcionalidade, o novo é claramente muito mais fácil controlar)

De todas as features que estou descrevendo aqui, hoje, essa é certamente a mais complicada, pentelha e chata de implementar de todas. Por quê? Bom, é o seguinte:

Não queremos que nenhuma magia atrapalhe a movimentação do personagem, isso é muito chato. Então, se o personagem está indo pra cima, mas quer lançar uma magia pra baixo, se no código eu simplesmente girar o personagem 180 graus pra trás, a animação vai parecer um moonwalk (as pernas vao correr pra baixo (já que estão viradas pra baixo) e o personagem vai, efetivamente, se mover pra cima.

Além disso, se o lançar um Frostbolt precisar esperar toda uma animação do personagem se virando, atirando, e virando de volta... sério, é chato. Perde a dinamicidade que queremos colocar no jogo, você se sente preso e de certa forma punido por estar lançando a habilidade.

Pra resolver esse impace, o primeiro passo que tomamos foi criar um Bone na coluna do personagem que seria controlado apenas pelo código, assim temos um bone que eu posso controlar pelo código sem me preocupar em prejudicar o efeito visual da animação. Como esse bone rotaciona toda a parte de cima do personagem, se eu mandar o bone "apontar" para o mouse, as pernas vao estar apontando em direção ao sentido de movimento do personagem, e o torso vai estar apontando na direção do mouse. Eis que surge o primeiro problema, se o jogador está andando pra cima, e olhar pra baixo, ele vira praticamente o exorcista, o que não é muito legal (nesse caso pelo menos).



O que é preciso é que quando o personagem esteja se movendo no sentido contrário do que ele está mirando (andando pra cima, mirando pra baixo, por exemplo) eu preciso trocar da animação "Correr" para "Correr-de-Costas". Assim, o personagem vai estar inteiro virado para trás, e andando de costas na direção de movimento estabelecida. Pronto, problema resolvido!!

Mas.... mais ou menos. Como saber se a direção de movimento é oposta à direção de mira? Bom, eu infelizmente não sou o matemático que gostaria de ser (ou que deveria ser...) mas, com ajuda do Sr Google, descobri que usando Vector3.Dot(direção-1, direção-2) retorna um valor entre 1 e -1. Se o resultado for 1, quer dizer que as duas direções estão apontando exatamente para o mesmo lugar, e se for -1, as duas estão apontando exatamente em direções opostas.


Maravilha, então se eu disser Vector3.Dot(direção-de-movimento, direção-de-mira), e o resultado for menor que 0, quer dizer que existe uma diferença maior do que 90 graus entre a direção de movimento e a direção de mira, logo, o personagem já está num ponto em que é melhor ele andar de costas do que correr pra frente.

Vixe, mas deu alguma coisa errada. Quando eu estou andando pra frente, e olhando marginalmente pra frente (um angulo menor que 90 graus de diferença), beleza. Quando eu olho pra trás (qualquer angulo maior que 90 graus) o personagem pisca de costas correndo de costas... e isso é feio... muito feio... e ai a primeira coisa que se pensa é usar Quaternion.Lerp pra que as pernas se virem pra trás gradualmente. E realmente funciona. No entanto, depois de testar por 10 segundos, você percebe que solucionou sim o problema de piscar de costas... mas criou outro problema. Como as pernas se rotacionam ao todo 180 graus (porque ou o personagem anda pra frente com as pernas pra frente, ou pra trás com as pernas pra trás), as vezes as pernas vão girar 180 graus pelo lado direito, e as vezes pelo esquerdo... só que o problema é que se o personagem estiver olhando pra direita, a 100 graus de diferença, a perna pode girar pra trás pela esquerda... criando novamente o efeito exorcista... -.-

"Po mas como assim você tem ai o valor de 1 a -1..." pois é, o problema é que se a diferença entre os angulos for 90 graus OU -90 graus, o valor é o mesmo (0), não é possível saber pra que lado que o infeliz ta olhando desse jeito -.-. O motivo pra essa infelicidade é que Vector3.Dot resulta numa função cossena.


Ok, de toda forma, estamos meio caminho andados. Pra resolver essa maravilha de problema, tivemos de fazer algo que eu não estava morrendo de vontade. Criar animações de strafe (andar de lado) uma para a direita e uma para a esquerda, e assim, quando o infeliz estiver olhando pra esquerda, eu troco pra animação "Correr olhando pra esquerda" e quando for pra direita, a mesma coisa. Mas óbviamente criar essas animações não adianta porcaria nenhuma, porque como o valor da função é sempre 0 quando ele estiver olhando pra direita OU esquerda, como vou saber que animação tocar??

E é ai que minha deficiência matemática me fez demorar pra encontrar a solução, e graças a documentação fenomenal, maravilhosa do Unity (sem sarcasmo) eu achei o que eu queria. A p**** do Vector3.Cross(direção-1, direção-2), que por sua vez retorna uma função de seno. Isso é, agora eu tenho uma outra função que quando compara a direção de movimento e a direção de mira, me retorna um valor entre 1,35 e -1,35, só que de outra forma.


Ok, acho que não é muito facil de entender de primeira, principalmente se como eu você não é lá um grande matemático. Tudo o que eu disse até agora, se resume brevemente nessa imagem.


Como eu tenho uma função que é capaz de me dizer se o personagem ta olhando pra frente ou pra trás (Vector3.Dot) e uma que é capaz de me dizer se o personagem está olhando pra direita ou pra esquerda (Vector3.Cross), eu já tenho como detectar pra onde exatamente o arrombado está olhando!


Agora, tudo que eu preciso fazer é o seguinte:


E, finalmente -.-, tudo isso resulta no tipo de rotação vista nos vídeos ai pra cima!

Um link muito útil que encontrei e recomendo pra entender essa história de Dot, Cross... é esse aqui.

Bom, antes de mais nada, para os que leram até aqui, meus parabéns pela paciência =P. Como disse ai no meio, não sou nenhum matemático e sempre tenho problema nos calculos de ângulos e tudo o mais, por isso, se você leu tudo isso só pra dar risada do meu embromation haha, eu ficaria MUITO feliz em saber se há uma solução mais fácil/correta pra esse problema. Se você já teve problema parecido e isso aqui te ajudou, fico muito feliz de saber que fui útil. Qualquer dúvida, deixe um comentário que respondo assim que possível, qualquer correção na minha metodologia, digo o mesmo.

Obrigado pela atenção,
Abraços!

6 comentários:

  1. Achei bem legal essa sua solução. Eu também sou programador e sou terrível com matemática, o que é uma infelicidade.
    Mas é muito bom ver exemplos como você que mesmo tendo problemas com uma matéria dita por muito "essencial" para um programador, não desistiu. =D

    ResponderExcluir
    Respostas
    1. haha é, acho que não pode desistir, o importante é saber que matemática é realmente fundamental e estar disposto a aprender algumas coisas haha, porque digo com segurança que no mínimo 50% dos problemas que me travam no desenvolvimento são relacionados a isso. Mas, mesmo assim, da pra fazer muita coisa, e com google da pra você aprender as coisas mais pontualmente, sem ter que entender teorias gigantescas que te levam a uma fórmula X... por isso, não desista! =P

      Excluir
  2. Bem legal a solução de vocês, Allan. Incrível como justamente os detalhes dão um trabalho absurdo, e detalhes que às vezes não vão interferir tanto no gameplay. O crítico que vocês colocaram mesmo é uma solução simples e que, do ponto de vista do jogador, tem maior impacto no gameplay do que a orientação do personagem.

    Mas a gente sabe que no fundo, são todos estes detalhes que somados, fazem com que o jogo fique ainda melhor. :)

    ResponderExcluir
    Respostas
    1. É verdade Rodolfo, na verdade me arrisco a dizer que detalhezinhos desse tipo são vai... uns 30% do trabalho envolvido (ao menos na parte de programação), uns outros 30% os menus... e o resto mecânica core mesmo...

      Mas como você disse, pro jogador esse tipo de detalhe as vezes conta 10x mais do que uma mecânica core linda sem nenhum bug e tudo o mais... é por isso mesmo que estamos gastando um pouco de esforço em implementar esse tipo de detalhezinho.

      Outra coisa que eu implementei não faz muito tempo é que multipliquei todos os valores de dano e de vida por 50, então Frostbolt ao invés de dar 4 de dano inicial, da 200, e adicionei uma aleatoriedade num total de 10% do valor do dano, então pode dar de 180 a 220... só isso já da uma baita diferença... apesar de na prática não ter diferença absolutamente nenhuma...

      Excluir
  3. Joguei o Knights Trial na versão do Square Enix e já achei fantástico. Fiquei até bravo de saber da implementação de novas armas, funções e etc. rs

    O novo Flamethrower é muito legal. É um pequeno bug nos 21s do vídeo?

    O impacto da camera lenta é legal também.. mas podia vir com um efeito visual que desse uma "dobrada" saindo do ponto de impacto.. tipo o de uma bomba atomica dos filmes.. rs

    Gostei da solução para o movimento, na hora q vc falou da função cosseno eu logo pensei, "que burro, pq não complementa com o seno", mas vc complementou.. rs

    parabéns e libera denovo na app store! rs..

    abs!

    ResponderExcluir
    Respostas
    1. Haha mas tudo isso é pra melhorar o jogo =P, quando você experimentar na pele as mudanças vai sentir como faz diferença, mesmo esses detalhezinhos mínimos como crítico e tal.

      Não é um bug não, é porque o projétil do Flamethrower bateu no tornado e foi refletido numa direção aleatória.

      Acho que entendi haha, você diz tipo aquela distorção né? O maior problema desse tipo de coisa (distorção da imagem) é que é um tanto pesado em processamento, principalmente pra celulares/tablets... mas a idéia é boa, quem sabe... =P

      E agora só vamos liberar de novo quando tiver pronto o jogo... haha

      Abs!

      Excluir