#![allow(dead_code)]
use std::{
collections::HashSet,
time::{Duration, Instant},
};
use bevy::{
log::LogPlugin,
prelude::*,
render::{RenderPlugin, settings::WgpuSettings},
time::TimeUpdateStrategy,
winit::WinitPlugin,
};
use bevy_spritesheet_animation::prelude::*;
pub struct Context {
pub app: App,
pub sprite_entity: Entity,
}
impl Context {
pub fn new() -> Self {
let mut app = App::new();
app.add_plugins((
DefaultPlugins
.build()
.disable::<WinitPlugin>()
.disable::<LogPlugin>()
.set(RenderPlugin {
render_creation: WgpuSettings {
backends: None,
..default()
}
.into(),
..default()
}),
SpritesheetAnimationPlugin,
))
.insert_resource(TimeUpdateStrategy::ManualInstant(Instant::now()));
app.world_mut()
.get_resource_mut::<Time<Virtual>>()
.unwrap()
.set_max_delta(Duration::from_millis(10000));
app.update();
let mut atlas_layouts = app
.world_mut()
.get_resource_mut::<Assets<TextureAtlasLayout>>()
.unwrap();
let sprite = Spritesheet::new(&Handle::default(), 8, 8)
.with_size_hint(768, 768)
.sprite(&mut atlas_layouts);
let entity = app.world_mut().spawn(sprite).id();
Self {
app,
sprite_entity: entity,
}
}
pub fn create_animation<F>(&mut self, mut f: F) -> Handle<Animation>
where
F: FnMut(AnimationBuilder) -> AnimationBuilder,
{
let builder = AnimationBuilder::new(Spritesheet::new(&Handle::default(), 8, 8));
let animation = f(builder).build();
let mut animations = self
.app
.world_mut()
.get_resource_mut::<Assets<Animation>>()
.unwrap();
animations.add(animation.clone())
}
pub fn attach_animation<F>(&mut self, f: F) -> Handle<Animation>
where
F: FnMut(AnimationBuilder) -> AnimationBuilder,
{
let animation_handle = self.create_animation(f);
self.app
.world_mut()
.entity_mut(self.sprite_entity)
.insert(SpritesheetAnimation::new(animation_handle.clone()));
animation_handle
}
pub fn run(&mut self, ms: u32) {
let mut events_resources = self
.app
.world_mut()
.get_resource_mut::<Messages<AnimationEvent>>()
.unwrap();
events_resources.clear();
let mut time_strategy = self
.app
.world_mut()
.get_resource_mut::<TimeUpdateStrategy>();
if let Some(TimeUpdateStrategy::ManualInstant(last_instant)) = time_strategy.as_deref_mut()
{
*last_instant += Duration::from_millis(ms as u64);
}
self.app.update();
}
pub fn check(
&mut self,
expected_atlas_index: usize,
expected_events: impl IntoIterator<Item = AnimationEvent>,
) {
let entity_ref = self.app.world().entity(self.sprite_entity);
let atlas = entity_ref
.get::<Sprite>()
.and_then(|sprite| sprite.texture_atlas.as_ref())
.or_else(|| {
#[cfg(feature = "3d")]
{
entity_ref
.get::<Sprite3d>()
.and_then(|sprite| sprite.texture_atlas.as_ref())
}
#[cfg(not(feature = "3d"))]
{
None
}
})
.unwrap();
assert_eq!(atlas.index, expected_atlas_index);
let events_resources = self
.app
.world_mut()
.get_resource_mut::<Messages<AnimationEvent>>()
.unwrap();
let mut events: HashSet<AnimationEvent> = HashSet::new();
for event in events_resources.get_cursor().read(&events_resources) {
events.insert(event.clone());
}
assert_eq!(events, HashSet::from_iter(expected_events));
}
pub fn get_sprite<F: FnMut(&mut SpritesheetAnimation)>(&mut self, mut f: F) {
let mut sprite = self
.app
.world_mut()
.get_mut::<SpritesheetAnimation>(self.sprite_entity)
.unwrap();
f(&mut sprite);
}
pub fn marker_hit(
&self,
marker: Marker,
animation: &Handle<Animation>,
animation_repetition: usize,
clip_id: ClipId,
clip_repetition: usize,
) -> AnimationEvent {
AnimationEvent::MarkerHit {
entity: self.sprite_entity,
marker,
clip_id,
clip_repetition,
animation: animation.clone(),
animation_repetition,
}
}
pub fn clip_rep_end(
&self,
animation: &Handle<Animation>,
clip_id: ClipId,
clip_repetition: usize,
) -> AnimationEvent {
AnimationEvent::ClipRepetitionEnd {
entity: self.sprite_entity,
clip_id,
clip_repetition,
animation: animation.clone(),
}
}
pub fn clip_end(&self, animation: &Handle<Animation>, clip_id: ClipId) -> AnimationEvent {
AnimationEvent::ClipEnd {
entity: self.sprite_entity,
clip_id,
animation: animation.clone(),
}
}
pub fn anim_rep_end(
&self,
animation: &Handle<Animation>,
animation_repetition: usize,
) -> AnimationEvent {
AnimationEvent::AnimationRepetitionEnd {
entity: self.sprite_entity,
animation: animation.clone(),
animation_repetition,
}
}
pub fn anim_end(&self, animation: &Handle<Animation>) -> AnimationEvent {
AnimationEvent::AnimationEnd {
entity: self.sprite_entity,
animation: animation.clone(),
}
}
}
impl Default for Context {
fn default() -> Self {
Self::new()
}
}