use std::any::Any;
use crate::core::Component;
use crate::math::Vec2;
#[derive(Debug, Clone, PartialEq)]
pub struct Sprite {
pub texture_path: String, pub visible: bool, pub size: Vec2, pub color: Color, pub flip_x: bool, pub flip_y: bool, pub layer: i32, }
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Color {
pub r: f32, pub g: f32, pub b: f32, pub a: f32, }
impl Color {
pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
assert!((0.0..=1.0).contains(&r), "Red component must be in range 0.0-1.0, got: {}", r);
assert!((0.0..=1.0).contains(&g), "Green component must be in range 0.0-1.0, got: {}", g);
assert!((0.0..=1.0).contains(&b), "Blue component must be in range 0.0-1.0, got: {}", b);
assert!((0.0..=1.0).contains(&a), "Alpha component must be in range 0.0-1.0, got: {}", a);
Self { r, g, b, a }
}
pub fn rgb(r: f32, g: f32, b: f32) -> Self {
Self::new(r, g, b, 1.0)
}
pub fn white() -> Self {
Self::new(1.0, 1.0, 1.0, 1.0)
}
pub fn black() -> Self {
Self::new(0.0, 0.0, 0.0, 1.0)
}
pub fn red() -> Self {
Self::new(1.0, 0.0, 0.0, 1.0)
}
pub fn green() -> Self {
Self::new(0.0, 1.0, 0.0, 1.0)
}
pub fn blue() -> Self {
Self::new(0.0, 0.0, 1.0, 1.0)
}
pub fn transparent() -> Self {
Self::new(1.0, 1.0, 1.0, 0.0)
}
pub fn lerp(&self, other: Color, t: f32) -> Self {
assert!((0.0..=1.0).contains(&t), "Interpolation factor must be in range 0.0-1.0, got: {}", t);
Self::new(
self.r + (other.r - self.r) * t,
self.g + (other.g - self.g) * t,
self.b + (other.b - self.b) * t,
self.a + (other.a - self.a) * t,
)
}
pub fn with_alpha(&self, alpha: f32) -> Self {
assert!((0.0..=1.0).contains(&alpha), "Alpha must be in range 0.0-1.0, got: {}", alpha);
Self::new(self.r, self.g, self.b, alpha)
}
}
impl Sprite {
pub fn new(texture_path: &str) -> Self {
Self {
texture_path: texture_path.to_string(),
visible: true,
size: Vec2::new(32.0, 32.0), color: Color::white(),
flip_x: false,
flip_y: false,
layer: 0,
}
}
pub fn default() -> Self {
Self::new("")
}
pub fn with_size(texture_path: &str, width: f32, height: f32) -> Self {
Self {
texture_path: texture_path.to_string(),
visible: true,
size: Vec2::new(width, height),
color: Color::white(),
flip_x: false,
flip_y: false,
layer: 0,
}
}
pub fn set_visible(&mut self, visible: bool) {
self.visible = visible;
}
pub fn toggle_visible(&mut self) {
self.visible = !self.visible;
}
pub fn set_size(&mut self, width: f32, height: f32) {
self.size = Vec2::new(width, height);
}
pub fn set_uniform_size(&mut self, size: f32) {
self.size = Vec2::new(size, size);
}
pub fn set_color(&mut self, color: Color) {
self.color = color;
}
pub fn set_color_rgb(&mut self, r: f32, g: f32, b: f32) {
self.color = Color::rgb(r, g, b);
}
pub fn set_alpha(&mut self, alpha: f32) {
assert!((0.0..=1.0).contains(&alpha), "Alpha must be in range 0.0-1.0, got: {}", alpha);
self.color.a = alpha;
}
pub fn set_flip_x(&mut self, flip: bool) {
self.flip_x = flip;
}
pub fn set_flip_y(&mut self, flip: bool) {
self.flip_y = flip;
}
pub fn set_layer(&mut self, layer: i32) {
self.layer = layer;
}
pub fn set_texture(&mut self, texture_path: &str) {
self.texture_path = texture_path.to_string();
}
pub fn is_visible(&self) -> bool {
self.visible && self.color.a > 0.0
}
pub fn has_texture(&self) -> bool {
!self.texture_path.is_empty()
}
}
impl Component for Sprite {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn clone_box(&self) -> Box<dyn Component> {
Box::new(self.clone())
}
}