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
// Sistema avançado de sprites 2D
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BlendMode2D {
    Normal,
    Add,
    Multiply,
    Screen,
    Overlay,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpriteAdvanced {
    pub x: f32,
    pub y: f32,
    pub width: f32,
    pub height: f32,
    pub rotation: f32,
    pub scale_x: f32,
    pub scale_y: f32,
    pub pivot_x: f32,
    pub pivot_y: f32,
    pub color: [u8; 4],
    pub blend_mode: BlendMode2D,
    pub flip_x: bool,
    pub flip_y: bool,
    pub visible: bool,
}

impl SpriteAdvanced {
    pub fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
        Self {
            x,
            y,
            width,
            height,
            rotation: 0.0,
            scale_x: 1.0,
            scale_y: 1.0,
            pivot_x: 0.5,
            pivot_y: 0.5,
            color: [255, 255, 255, 255],
            blend_mode: BlendMode2D::Normal,
            flip_x: false,
            flip_y: false,
            visible: true,
        }
    }

    pub fn with_rotation(mut self, rotation: f32) -> Self {
        self.rotation = rotation;
        self
    }

    pub fn with_scale(mut self, scale_x: f32, scale_y: f32) -> Self {
        self.scale_x = scale_x;
        self.scale_y = scale_y;
        self
    }

    pub fn with_pivot(mut self, pivot_x: f32, pivot_y: f32) -> Self {
        self.pivot_x = pivot_x;
        self.pivot_y = pivot_y;
        self
    }

    pub fn with_color(mut self, color: [u8; 4]) -> Self {
        self.color = color;
        self
    }

    pub fn with_blend_mode(mut self, blend_mode: BlendMode2D) -> Self {
        self.blend_mode = blend_mode;
        self
    }

    pub fn flip_horizontal(mut self) -> Self {
        self.flip_x = true;
        self
    }

    pub fn flip_vertical(mut self) -> Self {
        self.flip_y = true;
        self
    }

    pub fn get_bounds(&self) -> (f32, f32, f32, f32) {
        let w = self.width * self.scale_x;
        let h = self.height * self.scale_y;
        let px = w * self.pivot_x;
        let py = h * self.pivot_y;
        
        (self.x - px, self.y - py, w, h)
    }

    pub fn contains_point(&self, px: f32, py: f32) -> bool {
        let (x, y, w, h) = self.get_bounds();
        px >= x && px <= x + w && py >= y && py <= y + h
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpriteAnimation {
    pub frames: Vec<usize>,
    pub frame_duration: f32,
    pub current_frame: usize,
    pub elapsed: f32,
    pub looping: bool,
    pub playing: bool,
}

impl SpriteAnimation {
    pub fn new(frames: Vec<usize>, frame_duration: f32) -> Self {
        Self {
            frames,
            frame_duration,
            current_frame: 0,
            elapsed: 0.0,
            looping: true,
            playing: true,
        }
    }

    pub fn update(&mut self, dt: f32) {
        if !self.playing || self.frames.is_empty() {
            return;
        }

        self.elapsed += dt;
        if self.elapsed >= self.frame_duration {
            self.elapsed = 0.0;
            self.current_frame += 1;

            if self.current_frame >= self.frames.len() {
                if self.looping {
                    self.current_frame = 0;
                } else {
                    self.current_frame = self.frames.len() - 1;
                    self.playing = false;
                }
            }
        }
    }

    pub fn get_current_frame(&self) -> usize {
        if self.current_frame < self.frames.len() {
            self.frames[self.current_frame]
        } else {
            0
        }
    }

    pub fn play(&mut self) {
        self.playing = true;
    }

    pub fn pause(&mut self) {
        self.playing = false;
    }

    pub fn stop(&mut self) {
        self.playing = false;
        self.current_frame = 0;
        self.elapsed = 0.0;
    }

    pub fn restart(&mut self) {
        self.current_frame = 0;
        self.elapsed = 0.0;
        self.playing = true;
    }
}

// Sistema de efeitos visuais 2D
#[derive(Debug, Clone)]
pub struct VisualEffect {
    pub effect_type: EffectType,
    pub duration: f32,
    pub elapsed: f32,
    pub intensity: f32,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EffectType {
    Shake,
    Flash,
    Fade,
    Pulse,
    Wave,
}

impl VisualEffect {
    pub fn shake(duration: f32, intensity: f32) -> Self {
        Self {
            effect_type: EffectType::Shake,
            duration,
            elapsed: 0.0,
            intensity,
        }
    }

    pub fn flash(duration: f32) -> Self {
        Self {
            effect_type: EffectType::Flash,
            duration,
            elapsed: 0.0,
            intensity: 1.0,
        }
    }

    pub fn fade(duration: f32) -> Self {
        Self {
            effect_type: EffectType::Fade,
            duration,
            elapsed: 0.0,
            intensity: 1.0,
        }
    }

    pub fn update(&mut self, dt: f32) -> bool {
        self.elapsed += dt;
        self.elapsed < self.duration
    }

    pub fn get_value(&self) -> f32 {
        let t = (self.elapsed / self.duration).min(1.0);
        match self.effect_type {
            EffectType::Shake => {
                (1.0 - t) * self.intensity * ((self.elapsed * 20.0).sin())
            }
            EffectType::Flash => 1.0 - t,
            EffectType::Fade => t,
            EffectType::Pulse => ((self.elapsed * 5.0).sin() * 0.5 + 0.5) * (1.0 - t),
            EffectType::Wave => ((self.elapsed * 3.0).sin()) * (1.0 - t),
        }
    }
}

// Gerenciador de efeitos
pub struct EffectManager {
    effects: Vec<VisualEffect>,
}

impl EffectManager {
    pub fn new() -> Self {
        Self {
            effects: Vec::new(),
        }
    }

    pub fn add_effect(&mut self, effect: VisualEffect) {
        self.effects.push(effect);
    }

    pub fn update(&mut self, dt: f32) {
        self.effects.retain_mut(|effect| effect.update(dt));
    }

    pub fn get_shake_offset(&self) -> (f32, f32) {
        let mut x = 0.0;
        let mut y = 0.0;
        for effect in &self.effects {
            if effect.effect_type == EffectType::Shake {
                let val = effect.get_value();
                x += val * ((effect.elapsed * 30.0).cos());
                y += val * ((effect.elapsed * 25.0).sin());
            }
        }
        (x, y)
    }

    pub fn get_flash_intensity(&self) -> f32 {
        self.effects
            .iter()
            .filter(|e| e.effect_type == EffectType::Flash)
            .map(|e| e.get_value())
            .fold(0.0, f32::max)
    }

    pub fn get_fade_alpha(&self) -> f32 {
        self.effects
            .iter()
            .filter(|e| e.effect_type == EffectType::Fade)
            .map(|e| e.get_value())
            .fold(1.0, f32::min)
    }

    pub fn clear(&mut self) {
        self.effects.clear();
    }
}