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 2D Avançado - Partículas e Shaders
use sevenx_engine::*;
use sevenx_engine::world::World;

struct ParticlesDemo {
    particle_system: ParticleSystem,
    shader_manager: ShaderManager,
    time: f32,
    effect_mode: usize,
    shader_mode: usize,
    toggle_cooldown: f32,
}

impl GameState for ParticlesDemo {
    fn new() -> Self {
        let particle_system = ParticleSystem::new(2000)
            .with_blend_mode(BlendMode::Additive)
            .with_drag(0.5);

        let mut shader_manager = ShaderManager::new();
        
        // Adiciona bloom por padrão
        shader_manager.add_shader(
            Shader::new(ShaderType::Bloom)
                .with_parameter("threshold", 180.0)
                .with_parameter("bloom_intensity", 1.5)
        );

        Self {
            particle_system,
            shader_manager,
            time: 0.0,
            effect_mode: 0,
            shader_mode: 0,
            toggle_cooldown: 0.0,
        }
    }

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

        // Alterna efeito de partículas (1-6)
        if input.is_key_pressed(KeyCode::Digit1) && self.toggle_cooldown <= 0.0 {
            self.effect_mode = 0;
            self.toggle_cooldown = 0.3;
        }
        if input.is_key_pressed(KeyCode::Digit2) && self.toggle_cooldown <= 0.0 {
            self.effect_mode = 1;
            self.toggle_cooldown = 0.3;
        }
        if input.is_key_pressed(KeyCode::Digit3) && self.toggle_cooldown <= 0.0 {
            self.effect_mode = 2;
            self.toggle_cooldown = 0.3;
        }
        if input.is_key_pressed(KeyCode::Digit4) && self.toggle_cooldown <= 0.0 {
            self.effect_mode = 3;
            self.toggle_cooldown = 0.3;
        }
        if input.is_key_pressed(KeyCode::Digit5) && self.toggle_cooldown <= 0.0 {
            self.effect_mode = 4;
            self.toggle_cooldown = 0.3;
        }
        if input.is_key_pressed(KeyCode::Digit6) && self.toggle_cooldown <= 0.0 {
            self.effect_mode = 5;
            self.toggle_cooldown = 0.3;
        }

        // Alterna shader (Q/W/E/R)
        if input.is_key_pressed(KeyCode::KeyQ) && self.toggle_cooldown <= 0.0 {
            self.shader_mode = 0;
            self.update_shaders();
            self.toggle_cooldown = 0.3;
        }
        if input.is_key_pressed(KeyCode::KeyW) && self.toggle_cooldown <= 0.0 {
            self.shader_mode = 1;
            self.update_shaders();
            self.toggle_cooldown = 0.3;
        }
        if input.is_key_pressed(KeyCode::KeyE) && self.toggle_cooldown <= 0.0 {
            self.shader_mode = 2;
            self.update_shaders();
            self.toggle_cooldown = 0.3;
        }
        if input.is_key_pressed(KeyCode::KeyR) && self.toggle_cooldown <= 0.0 {
            self.shader_mode = 3;
            self.update_shaders();
            self.toggle_cooldown = 0.3;
        }

        // Limpa partículas (Space)
        if input.is_key_pressed(KeyCode::Space) {
            self.particle_system.clear();
        }

        // Emite partículas baseado no modo
        self.emit_particles();

        // Atualiza partículas
        self.particle_system.update(dt, 200.0);
    }

    fn draw(&mut self, _world: &World, frame: &mut [u8]) {
        // Limpa a tela
        for pixel in frame.chunks_exact_mut(4) {
            pixel[0] = 10;
            pixel[1] = 10;
            pixel[2] = 20;
            pixel[3] = 255;
        }

        // Renderiza partículas
        self.particle_system.render(frame, 0.0, 0.0, 800, 600);

        // Aplica shaders
        self.shader_manager.apply_all(frame, 800, 600);

        // Desenha UI
        self.draw_ui(frame);
    }
}

impl ParticlesDemo {
    fn emit_particles(&mut self) {
        use rand::Rng;
        let mut rng = rand::thread_rng();

        match self.effect_mode {
            0 => {
                // Explosão com turbulência
                if self.time.fract() < 0.016 {
                    for _ in 0..5 {
                        let angle = rng.gen_range(0.0..std::f32::consts::TAU);
                        let speed = rng.gen_range(100.0..300.0);
                        
                        let particle = Particle::new(
                            400.0,
                            300.0,
                            angle.cos() * speed,
                            angle.sin() * speed,
                            rng.gen_range(1.0..2.5),
                            [255, rng.gen_range(100..200), 50, 255],
                            rng.gen_range(4.0..8.0),
                        )
                        .with_turbulence(10.0)
                        .with_color_shift([-100.0, -50.0, 0.0, 0.0])
                        .with_scale(1.0, -0.4)
                        .with_rotation(0.0, rng.gen_range(-10.0..10.0));
                        
                        self.particle_system.emit(particle);
                    }
                }
            }
            1 => {
                // Fogo com color shift
                if self.time.fract() < 0.016 {
                    for _ in 0..8 {
                        let offset_x = rng.gen_range(-20.0..20.0);
                        let particle = Particle::new(
                            400.0 + offset_x,
                            550.0,
                            rng.gen_range(-10.0..10.0),
                            rng.gen_range(-150.0..-50.0),
                            rng.gen_range(1.0..2.0),
                            [255, rng.gen_range(150..255), 0, 255],
                            rng.gen_range(5.0..10.0),
                        )
                        .with_turbulence(5.0)
                        .with_color_shift([-80.0, -100.0, 0.0, 0.0])
                        .with_scale(1.0, -0.3)
                        .with_acceleration(0.0, -20.0);
                        
                        self.particle_system.emit(particle);
                    }
                }
            }
            2 => {
                // Magia multicolorida
                if self.time.fract() < 0.016 {
                    for _ in 0..6 {
                        let angle = self.time * 2.0 + rng.gen_range(0.0..1.0);
                        let radius = 100.0;
                        let x = 400.0 + angle.cos() * radius;
                        let y = 300.0 + angle.sin() * radius;
                        
                        let hue = (self.time * 100.0 + rng.gen_range(0.0..60.0)) % 360.0;
                        let color = self.hsv_to_rgb(hue, 1.0, 1.0);
                        
                        let particle = Particle::new(
                            x,
                            y,
                            -angle.cos() * 50.0,
                            -angle.sin() * 50.0,
                            rng.gen_range(1.0..2.0),
                            color,
                            rng.gen_range(3.0..6.0),
                        )
                        .with_rotation(0.0, rng.gen_range(-15.0..15.0))
                        .with_scale(1.0, -0.2)
                        .with_turbulence(3.0);
                        
                        self.particle_system.emit(particle);
                    }
                }
            }
            3 => {
                // Fumaça com aceleração
                if self.time.fract() < 0.016 {
                    for _ in 0..3 {
                        let particle = Particle::new(
                            400.0 + rng.gen_range(-30.0..30.0),
                            500.0,
                            rng.gen_range(-20.0..20.0),
                            rng.gen_range(-80.0..-40.0),
                            rng.gen_range(2.0..4.0),
                            [rng.gen_range(80..120), rng.gen_range(80..120), rng.gen_range(80..120), 180],
                            rng.gen_range(8.0..15.0),
                        )
                        .with_turbulence(8.0)
                        .with_scale(1.0, 0.5)
                        .with_acceleration(0.0, -10.0);
                        
                        self.particle_system.emit(particle);
                    }
                }
            }
            4 => {
                // Faíscas rápidas
                if self.time.fract() < 0.016 {
                    for _ in 0..10 {
                        let angle = rng.gen_range(0.0..std::f32::consts::TAU);
                        let speed = rng.gen_range(200.0..400.0);
                        
                        let particle = Particle::new(
                            400.0,
                            300.0,
                            angle.cos() * speed,
                            angle.sin() * speed,
                            rng.gen_range(0.3..0.8),
                            [255, 255, rng.gen_range(100..255), 255],
                            rng.gen_range(2.0..4.0),
                        )
                        .with_rotation(0.0, rng.gen_range(-20.0..20.0))
                        .with_scale(1.0, -1.0);
                        
                        self.particle_system.emit(particle);
                    }
                }
            }
            5 => {
                // Chuva de partículas
                if self.time.fract() < 0.016 {
                    for _ in 0..15 {
                        let particle = Particle::new(
                            rng.gen_range(0.0..800.0),
                            -10.0,
                            rng.gen_range(-10.0..10.0),
                            rng.gen_range(300.0..500.0),
                            rng.gen_range(2.0..4.0),
                            [100, 150, 255, 200],
                            rng.gen_range(2.0..4.0),
                        )
                        .with_acceleration(0.0, 50.0);
                        
                        self.particle_system.emit(particle);
                    }
                }
            }
            _ => {}
        }
    }

    fn update_shaders(&mut self) {
        self.shader_manager.clear_shaders();

        match self.shader_mode {
            0 => {
                // Bloom
                self.shader_manager.add_shader(
                    Shader::new(ShaderType::Bloom)
                        .with_parameter("threshold", 180.0)
                        .with_parameter("bloom_intensity", 1.5)
                );
            }
            1 => {
                // Motion Blur
                self.shader_manager.add_shader(
                    Shader::new(ShaderType::MotionBlur)
                        .with_parameter("direction", self.time)
                        .with_parameter("samples", 5.0)
                );
            }
            2 => {
                // Hue Shift animado
                self.shader_manager.add_shader(
                    Shader::new(ShaderType::HueShift)
                        .with_parameter("shift", (self.time * 50.0) % 360.0)
                );
                self.shader_manager.add_shader(
                    Shader::new(ShaderType::Saturation)
                        .with_parameter("saturation", 1.5)
                );
            }
            3 => {
                // Glitch + Chromatic Aberration
                self.shader_manager.add_shader(
                    Shader::new(ShaderType::Glitch)
                        .with_parameter("glitch_intensity", 0.05)
                );
                self.shader_manager.add_shader(
                    Shader::new(ShaderType::ChromaticAberration)
                        .with_parameter("offset", 3.0)
                );
            }
            _ => {}
        }
    }

    fn hsv_to_rgb(&self, h: f32, s: f32, v: f32) -> [u8; 4] {
        let c = v * s;
        let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs());
        let m = v - c;
        let (r, g, b) = if h < 60.0 {
            (c, x, 0.0)
        } else if h < 120.0 {
            (x, c, 0.0)
        } else if h < 180.0 {
            (0.0, c, x)
        } else if h < 240.0 {
            (0.0, x, c)
        } else if h < 300.0 {
            (x, 0.0, c)
        } else {
            (c, 0.0, x)
        };
        [
            ((r + m) * 255.0) as u8,
            ((g + m) * 255.0) as u8,
            ((b + m) * 255.0) as u8,
            255,
        ]
    }

    fn draw_ui(&self, frame: &mut [u8]) {
        // Desenha barra de informação no topo
        for y in 0..60 {
            for x in 0..800 {
                let idx = ((y * 800 + x) * 4) as usize;
                if idx + 3 < frame.len() {
                    frame[idx] = (frame[idx] as f32 * 0.3) as u8;
                    frame[idx + 1] = (frame[idx + 1] as f32 * 0.3) as u8;
                    frame[idx + 2] = (frame[idx + 2] as f32 * 0.3) as u8;
                }
            }
        }

        // Info text (simplificado - você pode usar um sistema de texto real)
        let effect_name = match self.effect_mode {
            0 => "Explosao com Turbulencia",
            1 => "Fogo com Color Shift",
            2 => "Magia Multicolorida",
            3 => "Fumaca com Aceleracao",
            4 => "Faiscas Rapidas",
            5 => "Chuva de Particulas",
            _ => "Unknown",
        };

        let shader_name = match self.shader_mode {
            0 => "Bloom",
            1 => "Motion Blur",
            2 => "Hue Shift",
            3 => "Glitch",
            _ => "None",
        };

        // Aqui você desenharia o texto real
        // Por enquanto, apenas mostramos no console
        println!(
            "Efeito: {} | Shader: {} | Particulas: {} | [1-6]: Efeitos | [Q/W/E/R]: Shaders | [Space]: Limpar",
            effect_name, shader_name, self.particle_system.count()
        );
    }
}

fn main() {
    let config = EngineConfig::default()
        .with_title("SevenX Engine - Partículas 2D Avançadas")
        .with_size(800, 600);

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