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;
}
}
#[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),
}
}
}
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();
}
}