Como fiz uma cidade multiplayer estilo GTA que roda no navegador (e o que aprendi com portais de jogos)
Oi pessoal! Sou dev solo no Uruguai e há alguns meses estou construindo o Balak City, uma cidade multiplayer de mundo aberto que roda direto no navegador, no PC e no celular. Quero contar algumas decisões técnicas e um problema que me custou jogadores, porque talvez ajude quem está fazendo jogo web.
A cidade é uma só, compartilhada
Todos os jogadores estão na mesma cidade ao mesmo tempo: trânsito, pedestres, polícia, gangues e propriedades. O desafio aqui é: quem simula a cidade?
No começo, o primeiro jogador que entrava virava o "anfitrião" e o navegador dele simulava os carros e pedestres para todo mundo. Funcionava, mas tinha problemas óbvios:
- se o anfitrião minimizava a aba, o navegador reduzia os timers e a cidade "congelava" para todos;
- se ele saía, outro jogador precisava assumir no meio da partida;
- celular fraco como anfitrião = cidade lenta para todos.
A solução foi colocar um servidor anfitrião (uma VPS) que roda a simulação o tempo todo. Os jogadores viram só convidados: recebem o estado e mandam as próprias ações. A sincronização passa pelos Cloudflare Workers com Durable Objects, que funcionam como "salas" com estado.
Lição: no navegador, nunca confie em uma aba em segundo plano para manter uma simulação viva.
Tudo em um arquivo (sim, de verdade)
O cliente é um único HTML grande, montado a partir de partes menores por um script. Desenho em Canvas 2D, visão de cima. Sem framework. Parece loucura, mas para um dev solo tem vantagens: deploy simples, zero build complicado e cache fácil de controlar com um arquivo de versão (o cliente compara um hash e avisa quando há versão nova).
Vizinhos com IA
Alguns moradores da cidade são personagens com IA (via API do Gemini) que conversam no chat geral, com personalidade própria. O cuidado aqui foi limitar a frequência e o tamanho das respostas para não virar spam nem estourar custo.
O problema dos portais de jogos (iframe)
Publiquei o jogo em portais que mostram o jogo dentro de um iframe. Resultado medido no meu painel: um portal trouxe 17 pessoas que jogaram e 0 contas criadas.
O motivo: dentro de um iframe de outro domínio, os navegadores bloqueiam ou isolam cookies e armazenamento de terceiros. Login e cadastro quebram ou não persistem, e a pessoa joga como visitante e vai embora.
O que fiz:
- o jogo detecta quando está em um iframe de outro site (se consigo ler
window.top.location, é o mesmo site; se dá erro, é um portal); - só nesse caso aparece um aviso "Jogue completo e crie sua conta no site", que abre o jogo em uma aba própria;
- na tela de entrada o aviso fica dentro do cartão (empurra o conteúdo, não cobre nada); durante o jogo vira uma abinha discreta na lateral;
- o link leva um parâmetro (
?from=portal) para medir quantos realmente passam.
Se você publica jogo web em portais, vale olhar isso, principalmente se o seu jogo tem conta/login.
Economia
A economia interna usa USDT na rede Solana (depósito e saque). Jogar é grátis e depositar é opcional. Não vou entrar em detalhes aqui porque o foco é técnico.
Se alguém quiser testar ou dar feedback técnico (principalmente desempenho no celular): https://balakapp.win
Perguntas sobre a arquitetura são bem-vindas, respondo tudo nos comentários.