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
use sevenx_engine::*;
use sevenx_engine::input::InputHandler;
use sevenx_engine::world::World;
use sevenx_engine::networking::ChatChannel;

/// Demo de multiplayer básico (sem networking real).
/// Para networking real, compile com: cargo run --example multiplayer_demo --features multiplayer
struct MultiplayerGame {
    network: NetworkManager,
    local_player_pos: (f32, f32),
}

impl GameState for MultiplayerGame {
    fn new() -> Self {
        // Cria um host
        let mut network = NetworkManager::create_host("player1", "Host");
        
        // Adiciona jogadores simulados
        network.send_message(NetworkMessage::PlayerJoined {
            id: "bot1".to_string(),
            name: "Bot 1".to_string(),
        });
        network.send_message(NetworkMessage::PlayerJoined {
            id: "bot2".to_string(),
            name: "Bot 2".to_string(),
        });

        println!("🎮 Multiplayer Demo");
        println!("WASD - Mover");
        println!("T - Chat");
        println!("R - Toggle Ready");
        println!("1/2 - Mudar time");
        println!();

        Self {
            network,
            local_player_pos: (400.0, 300.0),
        }
    }

    fn update(&mut self, dt: f32, input: &InputHandler, _world: &mut World) {
        // Movimento
        let speed = 200.0;
        let mut moved = false;

        if input.is_key_pressed(KeyCode::KeyW) {
            self.local_player_pos.1 -= speed * dt;
            moved = true;
        }
        if input.is_key_pressed(KeyCode::KeyS) {
            self.local_player_pos.1 += speed * dt;
            moved = true;
        }
        if input.is_key_pressed(KeyCode::KeyA) {
            self.local_player_pos.0 -= speed * dt;
            moved = true;
        }
        if input.is_key_pressed(KeyCode::KeyD) {
            self.local_player_pos.0 += speed * dt;
            moved = true;
        }

        // Atualiza posição na rede
        if moved {
            self.network.update_player_position(
                self.local_player_pos.0,
                self.local_player_pos.1,
                0.0,
            );
        }

        // Chat
        if input.is_key_just_pressed(KeyCode::KeyT) {
            self.network.send_chat("Hello from player!", ChatChannel::Global);
        }

        // Ready
        if input.is_key_just_pressed(KeyCode::KeyR) {
            let current = self.network.get_player(&self.network.player_id)
                .map(|p| p.is_ready)
                .unwrap_or(false);
            self.network.set_ready(!current);
            println!("Ready: {}", !current);
        }

        // Times
        if input.is_key_just_pressed(KeyCode::Digit1) {
            self.network.change_team("Red");
            println!("Time: Red");
        }
        if input.is_key_just_pressed(KeyCode::Digit2) {
            self.network.change_team("Blue");
            println!("Time: Blue");
        }

        // Simula movimento dos bots
        self.simulate_bots();

        // Tick de rede
        self.network.tick(dt);
    }

    fn draw(&mut self, _world: &World, frame_buffer: &mut [u8]) {
        // Limpa tela
        for pixel in frame_buffer.chunks_exact_mut(4) {
            pixel[0] = 20;  // R
            pixel[1] = 20;  // G
            pixel[2] = 30;  // B
            pixel[3] = 255; // A
        }

        // Desenha todos os jogadores
        for player in self.network.get_all_players() {
            let (x, y, _z) = player.position;
            
            // Cor baseada no time
            let color = match &player.team {
                Some(team) if team == "Red" => [255, 50, 50, 255],
                Some(team) if team == "Blue" => [50, 50, 255, 255],
                _ => [100, 255, 100, 255],
            };

            // Desenha jogador
            self.draw_circle(frame_buffer, x as i32, y as i32, 20, color);

            // Indicador de ready
            if player.is_ready {
                self.draw_circle(frame_buffer, x as i32, y as i32 - 30, 5, [255, 255, 0, 255]);
            }
        }

        // HUD
        self.draw_hud(frame_buffer);
    }
}

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

        // Bot 1 - movimento circular
        let time = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_secs_f32();
        
        let x = 400.0 + time.cos() * 200.0;
        let y = 300.0 + time.sin() * 200.0;
        
        self.network.send_message(NetworkMessage::PlayerMove {
            id: "bot1".to_string(),
            x,
            y,
            z: 0.0,
            tick: 0,
        });

        // Bot 2 - movimento aleatório
        if rng.gen_bool(0.1) {
            if let Some(bot) = self.network.connected_players.get("bot2") {
                let x = bot.position.0 + rng.gen_range(-50.0..50.0);
                let y = bot.position.1 + rng.gen_range(-50.0..50.0);
                
                self.network.send_message(NetworkMessage::PlayerMove {
                    id: "bot2".to_string(),
                    x: x.clamp(100.0, 700.0),
                    y: y.clamp(100.0, 500.0),
                    z: 0.0,
                    tick: 0,
                });
            }
        }
    }

    fn draw_circle(&self, frame_buffer: &mut [u8], cx: i32, cy: i32, radius: i32, color: [u8; 4]) {
        for y in (cy - radius).max(0)..(cy + radius).min(600) {
            for x in (cx - radius).max(0)..(cx + radius).min(800) {
                let dx = x - cx;
                let dy = y - cy;
                if dx * dx + dy * dy <= radius * radius {
                    let idx = ((y * 800 + x) * 4) as usize;
                    if idx + 3 < frame_buffer.len() {
                        frame_buffer[idx] = color[0];
                        frame_buffer[idx + 1] = color[1];
                        frame_buffer[idx + 2] = color[2];
                        frame_buffer[idx + 3] = color[3];
                    }
                }
            }
        }
    }

    fn draw_hud(&self, frame_buffer: &mut [u8]) {
        // Fundo do HUD
        for y in 0..60 {
            for x in 0..800 {
                let idx = (y * 800 + x) * 4;
                if idx + 3 < frame_buffer.len() {
                    frame_buffer[idx] = 0;
                    frame_buffer[idx + 1] = 0;
                    frame_buffer[idx + 2] = 0;
                    frame_buffer[idx + 3] = 200;
                }
            }
        }
    }
}

fn main() {
    let config = EngineConfig {
        window_title: "Multiplayer Demo".to_string(),
        window_width: 800,
        window_height: 600,
        clear_color: [20, 20, 30, 255],
        ..Default::default()
    };

    Engine::with_config(config).run::<MultiplayerGame>();
}