Skip to main content

SpriteAnimation

Struct SpriteAnimation 

Source
pub struct SpriteAnimation { /* private fields */ }
Expand description

Animation state for cycling through sprite sheet frames.

Implementations§

Source§

impl SpriteAnimation

Source

pub fn new(total_frames: u32, fps: f32) -> Self

Create a new animation for all frames.

Examples found in repository?
examples/sprite_sheet.rs (line 197)
152fn main() {
153    logging::init();
154
155    run_app(|ctx| {
156        let graphics_ctx = GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
157        let mut windows = HashMap::new();
158
159        let scale = Window::platform_dpi() as f32;
160        let window = ctx
161            .create_window(WindowDescriptor {
162                title: "Sprite Sheet Animation Example".to_string(),
163                size: Some(WinitPhysicalSize::new(400.0 * scale, 400.0 * scale)),
164                ..Default::default()
165            })
166            .expect("Failed to create window");
167
168        let renderable_window = RenderableWindow::new_with_descriptor(
169            window,
170            graphics_ctx.clone(),
171            WindowContextDescriptor {
172                format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
173                ..Default::default()
174            },
175        ).expect("Failed to create renderable window");
176
177        let window_id = renderable_window.id();
178        windows.insert(window_id, renderable_window);
179
180        // Generate sprite sheet
181        let (sprite_data, tex_width, tex_height) = generate_sprite_sheet_data();
182        let sprite_sheet = SpriteSheet::from_data(
183            &graphics_ctx,
184            &sprite_data,
185            tex_width,
186            tex_height,
187            SpriteSheetDescriptor {
188                sprite_width: 64,
189                sprite_height: 64,
190                columns: 4,
191                rows: 1,
192                ..Default::default()
193            },
194        );
195
196        // Create animation (4 frames at 8 fps)
197        let animation = SpriteAnimation::new(4, 8.0);
198
199        // Create shader module
200        let shader = graphics_ctx.device().create_shader_module(wgpu::ShaderModuleDescriptor {
201            label: Some("Sprite Shader"),
202            source: wgpu::ShaderSource::Wgsl(SHADER.into()),
203        });
204
205        // Create bind group layout
206        let bind_group_layout = graphics_ctx.device().create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
207            label: Some("Sprite Bind Group Layout"),
208            entries: &[
209                wgpu::BindGroupLayoutEntry {
210                    binding: 0,
211                    visibility: wgpu::ShaderStages::VERTEX,
212                    ty: wgpu::BindingType::Buffer {
213                        ty: wgpu::BufferBindingType::Uniform,
214                        has_dynamic_offset: false,
215                        min_binding_size: None,
216                    },
217                    count: None,
218                },
219                wgpu::BindGroupLayoutEntry {
220                    binding: 1,
221                    visibility: wgpu::ShaderStages::FRAGMENT,
222                    ty: wgpu::BindingType::Texture {
223                        sample_type: wgpu::TextureSampleType::Float { filterable: true },
224                        view_dimension: wgpu::TextureViewDimension::D2,
225                        multisampled: false,
226                    },
227                    count: None,
228                },
229                wgpu::BindGroupLayoutEntry {
230                    binding: 2,
231                    visibility: wgpu::ShaderStages::FRAGMENT,
232                    ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
233                    count: None,
234                },
235            ],
236        });
237
238        // Create pipeline layout
239        let pipeline_layout = graphics_ctx.device().create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
240            label: Some("Sprite Pipeline Layout"),
241            bind_group_layouts: &[&bind_group_layout],
242            push_constant_ranges: &[],
243        });
244
245        // Create render pipeline
246        let pipeline = graphics_ctx.device().create_render_pipeline(&wgpu::RenderPipelineDescriptor {
247            label: Some("Sprite Pipeline"),
248            layout: Some(&pipeline_layout),
249            vertex: wgpu::VertexState {
250                module: &shader,
251                entry_point: Some("vs_main"),
252                buffers: &[wgpu::VertexBufferLayout {
253                    array_stride: std::mem::size_of::<Vertex>() as u64,
254                    step_mode: wgpu::VertexStepMode::Vertex,
255                    attributes: &[
256                        wgpu::VertexAttribute {
257                            offset: 0,
258                            shader_location: 0,
259                            format: wgpu::VertexFormat::Float32x2,
260                        },
261                        wgpu::VertexAttribute {
262                            offset: 8,
263                            shader_location: 1,
264                            format: wgpu::VertexFormat::Float32x2,
265                        },
266                    ],
267                }],
268                compilation_options: wgpu::PipelineCompilationOptions::default(),
269            },
270            fragment: Some(wgpu::FragmentState {
271                module: &shader,
272                entry_point: Some("fs_main"),
273                targets: &[Some(wgpu::ColorTargetState {
274                    format: wgpu::TextureFormat::Bgra8UnormSrgb,
275                    blend: Some(wgpu::BlendState::ALPHA_BLENDING),
276                    write_mask: wgpu::ColorWrites::ALL,
277                })],
278                compilation_options: wgpu::PipelineCompilationOptions::default(),
279            }),
280            primitive: wgpu::PrimitiveState {
281                topology: wgpu::PrimitiveTopology::TriangleList,
282                ..Default::default()
283            },
284            depth_stencil: None,
285            multisample: wgpu::MultisampleState::default(),
286            multiview: None,
287            cache: None,
288        });
289
290        // Create uniform buffer
291        let uniforms = Uniforms {
292            mvp: [
293                [1.0, 0.0, 0.0, 0.0],
294                [0.0, 1.0, 0.0, 0.0],
295                [0.0, 0.0, 1.0, 0.0],
296                [0.0, 0.0, 0.0, 1.0],
297            ],
298        };
299        let uniform_buffer = graphics_ctx.device().create_buffer_init(&wgpu::util::BufferInitDescriptor {
300            label: Some("Uniform Buffer"),
301            contents: bytemuck::cast_slice(&[uniforms]),
302            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
303        });
304
305        // Create sampler
306        let sampler = graphics_ctx.device().create_sampler(&wgpu::SamplerDescriptor {
307            label: Some("Sprite Sampler"),
308            mag_filter: wgpu::FilterMode::Linear,
309            min_filter: wgpu::FilterMode::Linear,
310            ..Default::default()
311        });
312
313        // Create bind group
314        let bind_group = graphics_ctx.device().create_bind_group(&wgpu::BindGroupDescriptor {
315            label: Some("Sprite Bind Group"),
316            layout: &bind_group_layout,
317            entries: &[
318                wgpu::BindGroupEntry {
319                    binding: 0,
320                    resource: uniform_buffer.as_entire_binding(),
321                },
322                wgpu::BindGroupEntry {
323                    binding: 1,
324                    resource: wgpu::BindingResource::TextureView(sprite_sheet.view()),
325                },
326                wgpu::BindGroupEntry {
327                    binding: 2,
328                    resource: wgpu::BindingResource::Sampler(&sampler),
329                },
330            ],
331        });
332
333        // Initial vertex buffer (will be updated each frame with new UVs)
334        let vertices = create_quad_vertices(0.0, 0.0, 1.0, 1.0);
335        let vertex_buffer = graphics_ctx.device().create_buffer_init(&wgpu::util::BufferInitDescriptor {
336            label: Some("Vertex Buffer"),
337            contents: bytemuck::cast_slice(&vertices),
338            usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
339        });
340
341        Box::new(App {
342            _context: graphics_ctx,
343            windows,
344            pipeline,
345            bind_group,
346            vertex_buffer,
347            uniform_buffer,
348            sprite_sheet,
349            animation,
350            last_update: Instant::now(),
351        })
352    });
353}
Source

pub fn with_range(start: u32, end: u32, fps: f32) -> Self

Create an animation for a range of frames.

Source

pub fn looping(self, looping: bool) -> Self

Set whether the animation loops.

Source

pub fn update(&mut self, dt: f32) -> bool

Update the animation with elapsed time.

Returns true if the frame changed.

Examples found in repository?
examples/sprite_sheet.rs (line 373)
367    fn update(&mut self, _ctx: &mut astrelis_winit::app::AppCtx, _time: &astrelis_winit::FrameTime) {
368        let now = Instant::now();
369        let dt = now.duration_since(self.last_update).as_secs_f32();
370        self.last_update = now;
371
372        // Update animation
373        if self.animation.update(dt) {
374            // Frame changed - update vertex buffer with new UVs
375            let frame = self.animation.current_frame();
376            let uv = self.sprite_sheet.sprite_uv(frame);
377            let vertices = create_quad_vertices(uv.u_min, uv.v_min, uv.u_max, uv.v_max);
378            
379            // Get context from first window
380            if let Some(window) = self.windows.values().next() {
381                window.context().graphics_context().queue().write_buffer(
382                    &self.vertex_buffer,
383                    0,
384                    bytemuck::cast_slice(&vertices),
385                );
386            }
387        }
388    }
Source

pub fn current_frame(&self) -> u32

Get the current frame index.

Examples found in repository?
examples/sprite_sheet.rs (line 375)
367    fn update(&mut self, _ctx: &mut astrelis_winit::app::AppCtx, _time: &astrelis_winit::FrameTime) {
368        let now = Instant::now();
369        let dt = now.duration_since(self.last_update).as_secs_f32();
370        self.last_update = now;
371
372        // Update animation
373        if self.animation.update(dt) {
374            // Frame changed - update vertex buffer with new UVs
375            let frame = self.animation.current_frame();
376            let uv = self.sprite_sheet.sprite_uv(frame);
377            let vertices = create_quad_vertices(uv.u_min, uv.v_min, uv.u_max, uv.v_max);
378            
379            // Get context from first window
380            if let Some(window) = self.windows.values().next() {
381                window.context().graphics_context().queue().write_buffer(
382                    &self.vertex_buffer,
383                    0,
384                    bytemuck::cast_slice(&vertices),
385                );
386            }
387        }
388    }
Source

pub fn set_frame(&mut self, frame: u32)

Jump to a specific frame.

Source

pub fn play(&mut self)

Play the animation.

Source

pub fn pause(&mut self)

Pause the animation.

Source

pub fn stop(&mut self)

Stop and reset the animation.

Source

pub fn is_playing(&self) -> bool

Check if the animation is playing.

Source

pub fn is_finished(&self) -> bool

Check if the animation has finished (only relevant for non-looping).

Source

pub fn reverse(&mut self)

Reverse the animation direction.

Source

pub fn set_fps(&mut self, fps: f32)

Set the playback speed (fps).

Source

pub fn progress(&self) -> f32

Get normalized progress (0.0 to 1.0).

Trait Implementations§

Source§

impl Clone for SpriteAnimation

Source§

fn clone(&self) -> SpriteAnimation

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SpriteAnimation

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,