Trancado num Cubo: Por Que o Memory Falling Into Place Roda em Excalibur
Vamos direto ao ponto: você é uma navezinha soldada dentro de um cubo, e o cubo está cheio de coisas que querem te matar. É isso. É o jogo. Chamamos de Memory Falling Into Place porque queríamos um nome que parecesse letra de Radiohead que você jura já ter ouvido em algum lugar — e, pelo que a gente sabe, é basicamente isso.
Mecanicamente é um roguelike bullet-hell visto de cima. Você voa numa arena quadrada, atira em inimigos, tenta não encostar nas paredes (as paredes não são suas amigas, pode confiar), e se sobreviver, ganha Estrelas. Estrelas compram Upgrades. Upgrades deixam o próximo cubo um pouquinho menos propenso a te matar. Tem um grid 4×4 de mundos, cada um com um grid 4×4 de fases, porque aparentemente um grid só não era suficiente — precisávamos de um grid de grids. Muito a propósito pra um jogo sobre cubos, né.
Por que Excalibur?
Na hora de escolher o motor, os requisitos eram: 2D, TypeScript desde o berço, modelo actor/scene, física embutida e — crucial — um nome cool o bastante pra colocar num post de blog. O Excalibur.js marcou todos os pontos. Ele te dá Actor, Scene, Engine, manipulação de sprites/gráficos, input, áudio e um sistema de física com tipos de colisão, tudo isso sem precisar colar cinco bibliotecas diferentes antes de escrever uma linha de lógica de jogo.
E falando em física — sim, entramos assumindo que ia ser preciso parafusar o Matter.js em algum momento pra colisão "de verdade", porque é isso que todo tutorial da internet faz. Resultado: não precisou. O Excalibur já vem com seu próprio motor de física, com Body, CollisionType (Active, Fixed, Passive, PreventCollision) e grupos de colisão de fábrica. Nunca importamos o Matter.js. Nem uma vez. Aquela dependência que a gente já tava se preparando psicologicamente pra "definitivamente vamos precisar" simplesmente... não precisou. Um raro e belo momento de não over-engenheirar alguma coisa, e vamos ficar com todo o crédito mesmo que tenha sido 90% sorte.
A forma do código
Uma decisão que já está pagando o aluguel: todo sistema de gameplay ganha uma camada de lógica pura, sem nenhuma dependência do Excalibur — só funções TypeScript de boa e objetos de estado — e depois um Actor bem fininho por cima, que só cuida de renderização e ciclo de vida. Quer testar "essa conta do upgrade tá certa"? Sem engine, sem canvas, sem npm run dev, só uma chamada de função e um assert. Essa separação vai aparecer muito nos próximos posts, principalmente porque é o motivo desses posts conseguirem existir — bugs que normalmente exigiriam pilotar a nave contra a parede cinquenta vezes na mão agora são pegos pela suíte de testes.
Falando em bugs pegos (e não pegos) — no próximo episódio: um upgrade de multishot que dispara balas num círculo perfeito, um inimigo que continua atirando depois de já ter morrido, e um upgrade que se recusa solenemente a seguir as regras que todo mundo combinou. Até a próxima, dentro do cubo.