bevy_spritesheet 0.6.0

bevy extensions with support for selecting a sprite index depending on an associated state.
Documentation
use better_default::Default;
use bevy::{asset::AssetLoader, platform::collections::HashMap, prelude::*};
use std::time::Duration;

mod parser;

/// Direction the sprite is facing. It used to describe the state.
#[allow(missing_docs)]
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, Hash)]
pub enum Direction {
    Left,
    Right,
    Top,
    Bottom,
}

/// Describes the state of the sprite
#[allow(missing_docs)]
#[derive(Clone, Debug, serde::Deserialize, Eq, PartialEq, Hash)]
pub enum SpriteState {
    /// Indicates the sprite is still.
    Idle { direction: Direction },
    /// Indicates the sprite is walking.
    Walk { direction: Direction },
    /// Indicates the sprite is running.
    Run { direction: Direction },
}

impl SpriteState {
    /// Change direction
    pub fn change_direction(&self, direction: Direction) -> Self {
        match self {
            SpriteState::Idle { .. } => SpriteState::Idle { direction },
            SpriteState::Walk { .. } => SpriteState::Walk { direction },
            SpriteState::Run { .. } => SpriteState::Run { direction },
        }
    }
    /// Change to idle
    pub fn to_idle(&self) -> Self {
        match self {
            SpriteState::Idle { direction }
            | SpriteState::Walk { direction }
            | SpriteState::Run { direction } => SpriteState::Idle {
                direction: direction.to_owned(),
            },
        }
    }
    /// Change to walk
    pub fn to_walk(&self) -> Self {
        match self {
            SpriteState::Idle { direction }
            | SpriteState::Walk { direction }
            | SpriteState::Run { direction } => SpriteState::Walk {
                direction: direction.to_owned(),
            },
        }
    }
    /// Change to run
    pub fn to_run(&self) -> Self {
        match self {
            SpriteState::Idle { direction }
            | SpriteState::Walk { direction }
            | SpriteState::Run { direction } => SpriteState::Run {
                direction: direction.to_owned(),
            },
        }
    }
}

/// A sheet contains information about the mapping between states and the texture index.
#[derive(Debug, Default, Asset, TypePath, serde::Deserialize)]
pub struct Sheet {
    #[default(Duration::from_secs(1))]
    pub(super) animation: Duration,
    default_indices: Vec<usize>,
    mappings: HashMap<SpriteState, Vec<usize>>,
}

impl Sheet {
    pub(crate) fn new(
        animation: Duration,
        default_indices: Vec<usize>,
        mappings: HashMap<SpriteState, Vec<usize>>,
    ) -> Self {
        Sheet {
            animation,
            default_indices,
            mappings,
        }
    }
    pub(crate) fn get(&self, state: &SpriteState) -> &Vec<usize> {
        self.mappings.get(state).unwrap_or(&self.default_indices)
    }
}

#[derive(Debug, Default, TypePath)]
pub(super) struct SheetLoader;

impl AssetLoader for SheetLoader {
    type Asset = Sheet;
    type Settings = ();
    type Error = crate::error::Error;
    async fn load(
        &self,
        reader: &mut dyn bevy::asset::io::Reader,
        _: &Self::Settings,
        _load_context: &mut bevy::asset::LoadContext<'_>,
    ) -> Result<Self::Asset, Self::Error> {
        let mut bytes = Vec::new();
        reader.read_to_end(&mut bytes).await?;
        parser::parse(std::str::from_utf8(&bytes)?)
    }
    fn extensions(&self) -> &[&str] {
        &["sheet"]
    }
}