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
// Plataforma 3D - Exemplo Completo
use sevenx_engine::*;
use sevenx_engine::world::World;

struct Platformer3D {
    renderer3d: Renderer3D,
    
    // Player
    player: Mesh3D,
    player_pos: Vec3,
    player_vel: Vec3,
    on_ground: bool,
    
    // Plataformas
    platforms: Vec<Platform>,
    
    // Câmera
    camera_distance: f32,
    camera_height: f32,
    
    // Partículas
    particles: ParticleSystem3D,
    
    // Game state
    score: i32,
    coins: Vec<Coin>,
}

struct Platform {
    mesh: Mesh3D,
    position: Vec3,
    size: Vec3,
}

struct Coin {
    mesh: Mesh3D,
    position: Vec3,
    rotation: f32,
    collected: bool,
}

impl GameState for Platformer3D {
    fn new() -> Self {
        let mut renderer3d = Renderer3D::new(800, 600);
        renderer3d.wireframe = false;
        renderer3d.backface_culling = true;
        
        // Player (cubo pequeno)
        let mut player = Mesh3D::cube(1.0);
        for vertex in &mut player.vertices {
            vertex.color = [100, 200, 255, 255];  // Azul claro
        }
        
        // Criar plataformas
        let mut platforms = Vec::new();
        
        // Plataforma inicial
        platforms.push(Platform::new(Vec3::new(0.0, -2.0, 0.0), Vec3::new(8.0, 0.5, 8.0), [100, 150, 100, 255]));
        
        // Plataformas do caminho
        platforms.push(Platform::new(Vec3::new(10.0, -1.0, 0.0), Vec3::new(6.0, 0.5, 6.0), [150, 100, 100, 255]));
        platforms.push(Platform::new(Vec3::new(18.0, 1.0, 0.0), Vec3::new(6.0, 0.5, 6.0), [100, 100, 150, 255]));
        platforms.push(Platform::new(Vec3::new(26.0, 3.0, 0.0), Vec3::new(6.0, 0.5, 6.0), [150, 150, 100, 255]));
        
        // Plataformas laterais
        platforms.push(Platform::new(Vec3::new(5.0, 2.0, 8.0), Vec3::new(4.0, 0.5, 4.0), [100, 150, 150, 255]));
        platforms.push(Platform::new(Vec3::new(15.0, 4.0, -8.0), Vec3::new(4.0, 0.5, 4.0), [150, 100, 150, 255]));
        
        // Criar moedas
        let mut coins = Vec::new();
        coins.push(Coin::new(Vec3::new(10.0, 1.0, 0.0)));
        coins.push(Coin::new(Vec3::new(18.0, 3.0, 0.0)));
        coins.push(Coin::new(Vec3::new(26.0, 5.0, 0.0)));
        coins.push(Coin::new(Vec3::new(5.0, 4.0, 8.0)));
        coins.push(Coin::new(Vec3::new(15.0, 6.0, -8.0)));
        
        let particles = ParticleSystem3D::new(300);
        
        Self {
            renderer3d,
            player,
            player_pos: Vec3::new(0.0, 0.0, 0.0),
            player_vel: Vec3::new(0.0, 0.0, 0.0),
            on_ground: false,
            platforms,
            camera_distance: 15.0,
            camera_height: 8.0,
            particles,
            score: 0,
            coins,
        }
    }

    fn update(&mut self, dt: f32, input: &sevenx_engine::input::InputHandler, _world: &mut World) {
        // Movimento usando movimento vetorial (v0.2.7!)
        let (move_x, move_y) = input.get_movement_vector();
        let speed = if input.is_shift_pressed() { 12.0 } else { 8.0 };
        
        self.player_pos.x += move_x * speed * dt;
        self.player_pos.z += move_y * speed * dt;
        
        // Pulo usando just_pressed (v0.2.7!)
        if input.is_key_just_pressed(KeyCode::Space) && self.on_ground {
            self.player_vel.y = 12.0;
            self.on_ground = false;
            
            // Partículas de pulo
            self.particles.sparkles(self.player_pos);
            println!("🦘 Pulo!");
        }
        
        // Zoom da câmera com scroll (v0.2.7!)
        let scroll = input.get_mouse_wheel_delta();
        if scroll != 0.0 {
            self.camera_distance = (self.camera_distance - scroll * 2.0).clamp(5.0, 30.0);
        }
        
        // Gravidade
        self.player_vel.y -= 25.0 * dt;
        self.player_pos.y += self.player_vel.y * dt;
        
        // Colisão com plataformas
        self.on_ground = false;
        for platform in &self.platforms {
            if self.check_collision(&platform) {
                if self.player_vel.y < 0.0 {
                    self.player_pos.y = platform.position.y + platform.size.y / 2.0 + 0.5;
                    self.player_vel.y = 0.0;
                    self.on_ground = true;
                }
            }
        }
        
        // Coleta moedas
        for coin in &mut self.coins {
            if !coin.collected {
                let dist = (self.player_pos.x - coin.position.x).abs() +
                           (self.player_pos.y - coin.position.y).abs() +
                           (self.player_pos.z - coin.position.z).abs();
                
                if dist < 2.0 {
                    coin.collected = true;
                    self.score += 100;
                    self.particles.sparkles(coin.position);
                }
            }
        }
        
        // Atualiza moedas (rotação)
        for coin in &mut self.coins {
            if !coin.collected {
                coin.rotation += 3.0 * dt;
                coin.mesh.rotation.y = coin.rotation;
            }
        }
        
        // Reset se cair
        if self.player_pos.y < -20.0 {
            self.player_pos = Vec3::new(0.0, 0.0, 0.0);
            self.player_vel = Vec3::zero();
        }
        
        // Atualiza câmera (segue o player)
        self.update_camera();
        
        // Atualiza partículas
        self.particles.update(dt);
    }

    fn draw(&mut self, _world: &World, frame: &mut [u8]) {
        // Céu gradiente
        for y in 0..600 {
            let sky_color = 100 + (y as f32 / 600.0 * 100.0) as u8;
            for x in 0..800 {
                let idx = ((y * 800 + x) * 4) as usize;
                if idx + 3 < frame.len() {
                    frame[idx] = sky_color / 3;
                    frame[idx + 1] = sky_color / 2;
                    frame[idx + 2] = sky_color;
                    frame[idx + 3] = 255;
                }
            }
        }
        
        // Renderiza plataformas
        for platform in &self.platforms {
            self.renderer3d.render_mesh(&platform.mesh, frame, 800, 600);
        }
        
        // Renderiza moedas
        for coin in &self.coins {
            if !coin.collected {
                self.renderer3d.render_mesh(&coin.mesh, frame, 800, 600);
            }
        }
        
        // Renderiza player
        self.player.position = self.player_pos;
        self.renderer3d.render_mesh(&self.player, frame, 800, 600);
        
        // Renderiza partículas
        self.renderer3d.render_particles(&self.particles, frame, 800, 600);
        
        // HUD
        self.draw_hud(frame);
    }
}

impl Platformer3D {
    fn update_camera(&mut self) {
        // Câmera segue o player
        self.renderer3d.camera.position = Vec3::new(
            self.player_pos.x - self.camera_distance * 0.7,
            self.player_pos.y + self.camera_height,
            self.player_pos.z + self.camera_distance * 0.7,
        );
        
        self.renderer3d.camera.look_at(self.player_pos);
    }
    
    fn check_collision(&self, platform: &Platform) -> bool {
        let px = self.player_pos.x;
        let py = self.player_pos.y;
        let pz = self.player_pos.z;
        
        let min_x = platform.position.x - platform.size.x / 2.0;
        let max_x = platform.position.x + platform.size.x / 2.0;
        let min_z = platform.position.z - platform.size.z / 2.0;
        let max_z = platform.position.z + platform.size.z / 2.0;
        let top_y = platform.position.y + platform.size.y / 2.0;
        
        px > min_x && px < max_x &&
        pz > min_z && pz < max_z &&
        py > top_y - 1.0 && py < top_y + 1.0
    }
    
    fn draw_hud(&self, frame: &mut [u8]) {
        // Barra de HUD
        for y in 0..50 {
            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;
                }
            }
        }
        
        // Score
        self.draw_text(frame, 20, 15, &format!("SCORE: {}", self.score));
        
        // Moedas restantes
        let coins_left = self.coins.iter().filter(|c| !c.collected).count();
        self.draw_text(frame, 200, 15, &format!("COINS: {}", coins_left));
        
        // Controles
        self.draw_text(frame, 400, 15, "WASD: Move | SPACE: Jump");
    }
    
    fn draw_text(&self, frame: &mut [u8], x: usize, y: usize, text: &str) {
        for (i, _c) in text.chars().enumerate() {
            let px = x + i * 8;
            if px < 800 && y < 600 {
                for dy in 0..8 {
                    for dx in 0..6 {
                        let idx = (((y + dy) * 800 + (px + dx)) * 4) as usize;
                        if idx + 3 < frame.len() {
                            frame[idx] = 255;
                            frame[idx + 1] = 255;
                            frame[idx + 2] = 255;
                        }
                    }
                }
            }
        }
    }
}

impl Platform {
    fn new(position: Vec3, size: Vec3, color: [u8; 4]) -> Self {
        let mut mesh = Mesh3D::cube(1.0);
        mesh.position = position;
        mesh.scale = size;
        
        for vertex in &mut mesh.vertices {
            vertex.color = color;
        }
        
        Self { mesh, position, size }
    }
}

impl Coin {
    fn new(position: Vec3) -> Self {
        let mut mesh = Mesh3D::cube(0.5);
        mesh.position = position;
        mesh.scale = Vec3::new(0.5, 0.5, 0.1);
        
        for vertex in &mut mesh.vertices {
            vertex.color = [255, 215, 0, 255];  // Dourado
        }
        
        Self {
            mesh,
            position,
            rotation: 0.0,
            collected: false,
        }
    }
}

fn main() {
    println!("🎮 SevenX Engine v0.2.7 - Plataforma 3D");
    println!("🎲 Jogo de Plataforma 3D Completo");
    println!();
    println!("🎯 Controles:");
    println!("   WASD - Mover");
    println!("   Shift - Correr (v0.2.7!)");
    println!("   Espaço - Pular");
    println!("   Scroll - Zoom da câmera (v0.2.7!)");
    println!();
    println!("🎯 Objetivo: Colete todas as moedas douradas!");
    println!();

    let config = EngineConfig::default()
        .with_title("SevenX Engine v0.2.7 - Plataforma 3D")
        .with_size(800, 600);

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