sevenx_engine 0.2.11

Engine de jogos 2D/3D completa com suporte Android, física, áudio, partículas, tilemap, UI, eventos e sistema 3D avançado com PBR.
Documentation
// Demo Combinando Todas as Features Avançadas v0.2.6
use sevenx_engine::*;
use sevenx_engine::world::World;

struct AdvancedDemo {
    // Iluminação
    lighting: LightingSystem,
    player_light: usize,
    
    // Pathfinding
    pathfinder: Pathfinder,
    enemy_pos: GridPos,
    enemy_path: Option<Vec<GridPos>>,
    
    // Post-processing
    post_processor: PostProcessor,
    
    // 3D (pequeno cubo no canto)
    renderer3d: Renderer3D,
    cube: Mesh3D,
    
    // 🆕 Partículas 2D e 3D
    particle_system_2d: ParticleSystem,
    particle_system_3d: ParticleSystem3D,
    
    // 🆕 Shaders avançados
    shader_manager: ShaderManager,
    
    // Game state
    player_pos: (f32, f32),
    cell_size: i32,
    time: f32,
    toggle_cooldown: f32,
    show_particles: bool,
}

impl GameState for AdvancedDemo {
    fn new() -> Self {
        // Setup iluminação
        let mut lighting = LightingSystem::new();
        lighting.set_ambient(20, 20, 30, 0.2);
        
        let player_light = lighting.add_light(
            Light::point(400.0, 300.0, 200.0)
                .with_color(255, 200, 100)
                .with_intensity(1.0)
        );
        
        lighting.add_light(
            Light::spot(100.0, 100.0, 135.0, 45.0, 250.0)
                .with_color(100, 100, 255)
                .with_intensity(0.8)
        );

        // Setup pathfinding
        let mut pathfinder = Pathfinder::new(40, 30);
        for x in 10..30 {
            pathfinder.add_obstacle(x, 15);
        }
        for y in 5..20 {
            pathfinder.add_obstacle(20, y);
        }

        let enemy_pos = GridPos::new(35, 25);

        // Setup post-processing
        let mut post_processor = PostProcessor::new();
        post_processor.add_effect(PostEffect::Bloom {
            threshold: 0.7,
            intensity: 0.3,
        });
        post_processor.add_effect(PostEffect::Vignette {
            intensity: 0.4,
            radius: 0.9,
        });

        // Setup 3D
        let mut renderer3d = Renderer3D::new(200, 150);
        renderer3d.camera.position = Vec3::new(0.0, 2.0, 5.0);
        renderer3d.camera.look_at(Vec3::zero());
        renderer3d.wireframe = true;
        
        let mut cube = Mesh3D::cube(1.5);
        cube.position = Vec3::new(0.0, 0.0, 0.0);

        // 🆕 Setup partículas
        let particle_system_2d = ParticleSystem::new(1000)
            .with_blend_mode(BlendMode::Additive);
        let particle_system_3d = ParticleSystem3D::new(200);

        // 🆕 Setup shaders
        let mut shader_manager = ShaderManager::new();
        shader_manager.add_shader(
            Shader::new(ShaderType::Bloom)
                .with_parameter("threshold", 200.0)
                .with_parameter("bloom_intensity", 1.2)
        );

        Self {
            lighting,
            player_light,
            pathfinder,
            enemy_pos,
            enemy_path: None,
            post_processor,
            renderer3d,
            cube,
            particle_system_2d,
            particle_system_3d,
            shader_manager,
            player_pos: (400.0, 300.0),
            cell_size: 20,
            time: 0.0,
            toggle_cooldown: 0.0,
            show_particles: true,
        }
    }

    fn update(&mut self, dt: f32, input: &sevenx_engine::input::InputHandler, _world: &mut World) {
        self.time += dt;

        // Move jogador usando movimento vetorial (v0.2.7!)
        let (move_x, move_y) = input.get_movement_vector();
        let speed = if input.is_shift_pressed() { 400.0 } else { 200.0 };
        let mut moved = false;

        if move_x != 0.0 || move_y != 0.0 {
            self.player_pos.0 += move_x * speed * dt;
            self.player_pos.1 += move_y * speed * dt;
            moved = true;
        }

        // Atualiza luz do jogador
        self.lighting.lights[self.player_light].position = self.player_pos;

        // 🆕 Emite partículas quando o jogador se move
        if moved && self.show_particles {
            use rand::Rng;
            let mut rng = rand::thread_rng();
            
            // Rastro de partículas 2D
            for _ in 0..2 {
                let particle = Particle::new(
                    self.player_pos.0,
                    self.player_pos.1,
                    rng.gen_range(-20.0..20.0),
                    rng.gen_range(-20.0..20.0),
                    rng.gen_range(0.5..1.0),
                    [100, 200, 255, 200],
                    rng.gen_range(3.0..6.0),
                )
                .with_scale(1.0, -0.5);
                
                self.particle_system_2d.emit(particle);
            }
        }

        // 🆕 Toggle partículas usando just_pressed (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::KeyP) {
            self.show_particles = !self.show_particles;
            println!("💫 Partículas: {}", if self.show_particles { "ON" } else { "OFF" });
        }

        // 🆕 Emite explosão de partículas 3D usando just_pressed (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::KeyX) {
            self.particle_system_3d.explosion(Vec3::new(0.0, 0.0, 0.0));
            println!("💥 Explosão 3D!");
        }
        
        // Emite fogo com F (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::KeyF) {
            self.particle_system_3d.fire(Vec3::new(0.0, 0.0, 0.0));
            println!("🔥 Fogo!");
        }
        
        // Emite magia com M (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::KeyM) {
            self.particle_system_3d.magic(Vec3::new(0.0, 0.0, 0.0));
            println!("✨ Magia!");
        }

        // 🆕 Atualiza partículas
        self.particle_system_2d.update(dt, 100.0);
        self.particle_system_3d.update(dt);

        // Pathfinding do inimigo
        if moved || self.enemy_path.is_none() {
            let player_grid = GridPos::new(
                (self.player_pos.0 / self.cell_size as f32) as i32,
                (self.player_pos.1 / self.cell_size as f32) as i32,
            );

            self.enemy_path = self.pathfinder.find_path(self.enemy_pos, player_grid);
        }

        // Move inimigo
        if let Some(path) = &self.enemy_path {
            if path.len() > 1 && self.time.fract() < 0.1 {
                self.enemy_pos = path[1];
            }
        }

        // Rotaciona cubo 3D
        self.cube.rotation.y += dt;
        self.cube.rotation.x += dt * 0.5;

        // Toggle post-processing usando just_pressed (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::Space) {
            self.post_processor.set_enabled(!self.post_processor.enabled);
            println!("🎨 Post-Processing: {}", if self.post_processor.enabled { "ON" } else { "OFF" });
        }
    }

    fn draw(&mut self, _world: &World, frame: &mut [u8]) {
        let width = 800;
        let height = 600;

        // 1. Desenha grid com iluminação
        for y in 0..self.pathfinder.grid_height {
            for x in 0..self.pathfinder.grid_width {
                let pos = GridPos::new(x, y);
                let px = (x * self.cell_size) as f32;
                let py = (y * self.cell_size) as f32;

                let base_color = if self.pathfinder.obstacles.contains(&pos) {
                    [80, 50, 50, 255]
                } else if pos == self.enemy_pos {
                    [255, 50, 50, 255]
                } else {
                    let checker = ((x + y) % 2 == 0) as u8;
                    let c = 60 + checker * 20;
                    [c, c, c, 255]
                };

                // Aplica iluminação
                for dy in 0..self.cell_size {
                    for dx in 0..self.cell_size {
                        let screen_x = px + dx as f32;
                        let screen_y = py + dy as f32;
                        
                        if screen_x < width as f32 && screen_y < height as f32 {
                            let lit_color = self.lighting.apply_lighting(
                                screen_x,
                                screen_y,
                                base_color
                            );

                            let idx = ((screen_y as u32 * width + screen_x as u32) * 4) as usize;
                            if idx + 3 < frame.len() {
                                frame[idx..idx + 4].copy_from_slice(&lit_color);
                            }
                        }
                    }
                }
            }
        }

        // 2. Desenha caminho do inimigo
        if let Some(path) = &self.enemy_path {
            for pos in path {
                let px = pos.x * self.cell_size;
                let py = pos.y * self.cell_size;
                
                for dy in 2..(self.cell_size - 2) {
                    for dx in 2..(self.cell_size - 2) {
                        let x = px + dx;
                        let y = py + dy;
                        if x >= 0 && x < width as i32 && y >= 0 && y < height as i32 {
                            let idx = ((y * width as i32 + x) * 4) as usize;
                            if idx + 3 < frame.len() {
                                frame[idx] = 100;
                                frame[idx + 1] = 150;
                                frame[idx + 2] = 255;
                                frame[idx + 3] = 255;
                            }
                        }
                    }
                }
            }
        }

        // 3. Desenha jogador
        let px = self.player_pos.0 as i32;
        let py = self.player_pos.1 as i32;
        for dy in -8..=8 {
            for dx in -8..=8 {
                if dx * dx + dy * dy <= 64 {
                    let x = px + dx;
                    let y = py + dy;
                    if x >= 0 && x < width as i32 && y >= 0 && y < height as i32 {
                        let idx = ((y * width as i32 + x) * 4) as usize;
                        if idx + 3 < frame.len() {
                            frame[idx] = 255;
                            frame[idx + 1] = 255;
                            frame[idx + 2] = 0;
                            frame[idx + 3] = 255;
                        }
                    }
                }
            }
        }

        // 4. Renderiza cubo 3D no canto (mini preview)
        let mut mini_frame = vec![0u8; 200 * 150 * 4];
        for pixel in mini_frame.chunks_exact_mut(4) {
            pixel.copy_from_slice(&[30, 30, 50, 255]);
        }
        
        self.renderer3d.render_mesh(&self.cube, &mut mini_frame, 200, 150);
        
        // Copia mini frame para o canto superior direito
        for y in 0..150 {
            for x in 0..200 {
                let src_idx = ((y * 200 + x) * 4) as usize;
                let dst_x = width - 210 + x;
                let dst_y = 10 + y;
                let dst_idx = ((dst_y * width + dst_x) * 4) as usize;
                
                if dst_idx + 3 < frame.len() && src_idx + 3 < mini_frame.len() {
                    frame[dst_idx..dst_idx + 4].copy_from_slice(&mini_frame[src_idx..src_idx + 4]);
                }
            }
        }

        // 🆕 4.5. Renderiza partículas 2D
        if self.show_particles {
            self.particle_system_2d.render(frame, 0.0, 0.0, width, height);
        }

        // 🆕 4.6. Aplica shaders avançados
        self.shader_manager.apply_all(frame, width, height);

        // 5. Aplica post-processing
        self.post_processor.apply(frame, width, height);

        // 6. Desenha UI/texto
        let text = format!(
            "SPACE: Post-Processing {} | P: Particles {} | X: Explosion 3D | Particles: {}",
            if self.post_processor.enabled { "ON" } else { "OFF" },
            if self.show_particles { "ON" } else { "OFF" },
            self.particle_system_2d.count()
        );
        
        // Texto simples (você pode usar o sistema de UI da engine)
        // Por simplicidade, apenas desenhamos um retângulo de fundo
        for y in 550..580 {
            for x in 10..300 {
                let idx = ((y * width + x) * 4) as usize;
                if idx + 3 < frame.len() {
                    frame[idx] = 0;
                    frame[idx + 1] = 0;
                    frame[idx + 2] = 0;
                    frame[idx + 3] = 200;
                }
            }
        }
    }
}

fn main() {
    println!("🎮 SevenX Engine v0.2.7 - Advanced Features Demo");
    println!("✨ Features:");
    println!("   💡 Sistema de Iluminação");
    println!("   🗺️ Pathfinding A*");
    println!("   🎨 Post-Processing");
    println!("   🎲 Renderização 3D");
    println!("   💫 Partículas 2D e 3D");
    println!("   🎨 Shaders Avançados");
    println!();
    println!("🎯 Controles:");
    println!("   WASD/Setas - Mover (Shift para correr)");
    println!("   Space - Toggle Post-Processing");
    println!("   P - Toggle Partículas");
    println!("   X - Explosão 3D");
    println!("   F - Fogo 3D");
    println!("   M - Magia 3D");
    println!();

    let config = EngineConfig::default()
        .with_title("SevenX Engine v0.2.7 - Advanced Features Demo")
        .with_size(800, 600);

    let engine = Engine::with_config(config);
    engine.run::<AdvancedDemo>();
}