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