Arquivo da categoria: Programação

Todos Saúdem os Senhores Robô

Os computadores vão criar consciência própria e assumir controle total de pelo menos 80% das nações até 2143. Escrevam o que eu estou dizendo. Vou explicar meu raciocínio todo que me leva a essa conclusão e qualquer um, mesmo leigo no assunto, vai concordar comigo no final das contas.

Tudo começa com uma historinha que explica bem como o que hoje conhecemos por inteligência artificial funciona.

O Quarto Chinês

Dentro de um quarto fechado tem alguém que possui um guia infinitamente grande de todas as possíveis frases que alguém pode falar em chinês (ok, mandarim, que seja), e respostas apropriadas a essas frases. Um cara que fala mandarim fluentemente escreve algo em um pedaço de papel e passa por debaixo da porta. Após alguns minutos, outro papel volta com uma resposta apropriada escrita também em chinês. Mesmo que a pessoa dentro do quarto não faça a menor ideia do que esteja fazendo, e só esteja procurando as frases no seu super-guia e copiando os ideogramas, para todos os efeitos parece que ela fala chinês.

Quando um computador assume comportamentos inteligentes, ele também não faz a menor ideia do que está acontecendo. Ele está associando a situação que ele percebe com algo que ele julga como “uma resposta adequada”, nos mesmos moldes da historinha acima.

Em uma observação interessante: nem quem é da área sabe ao certo o que está acontecendo em relação a como a máquina cria essas associações. Inteligência artificial por redes-neurais, um dos métodos usados pra criar esse efeito de super-guia, é um dos mais difíceis de depurar.

Ah, mas Diogo, tu está considerando um super-guia infinito de conhecimento nesse teu raciocínio, não tem como ter isso. Bom, armazenar informação é algo que se torna cada dia mais barato. Vamos relembrar que um disquete antigamente guardava 1.44MB de dados, e hoje em dia o pendrive mais vagabundo da história guarda 8GB (quase 5700 vezes mais). A técnica do super-guia é tão factível que já é aplicada por coisas com as quais você interage diariamente:

O Google Translate pode a partir de várias traduções tentar chegar em uma frase que se aproxima muito bem do significado que você quer, e isto é bastante inteligente. Mas e se a gente pedisse pro google translate traduzir uma linguagem esquecida, algo que sequer nós humanos conseguimos traduzir?

IA Específica vs. IA Geral

Não. O programa do Google Translate é baseado no super-guia, certo? Então se estamos tratando de uma linguagem que ninguém conhece, ela não pode estar no super-guia. Mas já houveram ocorrências em que programas bolados para tentar encontrar padrões em dados não-organizados já descobriram regras gramaticais em linguagens perdidas. É o mesmo tipo de programa que analisa genomas. Ele percorre uma cadeia imensa de AUTACGTAAUCG e compara com a informação que ele conhece do portador daquele DNA, e começa a descobrir coisas tipo: toda vez que aparece TACG aqui nesse trechinho da cadeia de DNA, o sujeito é uma mulher. 

AHÁ! O computador aprende essa regra e agora podemos aplicar isso em várias outras coisas. O computador está se auto-ensinando regras novas conforme ele avança, parecendo ficar mais esperto. Só que não é um “AHÁ”. A cada cadeia de DNA que respeita esse comportamento, ele aumenta a sua tendência a adivinhar que o sujeito é mulher. Pouco a pouco, a associação entre aquele montinho de proteínas e o fato de que trata-se de uma dama vai se fortalecendo. Quando digo auto-ensinar, não é que o programa está se reescrevendo e mudando seu próprio comportamento. Ele aumenta a sua predileção por vincular um conjunto de informações com uma resposta. A resposta vai ficando mais e mais “adequada” no entendimento dele. De maneira simplificada, em um programa que joga xadrez, com base na avaliação do tabuleiro contra todo o super-guia de possibilidades de jogadas que ele tem, isso acontece:

pcvspessoa
Arnold humano contra Arnold T-800 cheio de inteligência artificial na partida de xadrez do século

Eventualmente, se a máquina se depara com uma situação que ela não conhece, ela vai tentar executar uma jogada, e vai passar a monitorar quanto sucesso ela tem ganhando jogos usando essa jogada. E aí ela entra pra estatística, aumentando a predileção do programa por uma jogada ao invés de outra:

pcvspessoa2
Arnold T-800 lidando com situações de jogo que ele não conhece

O problema é que as regras novas que ele se auto-ensina são específicas ao domínio de problemas que ele está tentando resolver. O programa do genoma de reconhecimento de padrões pode ser muito similar a um programa que identifica rostos, por exemplo. Mas pedir pro programa do genoma olhar pra vários rostos e tentar reconhecer pode ser como jogar uma chave de boca dentro do mecanismo inteiro. Isso porque daqui a pouco ele vai começar a misturar o que ele já conhece com a informação nova, e vão surgir resultados bizarros como tu jogar uma sequência de DNA pra ser avaliada pelo programa e ele responder ESSA É A CARA DA MARCINHA, SEM DÚVIDA.

doge_3370416k
O Deep Dream da Google é um programa que teve as associações de várias formas geométricas com o conceito de “cachorro” reforçadas além da conta.

Para que a skynet domine o mundo, precisamos de um tipo de inteligência artificial que seja aplicável em qualquer área de conhecimento. Algo não-específico. Uma inteligência geral. Tem que ser um computador fodão que consiga entender linguística, economia, informática, balística, psicologia, física, astronomia, e especialmente Street Fighter. Ninguém domina o mundo sem saber jogar de Bison.

 

O que é necessário para fazer a Skynet

Já sabemos sobre a inteligência geral. Mas mesmo que assumíssemos que isso é factível (spoilers: tamo longe), o que mais um computador precisaria ter para subjugar a raça humana? Se minha uber-inteligência está rodando numa máquina que está só plugada numa conexão da Vivo, provavelmente o estrago não seria muito grande, certo? No máximo ela ia mandar uns spams do Príncipe Nigeriano. Ela precisaria:

Ampliar seu escopo de ações

Isto é: uma máquina que só sabe enviar e receber mensagens via internet precisaria aprender a ganhar controle sobre coisas que a permita fazer mais que isso. Digamos: mandar uma carta pelo correio. Passar um fax. Dirigir um veículo. Invadir outro computador. Ela precisaria ampliar ainda mais o conjunto de inteligências específicas que ela precisa ter. Trata-se de uma máquina que não apenas se reprograma: ela precisa criar inteligências artificiais que a ajudem a resolver esses problemas.

Ser imparável

Se nossos suseranos cibernéticos tiverem um botão de “desliga” eles não são muito ameaçadores. A skynet teria que ser absolutamente indestrutível. Rodar em todas as máquinas do mundo, ter um suprimento de energia inesgotável, possuir máquinas que são feitas de materiais indestrutíveis. Conseguimos imaginar isso muito facilmente por causa de Exterminador do Futuro e Matrix.

Ser Onisciente

Ter acesso a todas as informações do passado e presente (e a partir disto ser capaz de prever o futuro com algum grau de certeza), para todas as áreas que sejam relevantes para sua existência. Como vocês devem imaginar pela linha de raciocínio que temos até agora, as áreas relevantes são TODAS. Tudo é útil pra uma máquina que planeja dominar o mundo. Tanto o super-guia quanto o programa do genoma melhoram suas capacidades conforme eles têm acesso a uma quantidade mais diversa de informações naquele campo. O mesmo valeria para uma inteligência artificial de escopo geral.

Um modelo da realidade

A máquina precisa ser capaz de montar um modelo de como a realidade que ela quer afetar funciona. O que é um sólido? O que é chão? Como andar? Se uma borboleta bater as asas em uma ilha do pacífico, isso pode causar um furacão em Papua Nova Guiné? Entender o comportamento do universo em que estamos inseridos é fundamental para usar isso ao seu favor na sua busca pela dominação universal.

O “ampliar seu escopo de ações” tem outro nome. Onipotência. Estamos falando de uma entidade Onipotente, Onisciente e indestrutível. Parece familiar? É fácil entender por quê o conceito de um programa que não temos total entendimento de como funciona atingir um estado de existência quase divino nos amedronta e nos fascina. É por isso que quando o buzzfeed escreve um post sobre como os robôs vão dominar o mundo e nos manter em cativeiro, sobre como todos nós vamos perder o emprego e todas as atividades vão ser exercidas por robôs, há tantos compartilhamentos e curtidas. É um assunto que mexe muito fundo conosco. 

O que acaba passando batido é que se algum ser humano conseguir concretizar qualquer etapa dessas que estamos comentando, ele não vai precisar de uma inteligência artificial para ter um controle gigantesco sobre a população. Se, por exemplo, alguém escrever um programa que escreve programas (não precisa nem ser inteligência artificial ainda), essa pessoa vai ficar tão bilionária, vai ter tanto país implorando pra fazer uso dessa tecnologia, que ela já vai ter o mundo em suas mãos. Se alguém conseguir montar um modelo preciso e completo da realidade, ainda que a longo prazo, seria possível provar que o universo é deterministico, não há entropia e então prever todos os acontecimentos futuros. Pensa em quanta gente não daria a vida por esse tipo de poder. O mesmo vale pra alguém que inventar algo que simplesmente não pode ser destruído. Vamos ter overlords humanos antes de ter overlords robôs.

Consciência

Ainda que todos os requisitos sejam preenchidos e finalmente sejamos exterminados, é provável que a máquina não faça a menor idéia do que ela está fazendo. Ela só está fazendo um monte de associações com base nas informações que ela tem e fornecendo a resposta que ela julga mais adequada. Quando dizemos que uma máquina se tornaria auto-consciente, o problema é definir o que entendemos por consciente. Se ela aparenta entender os valores da realidade na qual ela está inserida, parece tomar decisões em cima disso e entender se as consequências de seus atos levam aos objetivos que ela quer atingir, ela parece consciente. Da mesma maneira que o fulano do Quarto Chinês parece falar mandarim fluentemente.

O interessante é pensar como encaramos a nossa própria definição de consciência no que diz respeito a essência vs. aparência. Pode-se argumentar que uma máquina jamais seria capaz de ser consciente pois ela estaria apenas emulando a percepção e entendimento de si mesmo e de seu ambiente através de uma série de efeitos que fazem ela te dizer isso, mas isso não seria o suficiente para provar, de fato, que ela é consciente. É uma discussão bem complexa.  Entretanto, nossa própria consciência é causa de uma série de efeitos químicos e biológicos que fazem com que nos percebamos conscientes. A gente não sabe definir direito o que constitui consciência, enquanto programar é exatamente o ato de descrever um comportamento em uma linguagem formal e sem espaços para ambiguidades de maneira boa o suficiente para que uma máquina consiga reproduzi-lo. Talvez entender como a nossa própria consciência é construída seja o primeiro passo para poder modelar um sistema que possa ter uma inteligência artificial geral.

Ah, mas Diogo, e se dentre as áreas de conhecimento que a máquina puder aprender estiverem Ética e Filosofia?

Aí entra o Teorema Fundamental de Diogo Ribeiro sobre Inteligência Artificial e Overlords Robôs:

Qualquer inteligência artificial que começar a tentar entender filosofia vai perder tanto tempo tentando desvendar os milhares de paradoxos e mistérios que ela inclui que nunca mais vai sair dela, se tornando – para todos os efeitos – inútil na perspectiva da dominação mundial.

Já pensou o teto que é uma máquina com um modelo completo da realidade batendo na idéia de que uma flecha nunca vai atingir o alvo pois ela primeiro tem que percorrer a metade do caminho até ele? E depois a metade do caminho até a metade? Ou tentando decifrar a real natureza da frase “esta frase é falsa“?

Previsões

A parte mais fácil de prever o futuro é escrever uma previsão. Qualquer idiota lança uma previsão. Os grandes oráculos já sabiam que se a gente tentar adivinhar algum fenômeno várias vezes, eventualmente ele vai acontecer. Afinal de contas estamos no quê? No quadragésimo apocalipse que Nostradamus previu? (Acabo de descobrir que é meu 41o já. Confere aqui). Daqui a pouco elegem Bolsonaro pra Presidente da República, aí rola. Escrever previsões é fácil. O ponto é que ninguém tem pista alguma de se e quando isso pode acontecer. No máximo existem estimativas em relação a quando teremos poder computacional suficiente para podermos realizar alguma dessas tarefas.

Mais recentemente, houve uma emergência de pessoas que se auto caracterizam “futuristas” ou praticantes de “futurismo” que se especializa exatamente em fazer projeções educadas de se e quando possíveis cenários de futuro como esse vão acontecer. Ray Kurzweil, da Google, sendo o mais proeminente. Na minha opinião:

  1. Futurismo é um movimento artístico
  2. O nome do que define o que a área se propõe a fazer é futurologia
  3. Analisar tendências e procurar entender – dado o cenário atual – para onde as coisas rumam e em que ritmo, é um papel assumido por qualquer pesquisador. Não acho interessante do ponto de vista da comunidade científica que tente se criar uma categoria de pessoas que pense nesse tipo de coisa em uma perspectiva geral, sem ser especialista dos campos que está tentando FUTURAR .
  4. O único modo 100% preciso de prever tendências de futuro é construir ele. Querer que o mundo se encaixe em uma expectativa sem de fato estar investido em tornar ela realidade não significa muito e não ajuda as pessoas que estão determinadas em construir algo novo e/ou melhor.
  5. Qualquer idiota faz previsões. Veja novamente a primeira linha do post.

Claro que há avanços muito significativos na área, e cada vez mais temos resultados interessantíssimos de inteligências artificiais fazendo tarefas incríveis. A parte de “todos nós vamos perder o emprego” não deixa de ser uma realidade relacionada à evolução da tecnologia (pra quem ainda não assistiu Humans need not apply, recomendo!), mas na perspectiva de sermos governados e tiranizados por um programa que saiu de controle, tem um volume imenso de trabalho pela frente pra chegarmos lá, se é que isso é possível mesmo. Se uma máquina pode ser auto-consciente ou não é um problema muito mais de definição filosófica do que é consciência do que de como ele será implementado, e reforço o ponto de que haverão tiranos humanos antes de haverem tiranos-máquina.

Só pela diversão, nós treinamos uma rede neural com todos os textos do Mean Look (inclusive este) e geramos uma postagem de 50 frases que você pode conferir aqui e ficar mais sossegado em relação à ameaça de ser subjugado por uma máquina.

Resumindo o post:

Obrigado e passar bem, bjos de Rotom-luz.

Forças Imparáveis e Obstáculos Intransponíveis

Se Platão defende que a narrativa é a imitação da realidade e videogames são um mídia através da qual podemos retratá-las, temos de ter ferramentas para imitar fenômenos naturais. Entretanto este não é um post sobre física avançada. Vamos falar de sólidos.

Te garanto que o problema de detectar quando um objeto colidiu com outro e como proceder a partir daí é central a maior parte dos seus jogos favoritos . Parece bobo, mas o número de coisas que pode dar errado planejando como lidar com isso é assustador.

Mas não se assuste. Para ajudar a tratar todo esse terror, nós vamos contar com a ajuda do nosso mais novo mascote: digam olá para o Coliditto.

cl
“O abraço frio da morte te espera.”

Impenetrabilidade em Jogos

Dois parágrafos e já vamos falar de metafísica: Impenetrabilidade é uma propriedade da matéria que diz que dois corpos não podem ocupar o mesmo lugar no mesmo instante. Essa propriedade é o que faz com que coisas que tentem fazê-lo colidam entre si. Ainda que pareça um detalhe técnico, é um conceito tão natural para nós que quando um jogo faz isso muito mal, a quebra de expectativa em relação à realidade que conhecemos é tão grande que temos dificuldade de manter a imersão.

Quantas estrelas merece essa princesa?

Para simular impenetrabilidade de maneira simples, em geral jogos delimitam uma área ao redor do corpo sólido que chamaremos de colisor. Sem entrar em detalhes, o processo funciona de maneira simples, em duas fases:

  1. Detecção de colisões: o jogo verifica se dois objetos compartilham pelo menos um ponto de intersecção. Se sim, eles estão colidindo, se não, não estão.
  2. Tratamento de colisões: aqui rola o vulgo “Ok, bateu. E agora?”. O jogo precisa decidir o que fazer com os objetos que estão colidindo. Podemos, por exemplo voltar um dos objetos até o último instante onde eles não estavam mais colidindo, ou arrastar um dos objetos pra fora do outro até que eles não estejam mais colidindo (em geral a bola, porque acho difícil a parede ceder passagem).

Tudo o Que Pode Dar Errado Quando Você Bate em Alguma Coisa e Por quê

O processo é simples, mas muito pode dar errado. Tenho certeza que todos já têm exemplos em mente de vezes em que viram algum problema com colisões em jogos. A seguir vamos explorar alguns exemplos e especular o que pode levar eles a acontecerem. Vale notar que a bibliografia sobre como essas coisas são realmente implementadas não é muito disponível, e uma grande parte das possibilidades que vamos discutir aqui são especulativas, mas não deixam de ser um exercício interessante para entendermos como as coisas funcionam.

Super Mario 64: GOTTA GO FAST

A primeira vez que eu vi isso, meu palpite de como isso poderia acontecer foi em relação a fase de detecção de colisões. A cada instante, que em geral representa 1/30 de um segundo ou 1/60 de um segundo em jogos modernos, o jogo vai tentar movimentar Mario um pouquinho, e verificar se ele colide com algo. Há duas grandes maneiras de pensar como isso funcionaria. A primeira é chamada de colisão em espaço discreto:

discreto1-1 discreto2-1 discreto3-1

Neste caso, botamos Mario diretamente na posição pra qual ele tem que ir naquela fração de tempo, e então passamos pra etapa de detecção de colisões. Se ele estiver colidindo com a parede, o tratamento da colisão vai se encarregar de jogar o personagem pra fora dela. Parece tosco (e na real é um pouco), mas se algumas propriedades forem respeitadas, o modelo funciona. Se a distância máxima que o personagem puder percorrer em um frame for menor ou igual ao diâmetro do seu colisor, podemos garantir que não tem como ele ultrapassar aquela parede nunca. Ou seja: se o tamanho do colisor e a velocidade máxima do personagem forem fatores compatíveis, tá tudo suave.

A engine de Super Mario 64 tem colisores do tamanho certo limita a velocidade máxima de Mario, então em tese eles estariam seguros. Mas esse limite de velocidade só vale para velocidade POSITIVA. O vídeo acima usa um bug do jogo usando pulos que faz com que Mario se desloque extremamente rápido para trás. O que acontece? Poof. Vai direto através da parede.

discreto2-2 discreto3-2

A segunda grande maneira de abordar as colisões arrumaria esse problema. Ela se chama detecção em espaço contínuo: antes de mover o personagem, o jogo verifica se há alguma colisão possível entre a posição atual do personagem e a posição pra qual ele quer ir. Se houver uma colisão, ele passa a informação de em que ponto isso aconteceu para a fase de tratamento.

continuo1 continuo2 continuo3

No tratamento ele pega a posição onde houve a colisão, e então move o personagem pra lá. Não importa quão rápido Mario se deslocasse, a colisão nunca seria ignorada. O curioso é que supostamente há um artigo publicado que explica um algoritmo que teria sido usado na engine de Super Mario 64, e ele já sugere o método contínuo. Especulamos que ele não foi implementado exatamente como é dito no artigo, o que gera o comportamento que vimos. Mas talvez esse comportamento ocorra por algum erro na fase de tratamento da colisão que acabe posicionando Mario do outro lado da parede por sua velocidade ser negativa. Fica o questionamento.

The Legend of Zelda: Ângulos Agudos

Ocarina of time começou seu desenvolvimento na mesma engine de Super Mario 64, mas segundo Miyamoto a engine foi muito alterada. Se olharmos no mesmo artigo que descreve o algoritmo de colisões de Super Mario 64, eles descrevem um método que faz com que o personagem conserve seu movimento rente a uma parede quando ele colide com ela, como se ele estivesse deslizando rente a ela.

normals

Quando isso acontece entre 2 paredes que formam um ângulo agudo, fica difícil determinar a posição que o personagem deve assumir após a colisão, porque cada uma das paredes vai tentar empurrar o personagem em uma direção perpendicular a elas, preservando a velocidade que ele tinha em outras direções.

zeldaagudo1 zeldaagudo2 zeldaagudo3

É interessante notar que há vários jeitos de ultrapassar paredes em Zelda, mas a grande maioria dele envolve paredes com ângulos agudos e alguma estratégia para ganhar velocidade suficiente para ser passado através delas (que nem vimos no exemplo de Mario).

Neste caso em específico, também é possível que o jogo só trate a colisão em relação a uma parede, ignorando a outra, o que causa o efeito de que link é jogado apenas através da parede da direita. Em geral jogos possuem um buffer de tamanho físico que determinas quantas colisões simultâneas podem ser detectadas. Se o número de colisões ultrapassar esse limite, elas são ignoradas. Talvez não seja o caso em Zelda pois a estrutura de dados que guarda informação de colisões permite que mais de um polígono seja listado como alvo de uma colisão.

Skyrim e Buffer de Foda-se

Tendo explicado o fato de que os jogos processam colisões contra um número finito de objetos, adivinha quem está verificando só a colisão contra o prato?

skyrim1 skyrim2 skyrim3 skyrim4

Curiosamente este problema não ocorre quando se tenta colocar o prato contra uma parede côncava. Especulamos que isso se deve ao fato de que os objetos não são mais co-planares. O espaço que fica entre o prato e a parede pode ser suficiente para que o jogo passe a detectar a colisão entre o personagem e a parede.

Spooky’s Jump Scare Mansion: PARA TUDO Edition

Pra quem não conhece: é um jogo indie de horror baseado um pouco em SCP, onde você está preso em uma mansão onde por mil salas você vai ser perseguido por monstros que começam fofinhos e inocentes e terminam como bestas sanguinárias e incansáveis.

O jogo fica tenso rápido, e um dos aspectos que colabora pra isso é o seguinte: lembra que comentamos que em Super Mario 64 quando você se move rente a uma parede, ele só não deixa você entrar na parede, mas desliza você rente dela, preservando parte do seu movimento? Aqui os designers escolheram outra estratégia: o ângulo pelo qual você consegue passar deslizando por uma parede é beeeem menos tolerante:

Na primeira parte, o personagem bate no canto da quina da parede. Ele não deixa você deslizar por ela, ele PARA completamente o movimento. Você tem que ir pra trás e dar a volta naquela esquina, ou virar bastante a câmera até a ponta do cubo deixar de bater na parede. Agora: imagina você ter que gerenciar isso enquanto tem um bicho maluco querendo seu cérebro.

Logo após, o personagem tenta andar pra direita enquanto está encostado em uma parede. Ele não consegue deslizar, então começa a andar na diagonal (pra trás e pra direita). O movimento “serrilhado” resultante acontece porque quando o personagem está colado na parede, ele está tentando ir pra direita e pra trás. Pra direita ele não pode se mover pois está colidindo, mas pra trás pode. Então ele vai pra trás, e aumenta a distância dele com a parede. Quando ele vai pra direita de novo, ele bate de novo, e interrompe o movimento. Isso se repete rapidamente, mas é tudo derivado do aspecto de que o movimento é interrompido.

spooky

É um caso onde a resposta a colisões não é fluida ou 100% agradável para o jogador, mas isso colabora muito para manter o clima estressante e aterrorizante do jogo. Às vezes uma escolha de design que não é agradável ao jogador pode funcionar caso colabore para o clima que o jogo está tentando criar.

Série Souls: Hitbox Porn (GONE SEXUAL)

Os jogos da série Souls são conhecidos por terem um combate com hitboxes tão precisas que geram narrativas emergentes de combates que o jogador vai querer documentar para mostrar pros netos, de tão épico que é o esquema:

As hitboxes são animadas, o que significa que elas mudam de tamanho, orientação e posição durante as animações do personagem. No vídeo, dá pra ver que durante a animação de ataque do personagem, ele abaixa um pouco. Esse pouco é suficiente para ele desviar por milímetros do ataque inimigo. É realmente um sistema primoroso.

Quando se trata de colisões com o terreno, os jogos da série são menos cuidadosos. Especialmente porque eles focam muito mais em te dar uma experiência de combate dinâmico, vivo e excitante do que simplesmente simular caminhadas com perfeição. No final das contas o contraste entre o sistema de colisões em combate e o de terreno é HILÁRIO:

Lembram que as hitboxes mudam de tamanho durante as animações? Quando o Fire Demon nesse vídeo toma muito dano, ele faz algumas animações para mostrar ao jogador que ele está ficando desgastado. Elas também alteram o tamanho, orientação e posição de suas hitboxes. Entretanto, o inimigo continua tentando chegar até o jogador através de um espaço onde ele não cabe. Acontece que algumas dessas animações são suficientes para que ele consiga passar pelo menos por um pedaço da parede. No final do vídeo, quando ele ergue o corpo em uma das animações de quando ele toma muito dano, o centro dele ultrapassa o topo da parede, e aí o sistema de tratamento de colisões do jogo entende que ele estava dentro do teto e agora está ultrapassando o “chão”. Na etapa de tratamento da colisão, ele é atirado pro espaço que tem acima do teto.

Smash 4: Colisão Contínua Também Dá Pau

Em jogos com muitos elementos que se movimentam, colisões no método contínuo também têm seus problemas. Nesse caso, o Mr. Saturn está querendo ir para a esquerda, e a plataforma também. Durante as fases de detecção e tratamento de colisão do Mr. Saturn não tem nada impedindo ele de se mover naquela direção, então ele se move pra esquerda e começa a cair. No mesmo instante, a plataforma vai ter sua posição e tratamento alteradas também, e quando ela tenta se mover, o Mr. Saturn que estava caindo não pode mais cair. No próximo ciclo de atualizações, ele vai tentar se mover para a esquerda de novo, e esse conflito vai se repetir.

Colisões contínuas não lidam bem com muitos objetos que se movimentam dinamicamente. Como os objetos se movimentam um de cada vez, cada um com seu ciclo de detecção, tratamento e movimento, dependendo da ordem na qual os objetos são processados os resultados finais podem ser diferentes. Prever isso e tratar antes que aconteça é uma tarefa hercúlea. E calcular as colisões de todos primeiro e depois executar todos os movimentos pode gerar situações onde dois objetos têm uma intersecção. A partir do momento que isso acontece, se torna necessário usar a etapa de tratamento do método discreto e retirar os objetos de dentro da intersecção. Se quisermos levar em conta a velocidade e peso de cada um deles, começamos a entrar em simulação de física, e não mais colisão simples. E isso é outro papo.

Conclusões

Se você acha que entrar dentro de uma parede, ficar preso no teto, ser teletransportado para o outro lado do mapa são coisas exclusivas de jogos independentes, que foram feitos por meia dúzia de malucos, meu amigo: você está enganado. Como a gente viu, até os desenvolvedores de jogos triple A estão sujeitos a isso. 

1
Colisões são difíceis de acertar, ninguém está contente com isso.

Eis uma citação do Brad Hines, funcionário da Eidos sobre detecção de colisões (fonte aqui):

Colisão em video-games é uma parte de um grande e complicado conjunto de sistemas. É criado por seres humanos que são capazes de cometer erros, ou apressar trabalho, ou ter coisas mais prioritárias para fazer. O desenvolvimento de jogos geralmente é baseado em um prazo apertado e infelizmente problemas menores podem ser deixados de lado.

É um problema que não tem uma só solução, e nenhuma delas é 100% perfeita. Passa a ser um problema de onde você pode fazer concessões no seu jogo. Tanto Dark Souls quanto Spooky’s House of Jumpscares usam algoritmos de colisão com terreno que não são ideais, mas são concessões que eles fazem porque esses problemas não ficam no caminho de como eles querem que você jogue. Esse tipo de escolha de design é arriscada, mas às vezes vale mais a pena ignorar um problema menor do que ficar martelando em cima de um ponto que não é tão importante pro seu jogo.

Claro que é importante conhecer as opções e escolher a que fizer mais sentido, mas todo mundo está sujeito a uns problemas com isso. Fica com o vídeo da Bianca Velloso pra te garantir que a treta é séria até em 2016:

 

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.