# 🎮 Tutorial de Jogos - SevenX Engine v0.2.6
## 📚 Tutoriais Disponíveis
1. [Jogo Básico - Movimento Simples](#tutorial-1-jogo-básico)
2. [Jogo com Partículas](#tutorial-2-jogo-com-partículas)
3. [Jogo com Shaders](#tutorial-3-jogo-com-shaders)
4. [Jogo 3D Simples](#tutorial-4-jogo-3d-simples)
---
## Tutorial 1: Jogo Básico
### Objetivo
Criar um quadrado que se move com as setas.
### Código Completo
```rust
use sevenx_engine::*;
use sevenx_engine::world::World;
struct MeuJogo {
player_x: f32,
player_y: f32,
}
impl GameState for MeuJogo {
fn new() -> Self {
Self {
player_x: 400.0,
player_y: 300.0,
}
}
fn update(&mut self, dt: f32, input: &sevenx_engine::input::InputHandler, _world: &mut World) {
let speed = 200.0;
if input.is_key_pressed(KeyCode::ArrowUp) {
self.player_y -= speed * dt;
}
if input.is_key_pressed(KeyCode::ArrowDown) {
self.player_y += speed * dt;
}
if input.is_key_pressed(KeyCode::ArrowLeft) {
self.player_x -= speed * dt;
}
if input.is_key_pressed(KeyCode::ArrowRight) {
self.player_x += speed * dt;
}
}
fn draw(&mut self, _world: &World, frame: &mut [u8]) {
// Limpa tela (azul escuro)
for pixel in frame.chunks_exact_mut(4) {
pixel.copy_from_slice(&[40, 40, 60, 255]);
}
// Desenha jogador (verde)
let size = 20;
for y in -size..size {
for x in -size..size {
let px = (self.player_x as i32 + x) as usize;
let py = (self.player_y as i32 + y) as usize;
if px < 800 && py < 600 {
let idx = (py * 800 + px) * 4;
if idx + 3 < frame.len() {
frame[idx] = 100;
frame[idx + 1] = 255;
frame[idx + 2] = 100;
frame[idx + 3] = 255;
}
}
}
}
}
}
fn main() {
let config = EngineConfig::default()
.with_title("Meu Primeiro Jogo")
.with_size(800, 600);
Engine::with_config(config).run::<MeuJogo>();
}
```
### Como Executar
```bash
cargo run
```
### Controles
- **Setas**: Mover o quadrado verde
---
## Tutorial 2: Jogo com Partículas
### Objetivo
Adicionar partículas que seguem o jogador.
### Código Completo
```rust
use sevenx_engine::*;
use sevenx_engine::world::World;
struct JogoParticulas {
player_x: f32,
player_y: f32,
particles: ParticleSystem,
}
impl GameState for JogoParticulas {
fn new() -> Self {
let particles = ParticleSystem::new(1000)
.with_blend_mode(BlendMode::Additive);
Self {
player_x: 400.0,
player_y: 300.0,
particles,
}
}
fn update(&mut self, dt: f32, input: &sevenx_engine::input::InputHandler, _world: &mut World) {
let speed = 200.0;
let mut moved = false;
if input.is_key_pressed(KeyCode::ArrowUp) {
self.player_y -= speed * dt;
moved = true;
}
if input.is_key_pressed(KeyCode::ArrowDown) {
self.player_y += speed * dt;
moved = true;
}
if input.is_key_pressed(KeyCode::ArrowLeft) {
self.player_x -= speed * dt;
moved = true;
}
if input.is_key_pressed(KeyCode::ArrowRight) {
self.player_x += speed * dt;
moved = true;
}
// Emite rastro de partículas
if moved {
use rand::Rng;
let mut rng = rand::thread_rng();
for _ in 0..3 {
let particle = Particle::new(
self.player_x,
self.player_y,
rng.gen_range(-30.0..30.0),
rng.gen_range(-30.0..30.0),
1.0,
[100, 200, 255, 200],
5.0,
)
.with_scale(1.0, -0.5);
self.particles.emit(particle);
}
}
// Explosão com SPACE
if input.is_key_pressed(KeyCode::Space) {
let config = ParticleConfig::explosion();
self.particles.emit_burst(self.player_x, self.player_y, 50, config);
}
self.particles.update(dt, 100.0);
}
fn draw(&mut self, _world: &World, frame: &mut [u8]) {
// Limpa tela
for pixel in frame.chunks_exact_mut(4) {
pixel.copy_from_slice(&[20, 20, 30, 255]);
}
// Renderiza partículas
self.particles.render(frame, 0.0, 0.0, 800, 600);
// Desenha jogador (círculo amarelo)
let size = 15;
for y in -size..size {
for x in -size..size {
if x * x + y * y <= size * size {
let px = (self.player_x as i32 + x) as usize;
let py = (self.player_y as i32 + y) as usize;
if px < 800 && py < 600 {
let idx = (py * 800 + px) * 4;
if idx + 3 < frame.len() {
frame[idx] = 255;
frame[idx + 1] = 255;
frame[idx + 2] = 100;
frame[idx + 3] = 255;
}
}
}
}
}
}
}
fn main() {
let config = EngineConfig::default()
.with_title("Jogo com Partículas")
.with_size(800, 600);
Engine::with_config(config).run::<JogoParticulas>();
}
```
### Controles
- **Setas**: Mover (emite rastro)
- **SPACE**: Explosão de partículas
---
## Tutorial 3: Jogo com Shaders
### Objetivo
Adicionar efeitos visuais com shaders.
### Código Completo
```rust
use sevenx_engine::*;
use sevenx_engine::world::World;
struct JogoShaders {
player_x: f32,
player_y: f32,
shader_manager: ShaderManager,
time: f32,
}
impl GameState for JogoShaders {
fn new() -> Self {
let mut shader_manager = ShaderManager::new();
shader_manager.add_shader(
Shader::new(ShaderType::Bloom)
.with_parameter("threshold", 200.0)
.with_parameter("bloom_intensity", 1.5)
);
Self {
player_x: 400.0,
player_y: 300.0,
shader_manager,
time: 0.0,
}
}
fn update(&mut self, dt: f32, input: &sevenx_engine::input::InputHandler, _world: &mut World) {
self.time += dt;
let speed = 200.0;
if input.is_key_pressed(KeyCode::ArrowUp) {
self.player_y -= speed * dt;
}
if input.is_key_pressed(KeyCode::ArrowDown) {
self.player_y += speed * dt;
}
if input.is_key_pressed(KeyCode::ArrowLeft) {
self.player_x -= speed * dt;
}
if input.is_key_pressed(KeyCode::ArrowRight) {
self.player_x += speed * dt;
}
// Alterna shaders
if input.is_key_pressed(KeyCode::Digit1) {
self.shader_manager.clear_shaders();
self.shader_manager.add_shader(
Shader::new(ShaderType::Bloom)
.with_parameter("threshold", 200.0)
.with_parameter("bloom_intensity", 1.5)
);
}
if input.is_key_pressed(KeyCode::Digit2) {
self.shader_manager.clear_shaders();
self.shader_manager.add_shader(
Shader::new(ShaderType::HueShift)
.with_parameter("shift", (self.time * 50.0) % 360.0)
);
}
if input.is_key_pressed(KeyCode::Digit3) {
self.shader_manager.clear_shaders();
self.shader_manager.add_shader(
Shader::new(ShaderType::Glitch)
.with_parameter("glitch_intensity", 0.1)
);
}
}
fn draw(&mut self, _world: &World, frame: &mut [u8]) {
// Limpa tela
for pixel in frame.chunks_exact_mut(4) {
pixel.copy_from_slice(&[30, 30, 50, 255]);
}
// Desenha jogador brilhante
let size = 20;
for y in -size..size {
for x in -size..size {
if x * x + y * y <= size * size {
let px = (self.player_x as i32 + x) as usize;
let py = (self.player_y as i32 + y) as usize;
if px < 800 && py < 600 {
let idx = (py * 800 + px) * 4;
if idx + 3 < frame.len() {
frame[idx] = 255;
frame[idx + 1] = 255;
frame[idx + 2] = 100;
frame[idx + 3] = 255;
}
}
}
}
}
// Aplica shaders
self.shader_manager.apply_all(frame, 800, 600);
}
}
fn main() {
let config = EngineConfig::default()
.with_title("Jogo com Shaders")
.with_size(800, 600);
Engine::with_config(config).run::<JogoShaders>();
}
```
### Controles
- **Setas**: Mover
- **1**: Bloom (brilho)
- **2**: Hue Shift (mudança de cor)
- **3**: Glitch (falha digital)
---
## Tutorial 4: Jogo 3D Simples
### Objetivo
Criar um cubo 3D rotacionando.
### Código Completo
```rust
use sevenx_engine::*;
use sevenx_engine::world::World;
struct Jogo3D {
renderer3d: Renderer3D,
cube: Mesh3D,
rotation: f32,
}
impl GameState for Jogo3D {
fn new() -> Self {
let mut cube = Mesh3D::cube(3.0);
cube.position = Vec3::new(0.0, 0.0, 0.0);
let mut renderer3d = Renderer3D::new(800, 600);
renderer3d.camera.position = Vec3::new(0.0, 3.0, 10.0);
renderer3d.camera.look_at(Vec3::zero());
renderer3d.wireframe = true;
Self {
renderer3d,
cube,
rotation: 0.0,
}
}
fn update(&mut self, dt: f32, input: &sevenx_engine::input::InputHandler, _world: &mut World) {
// Rotaciona automaticamente
self.rotation += dt;
self.cube.rotation.y = self.rotation;
self.cube.rotation.x = self.rotation * 0.5;
// Controles de câmera
if input.is_key_pressed(KeyCode::KeyW) {
self.renderer3d.camera.position.z -= 5.0 * dt;
}
if input.is_key_pressed(KeyCode::KeyS) {
self.renderer3d.camera.position.z += 5.0 * dt;
}
// Toggle wireframe
if input.is_key_pressed(KeyCode::Space) {
self.renderer3d.wireframe = !self.renderer3d.wireframe;
}
}
fn draw(&mut self, _world: &World, frame: &mut [u8]) {
// Limpa tela (azul escuro)
for pixel in frame.chunks_exact_mut(4) {
pixel.copy_from_slice(&[20, 30, 50, 255]);
}
// Renderiza cubo 3D
self.renderer3d.render_mesh(&self.cube, frame, 800, 600);
}
}
fn main() {
let config = EngineConfig::default()
.with_title("Jogo 3D Simples")
.with_size(800, 600);
Engine::with_config(config).run::<Jogo3D>();
}
```
### Controles
- **W/S**: Aproximar/Afastar câmera
- **SPACE**: Toggle wireframe/sólido
---
## 🎓 Próximos Passos
### Exemplos Avançados
Veja os exemplos incluídos na engine:
```bash
# FPS 3D completo
cargo run --example fps_3d_game
# Partículas 2D avançadas
cargo run --example particles_2d_advanced
# 3D com partículas
cargo run --example 3d_demo
# Features avançadas
cargo run --example advanced_features_demo
```
### Documentação
- **API_REFERENCE.md** - Referência completa da API
- **FAQ.md** - Perguntas frequentes
- **FPS_3D_GUIDE.md** - Guia do FPS 3D
- **3D_GUIDE.md** - Guia de renderização 3D
---
## 💡 Dicas
### Performance
- Limite partículas a 500-1000
- Use no máximo 3-4 shaders simultâneos
- Shaders pesados: Bloom, GaussianBlur, OilPainting
### Debug
- Use `println!` para debug
- Verifique FPS: `let fps = 1.0 / dt;`
- Use wireframe para debug 3D
### Boas Práticas
- Comece simples e adicione features gradualmente
- Teste frequentemente com `cargo run`
- Leia os exemplos incluídos
- Consulte a documentação
---
## 🆘 Problemas Comuns
### Tela preta?
- Verifique se está desenhando no método `draw()`
- Certifique-se de limpar a tela primeiro
- Verifique os índices do array `frame`
### Não compila?
- Verifique os imports: `use sevenx_engine::*;`
- Use `sevenx_engine::input::InputHandler` no update
- Adicione `use sevenx_engine::world::World;`
### Performance ruim?
- Reduza número de partículas
- Limite shaders simultâneos
- Use menos objetos 3D
---
## 🎮 Divirta-se Criando!
Agora você tem tudo para criar seus próprios jogos com SevenX Engine!
**Boa sorte! 🚀✨**