GameFreak Sempre Aperta B

Ou “Por Que Pokémon Podia (e Devia) Ser Melhor”

Gostaríamos de começar esse texto com um pequeno caveat: Nós adoramos Pokémon. Sério. Jogamos desde a época em que EVs eram invisíveis e Pokémons Psíquicos não tomavam dano de Pokémons Fantasma (e milhões de crianças se revoltaram com o anime). O jogo encantou nossa geração e sempre que lançam um novo, fazemos questão de jogar.

Agora que tiramos isso do caminho, podemos começar: Mesmo com todos os seus méritos, Pokémon é um jogo ruim. Ok. Não é um jogo ruim. Vamos frasear de uma maneira mais coerente.

Pokémon deveria ser um jogo muito melhor.

“Time que tá ganhando não se mexe.” você justifica. “Dá dinheiro do jeito que tá!” Não ligo. Sou usuário e desenvolvedor, não empresário. Meu dever é fazer ficar melhor. As cifras são consequência.

Do ponto de vista de desenvolvimento de jogos, é impressionante como a GameFreak é parecida com o Ash no que diz respeito a ela ter algum problema muito sério com evolução. Da mesma maneira que mesmo depois de mais de 849 episódios e 18 filmes o Ash continua com o mesmo Pikachu e tem um histórico coerente de libertar, libertarlibertar todos os seus pokémons evoluídos, a GameFreak parece padecer do mesmo mal.

magik

Isso é como Pokémon XY se parece.

Depois de 6 gerações de jogos (9, se contarmos os Remakes), ao invés de buscar mudanças construtivas e melhorias em seus jogos, a GameFreak segue uma fórmula enfadonha e repetitiva: adicionar mais pokémons. E parece que essa fonte está secando – desculpa, Klefki, você tem um design escroto.

NINGUÉM FALA DO ROTOM. O ROTOM É ÓTIMO.

rotom

VOOOSH

Além disso, cada geração herda os problemas da anterior. Eles certamente parecem se esforçar para melhorar o balanceamento do jogo – acrescentar 50 personagens novos e não quebrar o jogo inteiro não é uma tarefa fácil – mas exceto isso, o jogo fica cada vez mais carregado de probleminhas residuais.

soil

SIM, CARALHO.

Péssimos vícios de interface de usuário, artificial lengthening (breeding e hatching não precisavam ser tão demorados e repetitivos), informação complexa totalmente inacessível (sério, quando foi a primeira vez que você ouviu falar de IVs, EVs e como manipulá-los?) e, por último, e o assunto que estaremos desenvolvendo aqui: Um péssimo, péssimo level design.

Prepare-se Para Encrenca!

Quem não adorava a Equipe Rocket do anime? Eles eram fracos, trapaceiros, carismáticos e todo mundo adorava ver eles quebrando a cara.

Você sente essa mesma afeição pela Equipe Rocket dos jogos? Ou melhor, pela Team ~Rival~ da vez?

Enquanto no anime eles faziam o papel de alivio cômico, no jogo a proposta é que a Team Rival seja um desafiante forte, que interrompa a trama principal repetitiva – capture pokémons, fique forte, derrote o ginásio, repita mil vezes – com um desafio extra. A Team Rival, seja na primeira ou na sexta geração, tem o papel de ser uma força de anarquia. E eles não são.

O objetivo de um antagonista em uma história é apresentar um desafio para o jogador. Como Pokémon é sobre desafios – derrotar a Elite 4 -, nós já temos um antagonista forte, mas ele não é um vilão. O objetivo do vilão, papel que a Team Rival tenta preencher, é apresentar um conflito urgente e altruísta – diferente do egoísmo da jornada do mestre pokémon. É reforçar a vitória do bem – o herói – contra o mal – a Team Rival – e conferir um sentimento de legitimidade à jornada do jogador. Ele não está derrotando os ginásios só por motivos egoístas; ele quer ficar forte para poder defender os ideais nos quais ele acredita.

Porém, a marca da personalidade dessas equipes em todos os jogos se resume a usar pokémons “malvadinhos”, algo insinuado mais pelo seu typing (dark ou poison é quase obrigação) e design do que pelas suas estratégias. Como suas estratégias são exatamente as mesmas, eles se tornam um obstáculo ordinário, nada diferentes das multidões de Bug Catchers e Ace Trainers.

Eles carecem de personalidade e identidade. São um péssimo coadjuvante pois tentam ser vilões e são péssimos vilões pois se comportam como coadjuvantes. Sua vilania não se traduz em estratégias de combate traiçoeiras – salvo pela frequência óbvia do uso de veneno, que só se deve ao typing – ou por ações de roteiro interessantes. Ao invés da organização terrorista imoral que os outros personagens descrevem, acabam não passando de bullies de recreio.

37nUbyc

Quando um bom vilão ganha, você fica feliz. Quando ele apanha, também.

Ao invés de cumprir com o objetivo proposto, a Team Rival acaba se tornando apenas uma “muleta” narrativa. Sua única função é apontar qual a direção na qual o jogador deve seguir quando ele não sabe bem o que fazer. Eles não cumprem o seu objetivo de narrativa embutida, que é ser uma força emergente e atuante no mundo pokémon.

E eles são tão fracos! Da mesma maneira que não diferem de coadjuvantes em sua personalidade, eles também não oferecem nenhuma dificuldade extra ao jogador ou exigem uma nova maneira de jogar o jogo. Dando continuidade às mesmas estrategias que usava contra os desafiantes na estrada, o jogador consegue derrotar sem dificuldade qualquer um dos capangas da Team Rival.

Ou seja: o objetivo de narrativa emergente também não é cumprido.

squirtle

Então, como nós achamos que isso devia ser feito?

Encrenca em Dobro!

Um dos paradigmas de como se contar uma boa história pode ser resumido na frase “Show, don’t tell” (“Mostre, não conte”). Em jogos eletrônicos, onde o jogador encarna o personagem, a atenção a essa frase deve ser redobrada.

Tornar as atitudes e intenções da Team Rival mais malignas de maneira expositiva – fazendo com que fossem mais cruéis e trapaceiros durante a narrativa – não teria grande efeito no seu impacto caso a maneira como ela é tratada em seu gameplay permanecesse intocada. Além de tratar apenas um sintoma, isso poderia facilmente descarrilhar em um spectacle creep. Algo que deveria ser mais explorado – não só com a Team Rival da vez, mas usando-a como ótimo exemplo – é o fato de que Pokémon é um jogo estratégico.

E se toda a vez que o jogador encontrasse membros da Team Rival, eles tivessem sempre uma carta na manga? Uma trapaça, um golpe baixo, algo que lhe pegasse desprevenido e forçasse o jogador a se adaptar na hora?

Dessa maneira, ao invés de contarmos ao jogador como a Team Rival é malvada, tornando a história mais chocante, nós podemos mostrá-loAlterando o comportamento – a inteligência artificial – da Team Rival no momento em que ela se encontra em conflito direto com o jogador – durante a batalha pokémon -, faria com que o jogador sentisse na pele toda a sua arguta e vilania dentro do contexto do jogo.

Eles não seriam só vilões traiçoeiros. Seriam vilões que estão sendo traiçoeiros com ele. Além disso, seria uma ótima oportunidade para ensinar o jogador a como enfrentar esse jogo sujo. E até mesmo como usá-lo.

Alias, isso é level design.

Fizemos alguns exemplos usando o Pokémon Showdown. Quer ver só?

Wobuffet com Counter

Wobuffet tem habilidades que evitam que seu adversário possa trocar de pokémon, forcem-no a usar o mesmo golpe várias vezes seguidas e – a cereja no bolo – dois ataques que devolvem o dano recebido por Wobuffet em dobro ao seu oponente: Counter e Mirror Coat. Um Wobuffet com bons atributos defensivos pode colocar em cheque um time muito forte. É uma estratégia muito irritante, algo que reforçaria a personalidade da Team Rival. Como derrotar? Ele é vulnerável a Status que dêem dano residual como poison, burn, &c.

Noibat com Switcheroo

Lagging Tail é um item que faz com que você aja por último em batalha, independente de quão rápido você é. Péssimo, né? (Ou ao menos terrívelmente circunstancial). Mas há alguns golpes, como Switcheroo ou Trick que podem trocar o item do seu pokémon com o do seu adversário, deixando-o prejudicado até o final da batalha, visto que não é possível modificar itens equipados durante um combate.

Dual screeners

Light Screen e Reflect reduzem o dano recebido e se mantém ativas mesmo depois de trocar de pokémon. Uma vez que alguém consegue preparar o campo com essas duas habilidades, seu time fica muito resistente, mas é uma estratégia que demora até ser concluída, o que a torna evitável se você agir rapidamente. 

 

Viram?

E esse problema persiste já fazem seis gerações. SEIS GERAÇÕES.

Nós entendemos que a proposta de Pokémon não é ser um jogo difícil. Mas pokémon é um jogo de estratégia! Até pouco tempo atrás, vários sistemas que já existiam desde as primeiras gerações eram apenas informações escondidas do jogador, e o jogo não explicava, introduzia ou sequer dava pistas de qualquer um deles.

Não defendemos que todos os integrantes do Team Rival devessem abusar desse tipo de tática. Isso poderia aumentar a dificuldade do jogo a um nível intolerável. Porém, quem utilizasse esses recursos poderia recompensar o jogador com o item ou golpes que foram aplicados naquela batalha, permitindo de fato que o jogador explorasse o que acaba de ver e se sentisse mais competente ao invés de apenas mais forte.

Ao mesmo tempo, é possível gastar menos tempo discutindo as intenções malignas do Team Rival. Se eles batalham como vilões, eles são vilões. Sua persona reflete a anima.

O mesmo princípio deveria ser aplicado a líderes de ginásio e até aos desafiantes na estrada (mas não todos, para não desvalorizar a ocorrência de táticas ricas durante o jogo). Tipo-inseto poderia diminuir sua velocidade a níveis insuportáveis ou usar um Shedinja. Tipo-água poderia abusar de Rain Dance e pokémons que se beneficiem de efeitos climáticos.

shedinja

Eu tenho 1 HP, mas só tomo dano do que é super-efetivo contra mim.Você não sabe o que é super-efetivo contra mim? Que pena.

Isso provoca os jogadores a serem mais criativos e a estudarem o jogo um pouquinho mais. Eles têm que pensar rápido para superarem jogadas que os peguem de surpresa. Criatividade nesse sentido, inclusive, seria algo ótimo para o cenário competitivo que têm repetido os mesmos times e estratégias seguidamente. (zzZZzzz…).

Mesmo com todos os defeitos que tem, Pokémon é um jogo riquíssimo. Ele tem um cenário competitivo divertido e uma comunidade incrível. Boa parte dos sistemas do jogo foram garimpados por essa comunidade, e isso é parte do que fez a franquia se sustentar ao longo dos anos.

Não queremos tirar o mérito da GameFreak! Quando Pokémon foi criado, a indústria ainda não tinha uma idéia muito clara sobre o que era game design e as coisas que fazem um jogo ser um bom jogo, e ainda assim foi febre no mundo inteiro. Arrisco dizer que Pokémon foi responsável por 90% das vendas de Game Boy aqui no Brasil. Mas desde então o mercado evoluiu muito – mais importante, os jogos evoluiram muito, aprendendo com outras áreas de conhecimento e refinando os conceitos do que é um bom jogo.

Nas últimas versões é perceptível o esforço da GameFreak de dar uma repaginada em alguns conceitos antigos – expondo os EVs pela primeira vez desde o começo da franquia, por exemplo. Porque não ir um pouquinho mais longe?

rotom_eye

Shuhari e por quê parar de seguir pessoas de sucesso

Em um post super intrigante no Medium, o Gustavo Tanaka fez um ponto sobre por quê deixar de acompanhar as jornadas e história de pessoas de sucesso:

https://medium.com/@gutanaka/por-que-parei-de-seguir-as-pessoas-de-sucesso-124e837aa2f7

Imediatamente me lembrei de um conceito de artes marciais que fala muito sobre como precisamos muitas vezes passar por um período onde conhecemos a jornada dos outros, as regras tradicionais para se obter sucesso, para pouco a pouco superá-las em estágios:

Shuhari (守破離) é um conceito de artes marciais japonesas que descreve os estágios pelo qual alguém passa ao adquirir maestria:

Shu: Em um primeiro momento se domina a forma tradicional, por repetição, até que ela vire um reflexo quase mecânico
Ha: Já familiar com os fundamentos, adicionamos nossa própria interpretação, ainda que isso quebre com a estrutura da forma tradicional
Ri: Transcende-se a forma, a criatividade sobre o conteúdo dominado permite usar o conhecimento de novas maneiras. Os princípios que fundamentam a forma são naturais, e não há esforço envolvido para aplicá-los seja de acordo com ou quebrando a forma tradicional.

https://en.wikipedia.org/wiki/Shuhari

Não ficar preso na mesma etapa pra sempre é tão importante quanto não pular nenhuma.

JavaScript – uma linha do tempo

Juntei acontecimentos que eu julguei interessantes para o crescimento da linguagem e botei em uma linha do tempo que vocês podem conferir abaixo, ou em tela cheia aqui! Dá pra ter uma idéia de como chegamos onde chegamos, e pra onde estamos indo. Cliquem nas setas nas laterais pra passar slide por slide ou cliquem e arrastem na linha do tempo ali em baixo pra navegar pra onde quiserem. Como sempre, os links são 90% da diversão do negócio. Vale observar atentamente acontecimentos que levaram um ao outro. A declaração do Facebook dizendo que HTML5 é lento, a Sencha implementando uma versão HTML5 do app do Facebook rodando rapidíssimo, e logo em seguida, o Facebook lança React. Ou a popularização do ajax depois do lançamento do gmail, por exemplo. Ou o surgimento de javascript isomórfico na mesma época que havia uma preocupação com reaproveitar código entre browsers (definição de ES5) e entre dispositivos (PhoneGap), e logo após nodejs ser lançado. Estou trabalhando em um jeito de deixar essas informações open-source pra quem quiser colaborar, editar, etc, mas ainda não está pronto! No meio tempo, me mandem um comment que eu edito!

Contribuições:
Thomas Paula
Rafael Gomes Dantas

React.js e como javascript escreve certo por linhas tortas

Do que se trata?

React.js é um framework em javascript escrito pelo Facebook para a construção de UIs, que recentemente tomou o mundo de assalto. Ele facilita a vida dos desenvolvedores, arrumando problemas que são reclamações constantes de quem trabalha com javascript. Mas será que não estamos frameworkizando um negócio que deveria ser solucionado de outra forma?

O tom messiânico no qual React é referido impressiona:

Facebook just taught us all how to build websites – Gyroscope Innovations

São afirmações pesadas. O design do framework é impressionante, mas vamos dissecar o que ele faz para resolver alguns dos problemas que ele se propõe a atacar.

Que problemas React resolve?

Virtual dom

O React usa um esquema onde ele acumula todas as modificações que deveriam ser feitas no DOM em uma árvore em memória, e depois que todos as consequências do código que está sendo executado atualmente (eventos, callbacks, etc) terminarem – ou seja, quando o event loop for liberado – aí sim ele vai lá e faz todas as mudanças de uma vez só. Tem uma explicação muito boa de como isso acontece por baixo dos panos aqui, pra quem tiver interesse.

O ponto é: o DOM não é lento. Para o trabalho que ele se propõe a fazer, ele é surpreendentemente rápido, só que a maioria das pessoas não entende o que ele faz. Dizer que o DOM é lento é tão estúpido quanto dizer “operações de IO são lentas”. Lentas em relação ao quê? Manipulação de valores em memória? A diferença é que elas fazem muito mais coisas do que manipulação de valores em memória. O problema do DOM é que modificá-lo programaticamente é muito fácil, então as pessoas tendem a fazer isso com uma frequência muito maior que a recomendada.

Em geral, se a pessoa está encostando no DOM o mínimo possível e ele continua lento, é por causa de um dos seguintes motivos:

  1. Seu CSS é uma bela bosta. Sério, é muito fácil fazer regras que sobrescrevem umas as outras e geram milhares de reflows.
  2. Você está fazendo coisa demais em javascript. O número de vezes que eu já vi controles que já estão implementados em HTML (checkboxes, radiobuttons, etc) programados em javascript… não dá pra contar.
  3. Você tem coisa demais na sua árvore. É o típico caso em que o cara vai lá e cria 2 divs dentro de uma div “porque não tinha outro jeito de alinhar as coisas do jeito que ele queria”. Apenas pare.

Acumular as modificações que deveriam ser feitas no DOM até o final do event loop é, de fato, uma boa prática. O que o React faz é tornar isso transparente para o desenvolvedor. React faz com que acumular mudanças no DOM para realizá-las todas de uma vez seja mais fácil do que modificar o DOM diretamente. Ele arruma um problema de design. Não de performance.

Aí eu me pergunto, pela primeira vez nesse post: e se isso fosse arrumado em uma camada mais baixa? E se o browser nos oferecesse mecanismos para um controle mais fino dos eventos de reflow/repaint provenientes de operações sobre o DOM? Será que estamos tratando isso no nível correto?

Componentes

Cara, imagina que beleza: tu vai lá no teu HTML e poe assim:

E aí PÁ teu browser substitui isso tudo por uma estrutura toda em HTML que descreve uma lista de tarefas, inclui um CSS que mostra isso bonitinho, e importa os javascripts necessários pra fazer a lista funcionar.

Isso são web components. É uma spec em desenvolvimento, um padrão aberto. E tem vários frameworks por aí que atacam esse problema. Polymer, Angular, Ember, etc. Os problemas? Isso gera uma cacetada de imports que vão virar mais requests, mais volume de dados, a compatibilidade dos browsers pra lidar com isso não está exatamente estável, etc.

React propõe um design onde o HTML para renderizar um componente possa ser colocado dentro do arquivo javascript que conhece ele:

Essa é a parte que me deixa empolgado. Os caras lá do Facebook nos mostram o seguinte: Separar HTML de javascript não é separação de responsabilidades. É separação de tecnologia. Estamos usando as duas coisas para gerenciar views. Se a gente se dispor a abraçar o capeta, a gente tem menos imports, menos acoplamento (só quem conhece o HTML de um componente é ele mesmo) e de quebra sai da herança maldita do Rails onde os componentes eram destripados entre 3 pastas diferentes.

A implementação disso por debaixo dos panos ainda não é 100%, o suporte dos browsers em relação a isso continua complicado, e ainda usamos gambiarras pra poder escrever um código um pouco melhor. React arruma um problema de arquitetura aqui. Não de implementação.

O ponto é: se há um padrão aberto disponível, será que não estamos resolvendo isso no nível errado? Será que não deveríamos tornar tarefa dos browsers a resolução de web components de acordo com o padrão sendo desenvolvido? Será que no futuro isso não vai ser desnecessário?

Adaptadores de código nativo

O pessoal do Facebook anunciou nessa semana o React Native para iOS e Android. É possível abstrair componentes nativos (sliders, botões, eventos de toque, etc) em código javascript usando React, e fazer o mesmo código (ou quase o mesmo) funcionar em seu aparelho favorito.

Tenho opiniões divididas sobre esse tópico:

Em relação a ter código que pode ser usado em plataformas diferentes, a motivação disso é clara, e já não estamos na primeira geração de tentativas de resolver esse problema. Flash, Java, .NET, PhoneGap, Titanium… Como contraponto de adaptar componentes nativos para serem usados em JS, temos o que o FirefoxOS está fazendo, de expor APIs com controle de autorização para serem usadas no browser. Se isso fosse um padrão, o que mudaria na nossa forma de desenvolver?

Voltando um pouco ao ponto de componentes: se Web Components estivesse mais estável, poderíamos ter componentes que tem o mesmo aspecto visual de componentes nativos do iOS ou Android, e várias aplicações poderiam compartilhar o mesmo código, a mesma rede de distribuição desses scripts (CDN), o mesmo cache, etc. Será que haveria necessidade de termos essa camada de adaptação JS <-> Nativo?

Será que estamos resolvendo isso na camada certa?

Como JS progride

A parte mais interessante desta pergunta é que resolver as coisas na camada errada em javascript em geral não é um problema: é um arauto de mudança.

Depois da popularização em massa de jQuery com seus seletores, document.querySelector e document.querySelectorAll foram adotados em larga escala nos browsers e hoje são um padrão.

É bacana encarar essas formas de arrumar problemas de design e arquitetura do ecossistema onde desenvolvemos aplicações para a web como uma forma de sugerir melhorias que eventualmente sejam transferidas ao nível mais eficiente. Já aconteceu antes. Acontecerá de novo.

O React se posicionar como um framework faz todo o sentido do mundo para o Facebook, que já tem uma aplicação que é o caso de uso perfeito (coincidência? o que será que veio primeiro? a aplicação ou o framework? haha :P). É necessário olhar friamente as features que React nos oferece e ver o que faz sentido dentro da nossa aplicação. Sempre é possível fazer mais com menos.

A arquitetura e o design do React são de fato uma obra de arte, e ele merece essa admiração. Mas o fato das funcionalidades virem embutidas como um framework é limitante em relação às formas que as pessoas podem adotar as técnicas que React propõe em suas aplicações.