| Crates.io | bevy_map_animation |
| lib.rs | bevy_map_animation |
| version | 0.3.1 |
| created_at | 2025-12-21 07:20:37.786521+00 |
| updated_at | 2026-01-20 11:16:42.627867+00 |
| description | Animation and sprite types for bevy_map_editor |
| homepage | |
| repository | https://github.com/jbuehler23/bevy_map_editor |
| max_upload_size | |
| id | 1997635 |
| size | 192,738 |
Sprite sheet animations for the bevy_map_editor ecosystem.
Part of bevy_map_editor.
| Type | Description |
|---|---|
SpriteData |
Sprite sheet definition with animations |
AnimationDef |
Single animation (frames, timing, loop mode) |
AnimatedSprite |
Component for playing animations |
AnimationTrigger |
One-shot trigger definition (time + payload) |
AnimationWindow |
Duration-based window definition (start/end + payload) |
LoopMode |
Loop, Once, or PingPong |
WindowTracker |
Component to enable window event tracking |
| Event | Description |
|---|---|
AnimationTriggerEvent |
Fired when a trigger fires (generic) |
AnimationWindowEvent |
Fired for window phase changes (Begin/Tick/End) |
AnimationSoundEvent |
Convenience event for sound payloads |
AnimationParticleEvent |
Convenience event for particle/VFX payloads |
AnimationCustomEvent |
Convenience event for custom payloads |
use bevy_map::animation::{SpriteData, AnimationDef, LoopMode};
let mut sprite = SpriteData::new("sprites/character.png", 32, 32);
sprite.add_animation("idle", AnimationDef {
frames: vec![0, 1, 2, 3],
frame_duration_ms: 200,
loop_mode: LoopMode::Loop,
..Default::default()
});
sprite.add_animation("attack", AnimationDef {
frames: vec![4, 5, 6, 7, 8],
frame_duration_ms: 80,
loop_mode: LoopMode::Once,
..Default::default()
});
use bevy_map::animation::{AnimationDef, AnimationTrigger, AnimationWindow, TriggerPayload};
let mut attack_anim = AnimationDef::new(vec![4, 5, 6, 7, 8], 80, LoopMode::Once);
// One-shot trigger at 240ms - play impact sound
attack_anim.add_trigger(AnimationTrigger::with_payload(
"impact",
240,
TriggerPayload::Sound {
path: "sounds/impact.ogg".into(),
volume: 0.8,
},
));
// Duration-based window from 160-320ms - hitbox active
attack_anim.add_window(AnimationWindow::with_payload(
"hitbox",
160,
320,
TriggerPayload::Custom {
event_name: "attack_hitbox".into(),
params: [("damage".into(), serde_json::json!(25))].into(),
},
));
use bevy::prelude::*;
use bevy_map::animation::{AnimationTriggerEvent, AnimationWindowEvent, WindowPhase};
fn handle_triggers(mut events: MessageReader<AnimationTriggerEvent>) {
for event in events.read() {
info!("Trigger: {} at {}", event.trigger_name, event.animation);
}
}
fn handle_windows(mut events: MessageReader<AnimationWindowEvent>) {
for event in events.read() {
match event.phase {
WindowPhase::Begin => info!("Window {} started", event.window_name),
WindowPhase::Tick => { /* every frame while active */ },
WindowPhase::End => info!("Window {} ended", event.window_name),
}
}
}
Define custom trigger types for type-safe event handling with Bevy Observers:
use bevy::prelude::*;
use bevy_map::animation::{AnimationTriggerType, AnimationEventExt};
use serde_json::Value;
use std::collections::HashMap;
#[derive(Event, Clone)]
pub struct AttackHitbox {
pub damage: i32,
pub knockback: f32,
}
impl AnimationTriggerType for AttackHitbox {
fn trigger_name() -> &'static str {
"attack_hitbox" // matches event_name in TriggerPayload::Custom
}
fn from_params(params: &HashMap<String, Value>) -> Option<Self> {
Some(Self {
damage: params.get("damage")?.as_i64()? as i32,
knockback: params.get("knockback")
.and_then(|v| v.as_f64())
.unwrap_or(5.0) as f32,
})
}
}
// Register the custom trigger type
app.register_animation_trigger::<AttackHitbox>();
// Handle with Bevy Observer
fn setup(mut commands: Commands) {
commands.spawn((
AnimatedSprite::new(/* ... */),
Observer::new(|trigger: Trigger<AttackHitbox>| {
let hitbox = trigger.event();
info!("Attack! Damage: {}", hitbox.damage);
}),
));
}
use bevy::prelude::*;
use bevy_map::prelude::*;
fn play_animation(mut query: Query<&mut AnimatedSprite>) {
for mut animated in query.iter_mut() {
animated.play("idle");
}
}
Add WindowTracker component to entities that need window event tracking:
commands.spawn((
AnimatedSprite::new(sprite_data_handle),
WindowTracker::default(), // Required for window events
// ... other components
));
Use AnimatedSpriteHandle for automatic loading:
use bevy_map::runtime::AnimatedSpriteHandle;
commands.spawn((
AnimatedSpriteHandle::new(
asset_server.load("maps/game.map.json"),
"player_sprite",
"idle",
),
Transform::default(),
));
Add SpriteAnimationPlugin for automatic animation updates:
use bevy_map::prelude::*;
app.add_plugins(SpriteAnimationPlugin);
Note: MapRuntimePlugin includes this automatically.
MIT OR Apache-2.0