Tutorial
Este tutorial orienta você a abrir um projeto de exemplo, escrever componentes de script e compilar seu primeiro jogo.
1. Iniciar o editor
zig build run
O Turian Studio abre com uma cena padrão (chão, câmera, luz direcional).
2. Abrir um projeto de exemplo
- Escolha File → Open Project…
- Navegue até
examples/basic-project/e confirme. - O Asset Browser exibe a pasta
assets/do projeto. - Dê um duplo clique em
scene-01.prefabpara carregar a cena.
3. Layout do editor
┌──────────────┬──────────────────────┬────────────────┐
│ Scene │ Scene View │ Inspector │
│ Hierarchy │ (3D viewport) │ │
├──────────────┴──────────────────────┴────────────────┤
│ Asset Browser │
└───────────────────────────────────────────────────────┘
- Scene Hierarchy — exibe cada GameObject; clique para selecionar, arraste para reordenar.
- Scene View — pré-visualização 3D em tempo real (GPU SDL3 — Vulkan/Metal/D3D12).
- Inspector — edite o Transform e os campos dos componentes no objeto selecionado.
- Asset Browser — navegue pela pasta
assets/; dê um duplo clique nos arquivos de cena.prefabpara abri-los.
4. Adicionar um game object
- Scene → Add Empty Object (ou clique no item do menu).
- Selecione-o na hierarquia.
- No Inspector, expanda o Transform e configure a Position (Posição) como
(0, 1, 0). - Clique em Add Component ▾ → MeshRenderer.
5. Escrever um componente de script
Crie assets/spinner.zig dentro da pasta do seu projeto:
const engine = @import("engine");
pub const Spinner = struct {
/// Marca esta struct como um componente que o editor deve descobrir.
pub const is_component = true;
/// Velocidade de rotação em graus por segundo (editável no Inspector).
speed: f32 = 90.0,
pub fn awake(self: *Spinner) void {
_ = self;
@import("std").debug.print("[Spinner] awake\n", .{});
}
pub fn update(self: *Spinner, time: engine.Time) void {
_ = self.speed * time.delta; // aplica rotação assim que a API de cena estiver disponível
}
};
Regras principais:
- Adicione
pub const is_component = true;dentro da struct para marcá-la para descoberta. O editor analisa o código-fonte em Zig (e não por expressão regular), portanto o marcador funciona independentemente de formatação, comentários ou compilação condicional. Defina comofalsepara desativar temporariamente a struct. - A struct deve ser
pube nomeada começando com uma letra maiúscula. - O nome de cada tipo de componente deve ser único em todo o projeto — duplicatas são relatadas e a segunda ocorrência é ignorada.
- Tipos de campos suportados:
f32,i32,bool,engine.Vec3,engine.GameObjectRef,engine.ComponentRef,engine.AssetRef.
Clique em Refresh no cabeçalho do Asset Browser para carregar o novo script e, em seguida, adicione o Spinner via Add Component ▾.
6. Hooks de ciclo de vida do script
Todos os hooks são opcionais — implemente apenas os que precisar:
| Hook | Chamado quando |
|---|---|
awake(self) |
O objeto é carregado pela primeira vez |
enable(self) |
O objeto se torna ativo |
start(self) |
A cena começa a rodar |
update(self, frame: engine.Frame) |
A cada frame (preferencial) |
update(self, time: engine.Time) |
A cada frame (legado) |
disable(self) |
O objeto se torna inativo |
destroy(self) |
O objeto é destruído |
Todos os hooks também aceitam frame: engine.Frame como segundo parâmetro — use update(self, frame: engine.Frame) para acessar input, serviços e o contexto completo da cena. Consulte o guia do Sistema de Input.
Campos do engine.Time (também disponíveis como frame.time):
.delta— segundos desde o último frame (f32).elapsed— total de segundos desde o início da cena (f32).frame— contador de frames (u64)
Exemplo de contador de FPS
const std = @import("std");
const engine = @import("engine");
pub const FpsDisplay = struct {
pub const is_component = true;
_timer: f32 = 0,
pub fn update(self: *FpsDisplay, time: engine.Time) void {
self._timer += time.delta;
if (self._timer >= 1.0) {
self._timer -= 1.0;
const fps = if (time.delta > 0) 1.0 / time.delta else 0.0;
std.debug.print("FPS: {d:.0}\n", .{fps});
}
}
};
Exemplo de referência de objeto
const engine = @import("engine");
pub const Follower = struct {
pub const is_component = true;
/// Arraste um game object a partir do Scene Hierarchy para este campo.
target: engine.GameObjectRef = .{},
pub fn start(self: *Follower) void {
const name = self.target.slice();
if (name.len > 0) {
@import("std").debug.print("[Follower] following '{s}'\n", .{name});
}
}
};
7. Salvar a cena
File → Save Scene grava assets/scene-01.prefab — um arquivo JSON legível por humanos que você pode analisar (diff) e comitar no Git.
8. Compilar o jogo
Via editor
Build → Build Game compila um executável independente em .cache/zig-out/bin/game dentro da pasta do projeto.
Via CLI
zig build cli -- build path/to/my-project
Ou com o binário instalado:
turian-cli build path/to/my-project
turian-cli new-project ../my-new-game "My Game" # cria um projeto
turian-cli info path/to/my-project # exibe metadados
9. Usando a biblioteca matemática
const math = @import("engine").math;
const pos = math.Vector3{ .x = 0, .y = 1, .z = 0 };
const rot = math.Quaternion.fromAxisAngle(math.Vector3.up(), 45.0);
const m = rot.toMatrix4();
const col = math.Vector3i{ .x = 255, .y = 128, .z = 0 }; // vetor de inteiros
Tipos disponíveis: Vector2, Vector3, Vector4, Vector2i, Vector3i, Vector4i, Matrix4, Quaternion.
Próximos passos
- Leia Instalação / compilar a partir do código-fonte para a configuração completa de desenvolvimento.
- Navegue pela [pasta de exemplos]({{ site.Params.Repo }}/-/tree/main/examples) para ver templates de projeto mais completos.
- Veja o guia do Sistema de Input para adicionar mapas de ação, suporte a gamepads e remapeamento em tempo de execução.
- Verifique a referência de campos de componentes no Inspector — passe o mouse sobre o rótulo de qualquer campo para obter informações sobre seu tipo.