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 de Pathfinding A*
use sevenx_engine::*;
use sevenx_engine::world::World;

struct PathfindingDemo {
    pathfinder: Pathfinder,
    start: GridPos,
    goal: GridPos,
    path: Option<Vec<GridPos>>,
    cell_size: i32,
    input_cooldown: f32,
}

impl GameState for PathfindingDemo {
    fn new() -> Self {
        let grid_width = 40;
        let grid_height = 30;
        let mut pathfinder = Pathfinder::new(grid_width, grid_height);

        // Adiciona alguns obstáculos
        for x in 10..30 {
            pathfinder.add_obstacle(x, 15);
        }
        for y in 5..20 {
            pathfinder.add_obstacle(20, y);
        }
        for x in 5..15 {
            pathfinder.add_obstacle(x, 10);
        }

        let start = GridPos::new(5, 5);
        let goal = GridPos::new(35, 25);
        let path = pathfinder.find_path(start, goal);

        Self {
            pathfinder,
            start,
            goal,
            path,
            cell_size: 20,
            input_cooldown: 0.0,
        }
    }

    fn update(&mut self, dt: f32, input: &sevenx_engine::input::InputHandler, _world: &mut World) {
        self.input_cooldown -= dt;
        
        // Cooldown reduzido com Shift (v0.2.7!)
        let cooldown_time = if input.is_shift_pressed() { 0.05 } else { 0.15 };
        
        if self.input_cooldown <= 0.0 {
            let mut moved = false;
            
            // Usa movimento vetorial (v0.2.7!)
            let (move_x, move_y) = input.get_movement_vector();
            
            if move_y < 0.0 && self.goal.y > 0 {
                self.goal.y -= 1;
                moved = true;
            }
            if move_y > 0.0 && self.goal.y < self.pathfinder.grid_height - 1 {
                self.goal.y += 1;
                moved = true;
            }
            if move_x < 0.0 && self.goal.x > 0 {
                self.goal.x -= 1;
                moved = true;
            }
            if move_x > 0.0 && self.goal.x < self.pathfinder.grid_width - 1 {
                self.goal.x += 1;
                moved = true;
            }

            // Space para adicionar obstáculo usando just_pressed (v0.2.7!)
            if input.is_key_just_pressed(KeyCode::Space) {
                let pos = self.goal;
                if self.pathfinder.obstacles.contains(&pos) {
                    self.pathfinder.remove_obstacle(pos.x, pos.y);
                    println!("🟩 Obstáculo removido em ({}, {})", pos.x, pos.y);
                } else {
                    self.pathfinder.add_obstacle(pos.x, pos.y);
                    println!("🟫 Obstáculo adicionado em ({}, {})", pos.x, pos.y);
                }
                moved = true;
            }
            
            if moved {
                self.path = self.pathfinder.find_path(self.start, self.goal);
                if let Some(path) = &self.path {
                    println!("🗺️ Caminho encontrado com {} passos", path.len());
                } else {
                    println!("❌ Nenhum caminho encontrado!");
                }
                self.input_cooldown = cooldown_time;
            }
        }
    }

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

        // Limpa tela
        for pixel in frame.chunks_exact_mut(4) {
            pixel[0] = 40;
            pixel[1] = 40;
            pixel[2] = 40;
            pixel[3] = 255;
        }

        // Desenha grid
        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;
                let py = y * self.cell_size;

                let color = if self.pathfinder.obstacles.contains(&pos) {
                    [100, 50, 50, 255] // Obstáculo
                } else if pos == self.start {
                    [50, 255, 50, 255] // Início
                } else if pos == self.goal {
                    [255, 50, 50, 255] // Objetivo
                } else {
                    [60, 60, 60, 255] // Vazio
                };

                self.draw_rect(frame, width, px, py, self.cell_size - 2, self.cell_size - 2, color);
            }
        }

        // Desenha caminho
        if let Some(path) = &self.path {
            for pos in path {
                let px = pos.x * self.cell_size;
                let py = pos.y * self.cell_size;
                self.draw_rect(frame, width, px, py, self.cell_size - 2, self.cell_size - 2, [100, 150, 255, 255]);
            }
        }
    }
}

impl PathfindingDemo {
    fn draw_rect(&self, frame: &mut [u8], width: u32, x: i32, y: i32, w: i32, h: i32, color: [u8; 4]) {
        for dy in 0..h {
            for dx in 0..w {
                let px = x + dx;
                let py = y + dy;
                if px >= 0 && px < width as i32 && py >= 0 && py < 600 {
                    let idx = ((py * width as i32 + px) * 4) as usize;
                    if idx + 3 < frame.len() {
                        frame[idx] = color[0];
                        frame[idx + 1] = color[1];
                        frame[idx + 2] = color[2];
                        frame[idx + 3] = color[3];
                    }
                }
            }
        }
    }
}

fn main() {
    println!("🎮 SevenX Engine v0.2.7 - Pathfinding Demo");
    println!("🗺️ Sistema de Pathfinding A*");
    println!();
    println!("🎯 Controles (com melhorias v0.2.7!):");
    println!("   WASD/Setas - Mover objetivo");
    println!("   Espaço - Toggle obstáculo");
    println!("   Shift - Mover mais rápido (v0.2.7!)");
    println!();
    println!("🟢 Verde = Início | 🔴 Vermelho = Objetivo");
    println!("🔵 Azul = Caminho | 🟤 Marrom = Obstáculo");
    println!();

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

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