pub struct SpriteAnimation { /* private fields */ }Expand description
Animation state for cycling through sprite sheet frames.
Implementations§
Source§impl SpriteAnimation
impl SpriteAnimation
Sourcepub fn new(total_frames: u32, fps: f32) -> Self
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}Sourcepub fn with_range(start: u32, end: u32, fps: f32) -> Self
pub fn with_range(start: u32, end: u32, fps: f32) -> Self
Create an animation for a range of frames.
Sourcepub fn update(&mut self, dt: f32) -> bool
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 }Sourcepub fn current_frame(&self) -> u32
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 }Sourcepub fn is_playing(&self) -> bool
pub fn is_playing(&self) -> bool
Check if the animation is playing.
Sourcepub fn is_finished(&self) -> bool
pub fn is_finished(&self) -> bool
Check if the animation has finished (only relevant for non-looping).
Trait Implementations§
Source§impl Clone for SpriteAnimation
impl Clone for SpriteAnimation
Source§fn clone(&self) -> SpriteAnimation
fn clone(&self) -> SpriteAnimation
Returns a duplicate of the value. Read more
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreAuto Trait Implementations§
impl Freeze for SpriteAnimation
impl RefUnwindSafe for SpriteAnimation
impl Send for SpriteAnimation
impl Sync for SpriteAnimation
impl Unpin for SpriteAnimation
impl UnwindSafe for SpriteAnimation
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
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>
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)
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)
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
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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