Voltar para o Blog
Quest Log

Desenvolvimento de Jogos Acessíveis: Design Inclusivo para Todos

Design inclusivo e acessível para jogos

Aprenda a criar jogos acessíveis e inclusivos que todos podem jogar. Guia completo sobre acessibilidade visual, auditiva, motora e cognitiva com implementações práticas.

Desenvolvimento de Jogos Acessíveis: Design Inclusivo para Todos

Acessibilidade em jogos não é caridade nem item de marketing. É design bem feito. Quando você dá ao jogador a opção de remapear o controle, ajustar o tamanho da legenda ou reduzir o tremor de tela, você não está só ajudando quem tem deficiência. Está ajudando o cara que joga no sofá com o controle longe, a pessoa de óculos que esqueceu eles na cozinha, o jogador cansado depois de um dia de trabalho.

O melhor exemplo prático disso é o Assist Mode do Celeste. Eles não esconderam as opções num menu de vergonha. Colocaram na cara, com um texto respeitoso, e deixaram o jogador decidir. The Last of Us Part II foi mais longe e virou referência de quantas opções dá pra oferecer sem quebrar o jogo. O ponto não é copiar essas listas. É entender o princípio: quando você projeta para quem tem mais dificuldade, você melhora a experiência de todo mundo.

Este guia mostra como implementar acessibilidade nas quatro frentes principais (visual, auditiva, motora e cognitiva), com código real em Godot quando faz sentido e decisões de design quando código não é o ponto.

Por Que Acessibilidade Importa

Tem o lado de negócio e tem o lado humano, e os dois apontam pra mesma direção.

Do lado de negócio: você aumenta o número de pessoas que conseguem terminar seu jogo, ganha reviews melhores e atende exigências que estão virando obrigatórias. O European Accessibility Act entrou em vigor em 2025 e cobre boa parte do software vendido na Europa. As plataformas (Xbox, PlayStation) já publicam guidelines próprias e cobram cada vez mais. Ignorar isso hoje é deixar dinheiro e alcance na mesa.

Do lado humano é mais simples ainda. Tem gente que nunca conseguiu terminar um jogo difícil porque a mira era rápida demais, ou porque o daltonismo escondia uma pista de cor, ou porque o tremor de tela dava enjoo. Quando você adiciona um modo de cor, um auto-sprint ou uma legenda decente, você não está fazendo um favor. Está removendo uma barreira que nunca precisou existir. E geralmente isso custa pouco tempo de desenvolvimento se você pensa nele desde o começo.

A regra que eu sigo: acessibilidade barata se planejada cedo, cara se enfiada no final. Decida quais opções você quer oferecer antes de fechar a arquitetura de input e de UI. Depois disso, cada uma vira só mais um toggle.

Tipos de Acessibilidade

Visual: além do modo daltônico

Acessibilidade visual cobre um espectro grande: daltonismo, baixa visão, sensibilidade a movimento e fotossensibilidade (risco de convulsão por flashes). Cada uma pede uma opção diferente, e o erro comum é tratar tudo como "modo daltônico".

O primeiro princípio é não depender só de cor para passar informação. Se a única forma de distinguir time aliado de inimigo é vermelho contra azul, qualquer pessoa com daltonismo fica perdida. Adicione um segundo canal: formato do ícone, símbolo, padrão de textura, posição. Isso resolve a maioria dos casos sem nenhum shader.

Quando você quer ir além e simular o filtro de cor na tela inteira, dá pra fazer com um shader. As matrizes abaixo aproximam como cada tipo de daltonismo percebe as cores e são usadas pra testar ou compensar. Em Godot, isso vira um ShaderMaterial aplicado num ColorRect que cobre a tela (um post-process simples):

shader_type canvas_item;

// 0 = nenhum, 1 = protanopia, 2 = deuteranopia, 3 = tritanopia
uniform int cb_mode : hint_range(0, 3) = 0;

void fragment() {
    vec4 color = texture(TEXTURE, UV);
    mat3 filter;

    if (cb_mode == 1) { // protanopia
        filter = mat3(
            vec3(0.567, 0.433, 0.0),
            vec3(0.558, 0.442, 0.0),
            vec3(0.0,   0.242, 0.758));
    } else if (cb_mode == 2) { // deuteranopia
        filter = mat3(
            vec3(0.625, 0.375, 0.0),
            vec3(0.7,   0.3,   0.0),
            vec3(0.0,   0.3,   0.7));
    } else if (cb_mode == 3) { // tritanopia
        filter = mat3(
            vec3(0.95, 0.05, 0.0),
            vec3(0.0,  0.433, 0.567),
            vec3(0.0,  0.475, 0.525));
    } else {
        filter = mat3(1.0); // identidade, sem alteração
    }

    color.rgb = filter * color.rgb;
    COLOR = color;
}

Atenção: esse filtro simula a visão daltônica. Você usa ele pra conferir como seu jogo aparece pra essas pessoas, ou como base de um modo de correção. Não é um botão mágico que "conserta" cores. O trabalho de verdade é garantir contraste e informação redundante no próprio design.

Para baixa visão, as opções que mais valem o esforço:

  • Escala de UI e de fonte. Permita o jogador aumentar o texto. Nunca chumbe fonte pequena. No Godot, use Theme e tamanhos relativos para escalar tudo de uma vez em vez de ajustar nó por nó.
  • Contraste alto e contorno. Um modo que aumenta o contraste entre HUD e fundo, e adiciona contorno em elementos importantes, ajuda muito.
  • Reduzir movimento. Tremor de tela, motion blur e câmera balançando causam enjoo em parte dos jogadores. Ofereça um toggle que desliga ou suaviza isso.

Para fotossensibilidade, a regra prática vem do padrão WCAG: evite mais de três flashes por segundo numa área grande da tela. Se seu jogo tem explosões piscando ou estroboscópio, dê uma opção de reduzir flashes e teste de verdade. Isso pode literalmente evitar uma convulsão.

Em código, junte essas opções num recurso de configuração e aplique uma vez quando o jogador muda. Em Godot um Resource de settings é o caminho limpo:

extends Resource
class_name AccessibilitySettings

@export var ui_scale: float = 1.0       # 0.75 a 2.0
@export var high_contrast: bool = false
@export var reduce_motion: bool = false
@export var reduce_flashing: bool = false
@export var colorblind_mode: int = 0     # 0=off,1=prot,2=deut,3=trit

func apply_visual(theme: Theme, cb_rect: ColorRect) -> void:
    # escala global de fonte via Theme, em vez de mexer nó a nó
    theme.set_default_font_size(int(16 * ui_scale))
    # liga o shader de daltonismo só quando precisa
    var mat := cb_rect.material as ShaderMaterial
    mat.set_shader_parameter("cb_mode", colorblind_mode)
    cb_rect.visible = colorblind_mode != 0
Próximo nível
Quer aprender isso na prática?

No CursoGame.Dev você sai dos tutoriais soltos e constrói jogos publicáveis, com trilha progressiva, quests práticas e feedback real.

Conhecer a plataforma
+500 alunos4.9/5Garantia 7 dias

Auditiva: mais que legenda

Legenda é o básico, e mesmo o básico tem nível. Uma legenda boa identifica quem está falando ([João]: "vamos"), descreve sons importantes que não são fala ([explosão à direita]) e deixa o jogador ajustar tamanho, cor e fundo. Sem isso, uma pessoa surda perde metade do contexto.

O que separa legenda meia-boca de legenda boa:

  • Rótulo de quem fala. Numa cena com várias pessoas, sem o nome a legenda vira sopa.
  • Legenda de som ambiente. "Passos se aproximando", "porta rangendo". Esses sons carregam informação de gameplay, não só de clima.
  • Fundo legível. Texto branco puro some em cena clara. Uma caixa preta semi-transparente atrás do texto resolve.

Depois das legendas, o próximo nível é dar uma representação visual para sons que importam no gameplay. Em jogos competitivos, ouvir de onde vem o passo do inimigo é vantagem. Quem não ouve fica em desvantagem injusta. A solução é um indicador direcional: uma seta ou marca na borda da tela apontando pra direção do som.

A lógica é direta: pega a posição da fonte de som em relação ao jogador, calcula o ângulo e posiciona o indicador. Em Godot 2D fica assim:

extends Control

@export var player: Node2D
@export var indicator: TextureRect  # seta que gira na borda da tela

func show_sound(source_pos: Vector2, volume: float) -> void:
    var dir := source_pos - player.global_position
    var angle := dir.angle()              # radianos, 0 = direita
    indicator.rotation = angle
    indicator.modulate.a = clamp(volume, 0.0, 1.0)  # mais alto = mais visível
    indicator.visible = true

Em 3D a ideia é a mesma, você só projeta a direção no plano da câmera antes de calcular o ângulo. O importante é decidir quais sons merecem indicador: tiro, passo, objetivo. Indicar todo som vira poluição visual e atrapalha mais do que ajuda.

Para quem usa controle, vibração também serve de canal extra. Um padrão de vibração diferente para "inimigo perto" ou "dano recebido" ajuda quem não ouve a reagir. Godot expõe isso por Input.start_joy_vibration.

Motora: controles adaptáveis

Acessibilidade motora é a frente onde uma decisão de arquitetura faz toda a diferença, e é aqui que mais gente erra chumbando o input direto no código.

A regra número um: nunca leia botões físicos direto na lógica de jogo. Use ações abstratas. No Godot isso é o sistema de Input Map: você define ações como pular, atirar, correr, e o jogador remapeia qual botão dispara cada ação sem você tocar em nada. Se você espalhou Input.is_key_pressed(KEY_SPACE) pelo código, remapeamento vira um pesadelo. Se você usou Input.is_action_pressed("pular"), remapeamento é de graça.

# Errado: tecla chumbada, impossível de remapear
if Input.is_key_pressed(KEY_SPACE):
    jump()

# Certo: ação abstrata, jogador remapeia no menu
if Input.is_action_just_pressed("pular"):
    jump()

Com ações no lugar, as outras opções motoras viram extensões naturais:

  • Hold vs toggle. Alguns jogadores não conseguem segurar um botão por muito tempo (mira, corrida, agachar). Ofereça a opção de transformar "segurar" em "apertar pra ligar, apertar pra desligar". Você guarda um estado booleano por ação e inverte ele no just_pressed.
  • Auto-sprint. Em vez de segurar o botão de correr o jogo inteiro, o personagem corre sozinho quando está se movendo fora de combate. Foi uma das mudanças mais elogiadas do God of War por jogadores com dor nas mãos.
  • Modo de uma mão. Layouts alternativos que cabem numa mão só, ou suporte a controles adaptados como o Xbox Adaptive Controller.
  • Janelas de tempo mais largas. Quick time events e combos com janela curta excluem muita gente. Ofereça aumentar o tempo de reação ou auto-completar QTEs.

A assistência de mira é o exemplo clássico de opção que ajuda tanto acessibilidade quanto jogadores casuais. Tem dois mecanismos que valem mais a pena e raramente parecem injustos: desacelerar a sensibilidade quando a mira passa perto de um alvo, e puxar levemente a mira na direção do alvo. Magnetismo forte e snap automático são mais agressivos e você só liga em níveis de assistência mais altos, sempre opcionais.

# Esboço de aim assist por desaceleração (3D)
@export var slowdown_range: float = 15.0
@export var slowdown_strength: float = 0.4  # 1.0 = sem efeito

func aim_sensitivity_for(target: Node3D) -> float:
    var dist := global_position.distance_to(target.global_position)
    if dist >= slowdown_range:
        return 1.0
    # quanto mais perto do alvo, mais devagar a mira gira
    var t := (slowdown_range - dist) / slowdown_range
    return lerp(1.0, slowdown_strength, t)

Cognitiva: simplicidade e clareza

Acessibilidade cognitiva ajuda quem tem dislexia, TDAH, autismo, ou simplesmente quem joga em sessões curtas e esquece onde estava. E quase tudo aqui é decisão de design, não de código.

As opções que mais resolvem:

  • Objetivo sempre à vista. Um lembrete de qual é o objetivo atual, acessível a qualquer momento. Nada de "o que eu tava fazendo mesmo?" depois de duas semanas sem jogar.
  • Ajuda de navegação. Marcador de bússola, minimapa, ou uma trilha discreta apontando pra onde ir. Deixe ligar e desligar.
  • Diário e log de quests. Registro do que aconteceu, de diálogos importantes, de objetivos. Memória externa pro jogador.
  • Sistema de dicas progressivo. Quando o jogador trava, ofereça ajuda em camadas: primeiro uma dica vaga, depois mais específica, e só por último a solução. Assim quem quer pensar sozinho não recebe spoiler, e quem está realmente preso não desiste.

O sistema de dicas progressivo é fácil de implementar e faz diferença enorme. A lógica: detecte que o jogador está parado há muito tempo no mesmo ponto, e a cada intervalo solte uma dica mais explícita.

extends Node

@export var hints: Array[String] = [
    "Dá uma olhada em volta procurando pistas.",
    "Tenta interagir com a alavanca vermelha.",
    "Aperta a alavanca vermelha e depois a azul.",
]
@export var seconds_between_hints: float = 30.0

var _stuck_time := 0.0
var _level := 0

func _process(delta: float) -> void:
    if player_is_stuck():
        _stuck_time += delta
        if _stuck_time >= seconds_between_hints and _level < hints.size():
            show_hint(hints[_level])
            _level += 1
            _stuck_time = 0.0
    else:
        _stuck_time = 0.0
        _level = 0

player_is_stuck() você define conforme o jogo: pode ser tempo sem progredir o objetivo, ou tempo na mesma sala. O ponto é que a dica é opcional, gradual e respeita quem quer resolver sozinho.

Próximo nível
Quer aprender isso na prática?

No CursoGame.Dev você sai dos tutoriais soltos e constrói jogos publicáveis, com trilha progressiva, quests práticas e feedback real.

Conhecer a plataforma
+500 alunos4.9/5Garantia 7 dias

Implementação Prática

Junte tudo num menu próprio, separado das opções gerais, organizado por categoria: Visual, Áudio, Controles, Jogabilidade. Cada opção vira um controle simples (slider, toggle, dropdown) ligado ao seu recurso de settings.

O que não pode faltar em cada seção:

  • Visual: escala de UI, modo daltônico, contraste alto, reduzir movimento, desligar flashes, cor e tamanho de legenda.
  • Áudio: legendas, legendas de som ambiente, indicadores visuais de som, volumes separados (master, efeitos, música, voz).
  • Controles: remapeamento, hold/toggle, auto-sprint, força de aim assist, modo uma mão.
  • Jogabilidade: dificuldade, marcadores de objetivo, sistema de dicas, opção de pular puzzle.

Um detalhe que muda a vida do jogador: aplique cada mudança na hora, com preview, em vez de exigir reiniciar. Ninguém deveria fechar o jogo pra testar se a legenda ficou do tamanho certo.

Presets de acessibilidade

Configurar trinta opções uma a uma cansa qualquer um, ainda mais quem tem dificuldade motora ou cognitiva. Ofereça presets que ligam um conjunto de opções de uma vez, e deixe o jogador refinar depois. Por exemplo, um preset "baixa visão" liga escala de UI grande, contraste alto e legendas grandes. Um preset "uma mão" ativa o layout alternativo e auto-sprint. Cada preset é só um atalho que escreve vários valores no recurso de settings.

Testar com usuários reais

Aqui não tem como terceirizar pra código. Acessibilidade você valida testando com pessoas que realmente dependem dela. Você pode achar que sua legenda está ótima até uma pessoa surda jogar e apontar que falta identificar quem fala. Você pode achar seu aim assist suave até alguém com tremor mostrar que ainda é rápido demais.

Onde encontrar quem testa: comunidades como a AbleGamers e a SpecialEffect, fóruns de acessibilidade, organizações locais de pessoas com deficiência. Antes do teste, pergunte quais são as necessidades da pessoa e configure o jogo pra ela. Durante, observe onde ela trava sem dizer nada. Depois, colete o feedback e itere.

O que vale a pena medir: a pessoa conseguiu completar a tarefa? Quanto tempo levou? Onde travou? Precisou de ajuda externa? Em que momento ficou frustrada? Isso vale mais que qualquer checklist preenchido sozinho na sua mesa.

Guidelines e Padrões

Você não precisa inventar do zero o que oferecer. Existem padrões consolidados que servem de mapa.

As Xbox Accessibility Guidelines (XAG) são a referência mais prática. Elas listam dezenas de critérios divididos por categoria. Um bom alvo inicial cobre o que mais impacta: controles remapeáveis, opções de legenda, modos daltônicos, escala de UI e opções de dificuldade. Daí você sobe para text-to-speech, indicadores visuais e assistência de mira conforme o orçamento.

O CVAA (lei americana) exige acessibilidade em recursos de comunicação. Se seu jogo tem chat de texto ou voz, isso significa coisas como suporte a leitor de tela no chat, fonte ajustável, e alternativa em texto para voz. Vale checar se você se enquadra antes de lançar com chat.

Não tente cumprir tudo de uma vez. Pegue a lista, marque o que já tem, priorize o que falta pelo impacto, e vá implementando por release.

Casos que Valem Estudar

The Last of Us Part II

Virou o exemplo mais citado de acessibilidade porque cobre as quatro frentes com profundidade: modo de alto contraste, escala de HUD, filtros de cor e guias de navegação no visual; legendas detalhadas e indicadores de percepção no auditivo; remapeamento completo, modificadores de dificuldade granulares e travas de mira no motor. Não é pra copiar a lista inteira, é pra ver até onde dá pra ir quando se decide levar a sério desde o começo.

Celeste e o Assist Mode

O Celeste é a aula de como apresentar acessibilidade sem condescendência. As opções de assistência (dashes extras, velocidade reduzida, invencibilidade) vêm com um texto que respeita o jogador em vez de envergonhar. A mensagem deles dizia, em resumo, que o jogo foi feito pra ser difícil e que eles recomendam jogar sem assistência pra ter a experiência pretendida, mas que entendem que cada pessoa é diferente e que esperam que o modo permita que mais gente curta o jogo.

Essa é a parte que importa copiar: não é a feature, é o tom. Sem menu de vergonha, sem punição, sem julgamento. Opção é opção.

Ferramentas Úteis

Algumas coisas dá pra automatizar no seu pipeline.

Checagem de contraste. O padrão WCAG define razões de contraste mínimas: 4.5:1 para texto normal, 3:1 para texto grande, 7:1 para o nível reforçado. Dá pra escrever uma função simples que calcula a razão de contraste entre duas cores e avisa quando seu HUD não passa. A fórmula usa a luminância relativa de cada cor.

# Razão de contraste WCAG entre duas cores
func relative_luminance(c: Color) -> float:
    var ch := [c.r, c.g, c.b]
    for i in 3:
        var v: float = ch[i]
        ch[i] = v / 12.92 if v <= 0.03928 else pow((v + 0.055) / 1.055, 2.4)
    return 0.2126 * ch[0] + 0.7152 * ch[1] + 0.0722 * ch[2]

func contrast_ratio(fg: Color, bg: Color) -> float:
    var l1 := relative_luminance(fg)
    var l2 := relative_luminance(bg)
    var hi: float = max(l1, l2)
    var lo: float = min(l1, l2)
    return (hi + 0.05) / (lo + 0.05)  # >= 4.5 passa pra texto normal

Detecção de flashes. Se seu jogo tem efeitos piscando, vale rodar uma checagem que mede a variação de luminância entre frames e alerta quando passa de três flashes por segundo numa área grande. Existem ferramentas dedicadas pra isso (analisadores de fotossensibilidade), e usar uma delas antes de lançar é mais confiável que confiar no olho.

Leitor de tela e TTS. Para menus acessíveis a pessoas cegas, o Godot expõe a API de acessibilidade do sistema operacional, e há plugins de comunidade que adicionam suporte a leitor de tela. Se acessibilidade total de menu está no seu escopo, comece por aí em vez de reinventar.

Por Onde Começar

Você não precisa implementar tudo no primeiro jogo. Precisa começar, e começar cedo. A ordem que eu recomendo, da maior pra menor relação custo-benefício:

  1. Não dependa de cor sozinha pra passar informação. Custo quase zero, ajuda muito.
  2. Use ações abstratas de input desde o primeiro dia, pra remapeamento sair de graça.
  3. Legenda decente, com nome de quem fala e som ambiente importante.
  4. Escala de UI e fonte, sem texto chumbado em tamanho pequeno.
  5. Modo daltônico e contraste alto.
  6. Reduzir movimento e flashes, pra enjoo e fotossensibilidade.
  7. Teste com pessoas reais e itere.

O custo de acessibilidade planejada cedo é pequeno. O custo de enfiar tudo no final, ou de excluir jogadores sem perceber, é grande. As mesmas opções que ajudam quem tem deficiência ajudam todo mundo: legenda serve em ambiente barulhento, remapeamento serve pra preferência pessoal, auto-sprint serve pra mão cansada.

Seu próximo jogo pode ser o primeiro que alguém consegue terminar. Vale o esforço de pensar nisso desde a primeira linha de código.