Input

Esta página foi traduzida automaticamente e pode conter erros. Encontrou um problema? Use o link "Edit this page" para ajudar a corrigir.

O sistema de input da Turian desacopla os dispositivos físicos da lógica do jogo através de ações nomeadas. Você define as ações em um asset .inputactions — mapeamentos de teclado, mouse e controle (gamepad) todos apontam para o mesmo nome de ação — e seus scripts apenas perguntam "a ação jump foi pressionada?", nunca "a tecla Espaço está pressionada?".


Início rápido

1. Criar um asset de Input Actions

No Asset Browser, clique com o botão direito → Create → Input Actions. Isso gera um arquivo .inputactions padrão (formato ZON) na pasta selecionada.

Dê um duplo clique no arquivo para abrir o Input Actions Editor.

2. Definir suas ações

O editor mostra uma lista de ações. Cada ação possui:

  • Name (Nome) — a string que seu script usará (ex: jump, move, look).
  • Kind (Tipo) — button (ligado/desligado), axis (1D −1…+1) ou vector (2D, x/y).
  • Roles (Papéis) — Positive/Negative para eixos (axis); Right/Left/Up/Down para vetores (vector); Buttons para botões (button). Cada papel suporta até 4 mapeamentos.

Para cada mapeamento, escolha um device (dispositivo) e um code (código):

Dispositivo (Device) Exemplos de código (Code)
key a, space, left_shift, left_ctrl
mouse right, left, middle
gamepad_button south, east, left_shoulder, left_trigger
gamepad_axis left_x, left_y, right_x, right_y, left_trigger, right_trigger

Para gamepad_axis, a caixa de seleção + seleciona a direção positiva desse eixo (ex: analógico para a direita, gatilho pressionado). Desmarque para a direção negativa.

Clique em Save para salvar o arquivo ZON e recompilá-lo (re-cook) no projeto.

3. Empacotar o asset

O carregador do jogo descobre cada asset .inputactions no seu projeto automaticamente — sem necessidade de código. O asset é aplicado ao engine.Input compartilhado na inicialização.


Lendo ações em um script

Os scripts recebem o contexto engine.Frame através do método update. frame.input é um *const engine.Input:

const engine = @import("engine");

pub const PlayerController = struct {
    pub const is_component = true;

    speed: f32 = 5.0,

    pub fn update(self: *@This(), frame: engine.Frame) void {
        const input = frame.input;
        const dt    = frame.time.delta;
        const t     = frame.transform;

        // Ação de botão — digital ligado/desligado (on/off)
        if (input.wasPressed("jump")) {
            // apenas borda de subida (rising edge)
        }

        // Ação de eixo — valor contínuo 1D
        const throttle = input.axis("throttle"); // -1..+1

        // Ação vetorial — 2D (ex: WASD / analógico esquerdo)
        const move = input.vector("move"); // .x = direita, .y = frente
        t.position.x += move.x * self.speed * dt;
        t.position.z += move.y * self.speed * dt;
    }
};

API de consulta de ações

Método Retorna Significado
isPressed(name) bool valor da ação ≥ limiar (pressionado)
wasPressed(name) bool subiu acima do limiar neste frame
axis(name) f32 valor 1D, −1…+1, com zona morta (deadzone)
vector(name) engine.Vector2 valor 2D, limitado ao círculo unitário

Todos os quatro funcionam da mesma forma, independentemente do mapeamento ser uma tecla, um botão do mouse ou analógico do controle — o tipo de ação apenas determina qual consulta faz sentido semântico.


Consultas brutas de dispositivos

Para interfaces gráficas (UI) ou código de debug que precisam de estados específicos de dispositivos, o frame.input também expõe consultas brutas (raw):

// Teclado
if (input.isKeyDown(.space)) { ... }
if (input.wasKeyPressed(.a)) { ... }

// Mouse
const delta = input.mouseDelta(); // pixels .x / .y neste frame
const wheel = input.wheelDelta(); // passos da roda do mouse neste frame
if (input.isMouseDown(.right)) { ... }

// Controle (Gamepad)
const lx = input.gamepadAxis(.left_x); // -1..+1
if (input.isGamepadButtonDown(.south)) { ... }

Exemplo: câmera livre (freefly camera)

O projeto de exemplo inclui o arquivo FreeflyCamera.zig, que controla uma câmera sem colisão (no-clip) tanto por teclado+mouse quanto por controle usando os mesmos nomes de ação:

move        — WASD / analógico esquerdo
look_axis   — analógico direito (analógico, independente de framerate)
ascend      — Space / botão A / gatilho direito
descend     — LShift / botão B / gatilho esquerdo
boost       — LCtrl / botão superior esquerdo (left shoulder)
look        — segurar botão direito do mouse para olhar com o delta do mouse

O script lê apenas ações — ele nunca menciona um código de tecla físico. Remapeie tudo em player-controls.inputactions sem alterar o FreeflyCamera.zig.


Reconfiguração em tempo de execução (rebinding)

O engine expõe duas funções para menus do tipo "pressione uma tecla para remapear" no jogo:

// Em uma atualização do menu de configurações:
if (frame.input.captureBinding()) |binding| {
    // Usuário pressionou algo — aplicar
    _ = frame.input.rebind("jump", .pos, 0, binding);
}

captureBinding() retorna a primeira tecla recém-pressionada, botão do mouse, botão do controle ou eixo do controle que cruzou o limiar de pressionamento. rebind substitui ou anexa um mapeamento pelo nome da ação, papel (.pos/.neg/.up/.down) e índice.

Persistência: salvar mapeamentos alterados entre sessões requer o sistema de configurações (issue #13, ainda não implementado). Acompanhe o progresso na issue #42.


Referência do engine.Frame

Cada hook do ciclo de vida que recebe um segundo parâmetro recebe o engine.Frame:

pub fn update(self: *@This(), frame: engine.Frame) void
pub fn start(self: *@This(),  frame: engine.Frame) void
// awake, enable, disable, destroy também aceitam frame
Campo Tipo Significado
frame.time engine.Time delta, tempo decorrido, contador de frames
frame.input *const engine.Input consultas de ações + estado bruto do dispositivo
frame.transform *engine.Transform posição/rotação/escala deste objeto
frame.objects []engine.SceneNode todos os objetos na cena
frame.services *engine.Services registro de serviços cadastrados pelo usuário

Use frame.service(MyService) para uma busca tipada de ?*MyService em frame.services.

A assinatura legada update(self, time: engine.Time) ainda é suportada para compatibilidade retroativa.


← Toda a documentação Editar esta página