Nesta série de artigos, falarei sobre como e por que decidimos criar nossa própria solução para importar animações em flash para o Unity, sobre otimizações e a cozinha interna do plug-in resultante. E também no programa: uma história sobre o interior do formato swf, os recursos da extensão do editor do Unity e geralmente sobre animações em geral. Eu peço um corte!

1. Introdução
No início de qualquer projeto, estão as dores da escolha da tecnologia para muitas de suas partes. Uma dessas partes é o sistema de animação. Existem várias variáveis das quais essa escolha depende. Em primeiro lugar, com o que seus animadores costumam trabalhar (ou podem) ou com quais ferramentas esses animadores são mais fáceis de encontrar. É claro que não faz sentido escolher um produto extremamente específico, porque se os funcionários atuais deixarem por um motivo ou outro (um ônibus repentino?), Será extremamente difícil substituí-los, parte do projeto simplesmente parará indefinidamente, o que, no caso de um produto comercial pode ser muito caro. A segunda variável é mais técnica: integração ao seu mecanismo. Existem soluções de terceiros e a qualidade dessas soluções, existe alguma força e capacidade de criar as minhas, além da produtividade e conveniência de todas as opções acima? Bem, a terceira variável são os recursos dessa ferramenta, porque se você precisar de cinemática inversa , é absolutamente estranho escolher animação não esquelética.
Tipos de animações 2D
Considere as opções mais populares para implementar animações em jogos. Vou falar apenas de animações 2D, 3D - este é o tópico de uma conversa, abordagens e ferramentas completamente diferentes. Você pode pular com segurança uma seção se for mais experiente nessas questões (não haverá revelações nem avarias no véu), ou se pretendeu ir ver os recursos de apenas animações em flash, elas estão abaixo.
Animações de quadros
Nossa mini-revisão é aberta com o tipo de animação mais simples e mais antigo: animação quadro a quadro. Cada quadro de tal animação é representado por uma imagem separada, com uma rápida mudança da qual surge uma ilusão de movimento.
Prós:
Uma implementação elementar, geralmente em qualquer mecanismo. Qualquer complexidade e estilo de animação, pelo menos, expõe e insere um filme em quadros (em teoria, é claro). Qualquer ferramenta: quase tudo pode fornecer uma sequência de quadros que, se necessário, podem ser colados em um atlas de textura.
Contras:
O principal menos é, obviamente, o tamanho dessas coisas na memória. Naturalmente, existem todos os tipos de truques, como cortar quadros em blocos e subsequente reutilização de blocos repetidos, carregamento em segundo plano de quadros do disco e liberação já mostrados, entre outros. Mas esses truques têm suas desvantagens. A divisão de blocos - adequada apenas para pixel art , carregamento em segundo plano - cria carga adicional no disco, ocupa muito espaço nesse disco e o tamanho do seu jogo aumenta, assim como a quantidade de dados baixados para iniciar ou atualizar.
Total:
Adequado apenas para animações de tamanho pequeno e número de quadros, ideal para pixel art e o estilo de jogos retrô à la NES .
Animações em vídeo
Como apoteose da loucura das animações quadro a quadro, aparecem as animações em vídeo. E sim, é usado e até ocasionalmente para o local. Implementamos isso para jogos no gênero " Hidden Object ", para animações grandes e complexas, bem como para cenas cortadas com um toque de realismo. Com a ajuda de codecs como theora e vp8, você pode implementar animações de vídeo bastante toleráveis (e mesmo com um canal alfa ).
As vantagens aqui, é claro, são que você pode mostrar em tais animações tudo o que seu coração deseja, desde cenas dirigidas com a participação de atores reais até batalhas em 3D renderizadas. As desvantagens são a carga selvagem na CPU ao decodificar isso e, é claro, a qualidade da imagem. Você pode encontrar um compromisso entre qualidade e desempenho em casos muito limitados e específicos, como nos jogos indicados acima para Objetos Ocultos, por exemplo.
Em geral, está longe de ser adequado para todos e longe de sempre, ou melhor, quase nunca, se não considerarmos cenas cortadas renderizadas - onde é o lugar para essas "animações". Uma boa implementação de tais animações também não pode se vangloriar de simplicidade, há muitas nuances e truques, tanto em termos da qualidade da imagem de saída quanto das cargas recebidas no processador central. Devido à especificidade, existem poucas implementações prontas, elas também não diferem na qualidade ou custam muito dinheiro (oi, Bink_Video ), muitas escrevem por conta própria.
Animações esqueléticas
Então chegamos aos tipos populares e modernos de animações 2D. As animações esqueléticas capturam cada vez mais os corações e mentes dos desenvolvedores no campo de 2D, tornando-se a animação padrão para jogos. É engraçado que eles tenham aparecido tão amplamente em 2D recentemente, diferentemente da 3D, onde apareceram durante o tempo de King Peas, quando os pais escreveram Half-Life . A essência das animações esqueléticas, curiosamente, está no esqueleto, que cria um animador a partir de ossos conectados entre si por uma estrutura de árvore. Fragmentos são anexados aos ossos na forma de figuras separadas. Toda a estrutura é acionada por deslocamentos e rotações dos ossos um em relação ao outro. Os deslocamentos e rotações dos ossos no esqueleto seguem a linha do tempo geral da animação.
As vantagens são óbvias: não precisamos armazenar cada quadro da animação na forma de figuras separadas, apenas fragmentos (os braços e as pernas do personagem, por exemplo), que moveremos os ossos do esqueleto. Existem excelentes implementações desse tipo de animação com tempos de execução para as plataformas e mecanismos necessários, com um preço razoável de uso ou mesmo gratuito: Spine , Spriter , Anima2D , DragonBones e outros. Graças ao esqueleto e suas características, é possível obter uma suavidade colossal das animações interpolando as posições de seus ossos, além de misturar transições de animação para animação e até misturar duas animações diferentes: disparar em fuga, disparar furtivamente e assim por diante. Não vou listar todas as possibilidades de animação esquelética, existem muitas e são muito legais. É melhor fornecer um link em que eles sejam mostrados claramente com fotos e descrições no site da Spine .
Parece uma bala de prata, mas não. Houve alguns pontos negativos. Faça imediatamente uma reserva que, para muitos projetos e animações, essas desvantagens podem não existir. Se as animações esqueléticas combinam com você - é ótimo, use-as, elas são lindas e modernas.
Vamos voltar aos pontos negativos. Um estágio adicional na criação de animação é o rig (ou o rigging, como muitos termos em nossa indústria, também foi russificado). A própria criação do esqueleto e a ligação dos ossos aos fragmentos. Se o objeto tiver uma animação, e não várias, como, por exemplo, o personagem do jogo no gênero " Platformer ", o palco será completamente supérfluo. Nem todas as animações são convenientemente animadas com ossos. Existem muitas animações em que os ossos atrapalham e, sem elas, é mais conveniente e rápido, tanto em termos de criação quanto em termos de desempenho do jogo. Um item separado, contratarei especialistas do mercado. O número deles cresce com a popularidade da animação esquelética, mas ainda não é uma tarefa fácil encontrá-los em sua equipe. A dispersão de ferramentas e ferramentas também afeta, alguém está acostumado e usa um, alguém, é necessário reaprender em movimento, o que cria dificuldades adicionais em encontrar e treinar funcionários.
Animações da linha do tempo
Levei esse tipo de animação até o fim, não porque é melhor que todos os outros, mas porque são apenas as animações em flash sobre o interior que serão discutidas na parte técnica do artigo. O Flash não é o único representante desse tipo de animação, mas certamente seu líder, portanto tudo será descrito com relação a ele. As animações da linha do tempo consistem em fragmentos que são animados em camadas separadas em uma linha do tempo. Quase a mesma coisa que vimos na animação esquelética, mas sem esqueleto. De acordo com os quadros principais da linha do tempo, podemos mover, girar, substituir, desenhar novos fragmentos nesses quadros e, é claro, interpolar a hifenização, a escala e a rotação entre eles. Ou seja, não movemos os ossos com os fragmentos anexados, mas os próprios fragmentos. Obviamente, perdemos muitas das oportunidades que as animações esqueléticas nos dão, mas nem todo mundo precisa delas. Em troca, adquirimos outros, como:
- a capacidade de desenhar e inserir novos fragmentos no meio da animação;
- sem plataforma, sem ossos que às vezes apenas interferem;
- O Adobe Flash (agora Adobe Animate ) é a ferramenta de animação mais antiga e comprovada há anos; um número muito grande de animadores, de uma forma ou de outra, é o proprietário;
- a capacidade de usar animações antigas ao traduzir seus projetos em flash para o Unity, incluindo animações feitas em gráficos vetoriais , e não apenas em raster .
O flash está morto? Como jogador nos navegadores - certamente, como uma ferramenta para animações - viva e bem, não há alternativas e não são esperadas. Contras? Claro. O principal ponto negativo é que isso não é animação esquelética, hein. Somos privados da oportunidade de misturar animações entre si, não temos cinemática inversa e recursos semelhantes inerentes apenas ao esqueleto. Mas temos cronogramas aninhados um no outro, bem como máscaras de varredura e vetor! Todos os animadores adoram máscaras! Aqui, vale ressaltar que no Spine, surgiram muito recentemente recursos de recorte , mas até agora apenas geométricos e muito limitados em comparação com máscaras de flash.
Resumo do Tipo de Animação
Naturalmente, não listei todos os tipos de animações, apenas as principais. Por exemplo, as chamadas animações processuais foram deixadas para trás, quando objetos ou seus fragmentos são acionados apenas por código, mas não é possível contrastá-los com outros, e eu realmente não queria inflar o artigo, é melhor ver algo mais especializado em animações para completar a imagem.
Para resumir. Não há bala de prata, como sempre e em quase tudo. Você precisa escolher o projeto, tarefas e pessoas. Afinal, ninguém restringe ninguém a usar um tipo de animação. Em todos os lugares existem projetos em que todos os tipos de animações são usados ao mesmo tempo e todos estão felizes. Cenas - vídeo, personagens - esqueleto, cenário - linha do tempo, vôos de emissores de sistemas de partículas - procedurais, as próprias partículas em seus sistemas - quadro a quadro. Tiramos o melhor de cada tipo.
A agonia da escolha e a decisão de escrever sua própria
Bem, por algumas razões objetivas, decidimos que precisávamos de animações em flash para o nosso projeto. Surgiu a questão de integrá-los ao mecanismo. Depois de experimentar várias opções de plug-ins, decidimos por um que nos adequasse às suas capacidades, estivesse ativo e em suporte, e também tinha um preço completamente indecente para uma licença entre licenças, mas você pode tolerar um bom produto. Intencionalmente, não cito nomes, para não fazer publicidade ou anti-publicidade a ninguém.
Com este plugin, vivemos quase um ano de desenvolvimento, durante o qual os detalhes foram esclarecidos, que não pudemos usar mais. Ou seja, a qualidade de sua integração no Unity. Tudo isso resultou em erros francamente graves que não se pode dizer que são fáceis, rápidos e sem uma luta reparada por parte dos desenvolvedores, e com um desempenho terrível nos dispositivos de destino, e ainda temos o nível do iPad 2 . Isso aconteceu devido à integração analfabeta em um mecanismo específico, à ignorância de suas especificidades e armadilhas, e ficamos mais do que satisfeitos com as possibilidades, mas os códigos-fonte, mesmo em ordem pessoal, recusaram-se a abrir e foi decidido escrever nossa decisão.
Tive uma experiência bastante bem-sucedida ao escrever extensões para o Unity e tive pouca experiência em converter animações em flash para meus formatos. Este último foi há muito tempo, mas algo foi lembrado. No mesmo local, foi decidido escrever tudo como um projeto doméstico, para não depender do projeto ou da empresa em que trabalho e, para ser sincero, também queria ter meu próprio produto. Então, armado com uma especificação de formato swf de 250 páginas, fui para a batalha.
Opções de exportação
Para começar, vale a pena discutir opções para exportar animações do editor de flash. Existem vários deles, naturalmente com seus prós e contras. Vamos passar pelos principais.
Formato .xfl
No editor de animação em flash, é possível salvar a fonte da animação em um formato .xfl não compactado, em vez do formato .fla fechado, oferecido por padrão. O formato é bastante simples, mas não documentado. Ele consiste em vários diretórios aninhados e um monte de arquivos .xml, onde são descritos todos os estados dos clipes armazenados. O formato da descrição também é simples e claro, aqui está um exemplo:
static_clip.xml
<DOMSymbolItem name="static_clip" itemID="5c719f28-00000051" lastModified="1550950184"> <timeline> <DOMTimeline name="static_clip"> <layers> <DOMLayer name="Layer_1" color="#00FFFF" current="true" isSelected="true"> <frames> <DOMFrame index="0" keyMode="9728"> <elements> <DOMBitmapInstance selected="true" libraryItemName="bitmap.png"/> </elements> </DOMFrame> </frames> </DOMLayer> </layers> </DOMTimeline> </timeline> </DOMSymbolItem>
Link para a fonteAqui temos um clipe estático static_clip
com uma camada Layer_1
e um quadro, no qual existe um bitmap chamado bitmap.png
.
movie_clip.xml
<DOMSymbolItem name="movie_clip" itemID="5c719f30-00000053" lastModified="1550950713"> <timeline> <DOMTimeline name="movie_clip"> <layers> <DOMLayer name="Layer_1" color="#00FFFF" current="true" isSelected="true"> <frames> <DOMFrame index="0" duration="4" tweenType="motion" motionTweenSnap="true" keyMode="22017"> <elements> <DOMSymbolInstance libraryItemName="static_clip"> <matrix> <Matrix tx="-50" ty="-50"/> </matrix> <transformationPoint> <Point x="28.5" y="27.5"/> </transformationPoint> </DOMSymbolInstance> </elements> </DOMFrame> <DOMFrame index="4" tweenType="motion" motionTweenSnap="true" keyMode="22017"> <elements> <DOMSymbolInstance libraryItemName="static_clip" centerPoint3DX="128.5" centerPoint3DY="127.5"> <matrix> <Matrix tx="100" ty="100"/> </matrix> <transformationPoint> <Point x="28.5" y="27.5"/> </transformationPoint> </DOMSymbolInstance> </elements> </DOMFrame> </frames> </DOMLayer> </layers> </DOMTimeline> </timeline> </DOMSymbolItem>
Link para a fonteAqui, descrevemos o clipe de animação movie_clip
, que contém dois quadros-chave com os índices 0 e 4, respectivamente. Os quadros contêm nosso clipe estático static_clip
nas coordenadas (-50;-50)
e (100;100)
. Entre os quadros, há interpolação de movimento (animação procedural, no nosso caso, é apenas uma transferência, sem escala e rotação), respectivamente, a posição de um clipe estático entre os quadros-chave pode ser obtida pela interpolação linear de coordenadas desses quadros.
Naturalmente, tudo estará em animação real, ahem ... um pouco mais complicado e mais volumoso, mas você pode descobrir tudo sem documentação. Parece que aqui é felicidade. E conheço vários projetos e empresas que foram bem-sucedidos nesse caminho, mas com algumas limitações e dificuldades. Essas dificuldades são a mosca na pomada .xfl, a saber:
- Os pré-adolescentes (pré-adolescentes, russificados quanto possível) são muito diferentes, simples: com interpolação linear e mais complexos: com funções definidas pelo usuário e gráficos dessa interpolação, transformando gráficos vetoriais em gêmeos, com suas próprias regras apenas para macromedia e adobe;
- Os gráficos vetoriais, como todas as animações, exceto os gráficos de varredura, são descritos em forma de texto, por exemplo . Portanto, é necessário escrever seu próprio rasterizador, o que, devido às complexidades e características do vetor em flash, não é possível na prática;
- As regras para reproduzir animações, incluindo as aninhadas, você precisa pensar a partir do zero, não há documentação para ela e quando o quadro deve ser mostrado, o que ajustar em quais situações e o que deixar sem interpolação - ele ainda precisa ser determinado por longas experiências, tentando cobrir todos os casos possíveis. execuções de teste, que são um exercício não trivial para uma solução geral, e não privada.
Essas não são todas as dificuldades dessa abordagem, mas são suficientes para entender que, para uma solução geral, ela é adequada apenas com fortes reservas. Era uma vez o caminho para um dos projetos em que participei. Havia cenas cortadas com flash, com gêmeos clássicos (sem regras de interpolação personalizadas e funções especiais dessa interpolação), apenas gráficos de bitmap e sem outros recursos avançados que o editor de flash fornece. A solução privada foi escrita com bastante rapidez e eficiência, mas os animadores tiveram que ser severamente limitados para não usar nada mais ou menos complicado. A abordagem tem direito à vida e existem várias bibliotecas, com diferentes graus de negligência, baseadas nela, mas, como eu disse, com muitas reservas e limitações.
Scripts .jsfl
Outra opção, quase funcionando, é obter informações sobre nossas animações. O jsfl-scripts permite expandir o editor de flash, interagir com o ambiente, alterar a animação e, é claro, obter todas as informações necessárias sobre linhas de tempo, camadas, clipes e quadros neles. E também é usado pelos animadores para automatizar várias ações, mas essa é uma história de um livro vizinho. Em geral, a abordagem é dotada de todas as desvantagens da abordagem anterior, então não vou me deter nela, só posso dizer que com ela é possível descarregar toda a animação na forma de, por exemplo, animação quadro a quadro, e esse não é o caminho de um Jedi real (mas, naturalmente, ocorre em alguns projetos). Voltaremos a esses scripts da maneira que escolhi: rasterizar gráficos vetoriais e otimizar a animação paginada.
Aplicativo AIR
Mas essa abordagem já está funcionando e pode ser usada como deveria. Eu não o escolhi, mas como referência darei essa opção. A essência da abordagem é que criamos um aplicativo AIR no próprio flash ou, para os estetas, no Haxe , por exemplo, que obterá todas as informações de uma animação já compilada em um formato swf. Reproduzimos a animação quadro a quadro dentro de nosso aplicativo, obtemos todas as informações do quadro e as salvamos no formato que precisamos para nosso tempo de execução. Aqui todos os problemas acima são resolvidos:
- não é necessário rasterizar gráficos vetoriais, o flash runtime fará isso por nós; resta apenas obter essas informações e salvar o resultado da varredura de fragmentos vetoriais;
- não é necessário criar regras e lidar com interpolação dupla personalizada, o flash player dentro do aplicativo AIR sabe exatamente como fazer isso e fará quase tudo por nós;
Como bônus, temos a oportunidade de usar scripts de quadros em animações (todos os tipos de play()
, stop()
e outros gotoAndPlay()
, alguns animadores os amam muito). A desvantagem é a incapacidade de exportar as animações em loop para o próprio flash, mas isso não importa, já que você já pode executá-las em seu tempo de execução e pedir aos animadores que preparem tudo para isso.
Vale ressaltar que tenho certeza de que tudo será um pouco mais complicado do que parece na minha descrição, já que eu pessoalmente não fui lá, então não posso lhe contar os detalhes. Que aqueles que passaram por esse caminho compartilhem suas experiências, com prazer lemos sobre suas alegrias e tribulações!
Próprio flash player
Esta é provavelmente a opção mais honesta, óbvia e direta de todas, mas também a mais difícil. No final, é isso que um flash player real faz, que a maioria de nós possui em nosso navegador favorito como complemento. Representantes populares desse gênero: gameswf e, crescidos a partir do anterior, scaleform . Ambos agora estão mortos. É interessante que eles foram usados principalmente para implementar a GUI em vários projetos, incluindo AAA . Mas estamos interessados na estrutura interna, não nas aplicações específicas de bibliotecas mortas.
Qualquer flash player que se preze tem pelo menos o seguinte:
- analisador de formato swf;
- gráficos vetoriais de rasterizador;
- implementação de uma máquina virtual para executar o código do ActionScript ;
- implementação de uma biblioteca padrão para código de usuário;
Cada um desses pontos fala sobre o que é possível implementá-lo, então você terá que mudar mais de uma equipe para esta tarefa e trocar vários anos de desenvolvimento para a versão mínima. Mesmo a implementação de uma pequena parte, suficiente para desempenhar alguma coisa, levará muito tempo, e as dificuldades adicionais, na forma de tantas partes não documentadas de todo esse pipeline, dobrarão esse período já imenso.
Sim, a rede está cheia de tentativas de implementar cada uma dessas partes, com vários graus de negligência e agravamento. Mas nem mesmo é possível tomar esses desenvolvimentos como base, apenas levará anos para detectar bugs e escrever testes de unidade não escritos antes de perceber que não funcionará em toda a extensão. Aqueles que tentaram complementar o gameswf com os recursos necessários entendem do que estou falando. Um flash-player honesto também precisa rasterizar gráficos vetoriais com antecedência, mas em tempo de execução, o que afetará um desempenho tão grande que nem todo projeto pode sobreviver. Aproveito esta oportunidade para expressar meus cumprimentos aos sobreviventes que usaram o scaleform em dispositivos móveis. Em geral, o caminho mais sombrio e sem esperança, não a nossa escolha.
Combinamos abordagens
Então finalmente chegou à minha opção. Tendo estudado os caminhos possíveis, uma combinação interessante foi desenhada para mim. De implementação relativamente simples, viável para uma pessoa em volume e ao mesmo tempo funcional o suficiente para atender às necessidades da maioria das animações em 2D da linha do tempo.
Primeiro, usaremos a animação compilada no swf para não oferecer várias opções de reprodução e quase nunca adivinhar como o flash player funciona por dentro, pois não podemos cobrir todos os casos possíveis, mas tentamos escrever uma solução geral. Além disso, o editor de flash se livra de todos os gêmeos que foram usados na animação, representando inteligentemente, no swf compilado, as posições nuas dos fragmentos.
Em segundo lugar, proibimos o uso de scripts em animações. Sim, esse é um requisito muito difícil e triste, mas não tenho uma equipe de programadores para implementar uma máquina virtual honesta e uma biblioteca padrão que precisaria escrever quase cegamente. Aqui, é claro, o menos da minha abordagem é visível em relação à abordagem em que o aplicativo AIR foi usado, pois, no último, alguns scripts para reprodução de animação interna poderiam ser usados. Por outro lado, isso não interfere na criação de boas animações. Para transferir informações personalizadas da animação para o jogo, você pode usar os chamados frame labels
, que serão visíveis no código, além de suspender eventos personalizados em quadros específicos, na forma de funções de retorno de chamada que já estão em tempo de execução.
Em terceiro lugar, nos livramos de escrever nosso próprio rasterizador de gráficos vetoriais, pela incapacidade de escrever um para o caso geral, para cobrir todas as opções e recursos do vetor em flash. Em vez disso, rasterizaremos os gráficos para a compilação (!) Usando um script jsfl. Ao mesmo tempo, com a ajuda desse script, otimizaremos nossos gráficos vetoriais mesclando clipes estáticos em uma imagem, reduzir ou aumentar as imagens de bitmap resultantes para nossas necessidades: qualidade e / ou desempenho. Aqui também vale lembrar as várias opções de qualidade / resolução da arte para dispositivos com diferentes densidades de pixel na tela (por exemplo, arte em HD e SD).
A conclusão da parte lírica
Isso conclui a primeira parte do artigo. Na segunda parte, haverá detalhes técnicos de implementação, partes de código, figuras (!), Otimizações, truques e truques. Em breve em suas telas, não perca! No final, darei alguns links interessantes com informações sobre o uso de animações em flash de colegas, felizmente do ZeptoLab e Playrix .