mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-09 08:08:13 -06:00
refactor: split up and move texture-related code into src/texture submodule
This commit is contained in:
136
src/animation.rs
136
src/animation.rs
@@ -1,136 +0,0 @@
|
||||
//! This module provides a simple animation and atlas system for textures.
|
||||
use sdl2::{
|
||||
rect::Rect,
|
||||
render::{Canvas, Texture},
|
||||
video::Window,
|
||||
};
|
||||
|
||||
use crate::direction::Direction;
|
||||
|
||||
/// Trait for drawable atlas-based textures
|
||||
pub trait FrameDrawn {
|
||||
fn render(&self, canvas: &mut Canvas<Window>, position: (i32, i32), direction: Direction, frame: Option<u32>);
|
||||
}
|
||||
|
||||
/// A texture atlas abstraction for static (non-animated) rendering.
|
||||
pub struct AtlasTexture<'a> {
|
||||
pub raw_texture: Texture<'a>,
|
||||
pub offset: (i32, i32),
|
||||
pub frame_count: u32,
|
||||
pub frame_width: u32,
|
||||
pub frame_height: u32,
|
||||
}
|
||||
|
||||
impl<'a> AtlasTexture<'a> {
|
||||
pub fn new(texture: Texture<'a>, frame_count: u32, frame_width: u32, frame_height: u32, offset: Option<(i32, i32)>) -> Self {
|
||||
AtlasTexture {
|
||||
raw_texture: texture,
|
||||
frame_count,
|
||||
frame_width,
|
||||
frame_height,
|
||||
offset: offset.unwrap_or((0, 0)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_frame_rect(&self, frame: u32) -> Option<Rect> {
|
||||
if frame >= self.frame_count {
|
||||
return None;
|
||||
}
|
||||
Some(Rect::new(
|
||||
frame as i32 * self.frame_width as i32,
|
||||
0,
|
||||
self.frame_width,
|
||||
self.frame_height,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn set_color_modulation(&mut self, r: u8, g: u8, b: u8) {
|
||||
self.raw_texture.set_color_mod(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FrameDrawn for AtlasTexture<'a> {
|
||||
fn render(&self, canvas: &mut Canvas<Window>, position: (i32, i32), direction: Direction, frame: Option<u32>) {
|
||||
let texture_source_frame_rect = self.get_frame_rect(frame.unwrap_or(0));
|
||||
let canvas_destination_rect = Rect::new(
|
||||
position.0 + self.offset.0,
|
||||
position.1 + self.offset.1,
|
||||
self.frame_width,
|
||||
self.frame_height,
|
||||
);
|
||||
canvas
|
||||
.copy_ex(
|
||||
&self.raw_texture,
|
||||
texture_source_frame_rect,
|
||||
Some(canvas_destination_rect),
|
||||
direction.angle(),
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.expect("Could not render texture on canvas");
|
||||
}
|
||||
}
|
||||
|
||||
/// An animated texture using a texture atlas.
|
||||
pub struct AnimatedAtlasTexture<'a> {
|
||||
pub atlas: AtlasTexture<'a>,
|
||||
pub ticks_per_frame: u32,
|
||||
pub ticker: u32,
|
||||
pub reversed: bool,
|
||||
pub paused: bool,
|
||||
}
|
||||
|
||||
impl<'a> AnimatedAtlasTexture<'a> {
|
||||
pub fn new(
|
||||
texture: Texture<'a>,
|
||||
ticks_per_frame: u32,
|
||||
frame_count: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
offset: Option<(i32, i32)>,
|
||||
) -> Self {
|
||||
AnimatedAtlasTexture {
|
||||
atlas: AtlasTexture::new(texture, frame_count, width, height, offset),
|
||||
ticks_per_frame,
|
||||
ticker: 0,
|
||||
reversed: false,
|
||||
paused: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn current_frame(&self) -> u32 {
|
||||
self.ticker / self.ticks_per_frame
|
||||
}
|
||||
|
||||
/// Advances the animation by one tick, unless paused.
|
||||
pub fn tick(&mut self) {
|
||||
if self.paused {
|
||||
return;
|
||||
}
|
||||
if self.reversed {
|
||||
if self.ticker > 0 {
|
||||
self.ticker -= 1;
|
||||
}
|
||||
if self.ticker == 0 {
|
||||
self.reversed = !self.reversed;
|
||||
}
|
||||
} else {
|
||||
self.ticker += 1;
|
||||
if self.ticker + 1 == self.ticks_per_frame * self.atlas.frame_count {
|
||||
self.reversed = !self.reversed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_color_modulation(&mut self, r: u8, g: u8, b: u8) {
|
||||
self.atlas.set_color_modulation(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FrameDrawn for AnimatedAtlasTexture<'a> {
|
||||
fn render(&self, canvas: &mut Canvas<Window>, position: (i32, i32), direction: Direction, frame: Option<u32>) {
|
||||
let frame = frame.unwrap_or_else(|| self.current_frame());
|
||||
self.atlas.render(canvas, position, direction, Some(frame));
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
//! Edible entity for Pac-Man: pellets, power pellets, and fruits.
|
||||
use crate::animation::{AtlasTexture, FrameDrawn};
|
||||
use crate::constants::{FruitType, MapTile, BOARD_HEIGHT, BOARD_WIDTH};
|
||||
use crate::direction::Direction;
|
||||
use crate::entity::{Entity, Renderable, StaticEntity};
|
||||
use crate::map::Map;
|
||||
use crate::texture::atlas::AtlasTexture;
|
||||
use crate::texture::FrameDrawn;
|
||||
use glam::{IVec2, UVec2};
|
||||
use sdl2::{render::Canvas, video::Window};
|
||||
use std::cell::RefCell;
|
||||
|
||||
@@ -2,13 +2,14 @@ use rand::rngs::SmallRng;
|
||||
use rand::Rng;
|
||||
use rand::SeedableRng;
|
||||
|
||||
use crate::animation::{AnimatedAtlasTexture, FrameDrawn};
|
||||
use crate::constants::{MapTile, BOARD_WIDTH};
|
||||
use crate::direction::Direction;
|
||||
use crate::entity::pacman::Pacman;
|
||||
use crate::entity::{Entity, MovableEntity, Moving, Renderable};
|
||||
use crate::map::Map;
|
||||
use crate::modulation::{SimpleTickModulator, TickModulator};
|
||||
use crate::texture::animated::AnimatedAtlasTexture;
|
||||
use crate::texture::FrameDrawn;
|
||||
use glam::{IVec2, UVec2};
|
||||
use sdl2::pixels::Color;
|
||||
use sdl2::render::Texture;
|
||||
|
||||
@@ -8,11 +8,12 @@ use sdl2::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
animation::{AnimatedAtlasTexture, FrameDrawn},
|
||||
direction::Direction,
|
||||
entity::{Entity, MovableEntity, Moving, Renderable, StaticEntity},
|
||||
map::Map,
|
||||
modulation::{SimpleTickModulator, TickModulator},
|
||||
texture::animated::AnimatedAtlasTexture,
|
||||
texture::FrameDrawn,
|
||||
};
|
||||
|
||||
use glam::{IVec2, UVec2};
|
||||
|
||||
@@ -15,7 +15,6 @@ use sdl2::ttf::Font;
|
||||
use sdl2::video::WindowContext;
|
||||
use sdl2::{pixels::Color, render::Canvas, video::Window};
|
||||
|
||||
use crate::animation::AtlasTexture;
|
||||
use crate::asset::{get_asset_bytes, Asset};
|
||||
use crate::audio::Audio;
|
||||
use crate::constants::RAW_BOARD;
|
||||
@@ -26,6 +25,7 @@ use crate::entity::blinky::Blinky;
|
||||
use crate::entity::pacman::Pacman;
|
||||
use crate::entity::Renderable;
|
||||
use crate::map::Map;
|
||||
use crate::texture::atlas::AtlasTexture;
|
||||
|
||||
/// The main game state.
|
||||
///
|
||||
|
||||
@@ -52,7 +52,6 @@ unsafe fn attach_console() {
|
||||
// Do NOT call AllocConsole here - we don't want a console when launched from Explorer
|
||||
}
|
||||
|
||||
mod animation;
|
||||
mod asset;
|
||||
mod audio;
|
||||
mod constants;
|
||||
@@ -66,6 +65,7 @@ mod game;
|
||||
mod helper;
|
||||
mod map;
|
||||
mod modulation;
|
||||
mod texture;
|
||||
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
fn sleep(value: Duration) {
|
||||
|
||||
72
src/texture/animated.rs
Normal file
72
src/texture/animated.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
//! This module provides a simple animation and atlas system for textures.
|
||||
use sdl2::{
|
||||
render::{Canvas, Texture},
|
||||
video::Window,
|
||||
};
|
||||
|
||||
use crate::direction::Direction;
|
||||
use crate::texture::atlas::AtlasTexture;
|
||||
use crate::texture::FrameDrawn;
|
||||
|
||||
/// An animated texture using a texture atlas.
|
||||
pub struct AnimatedAtlasTexture<'a> {
|
||||
pub atlas: AtlasTexture<'a>,
|
||||
pub ticks_per_frame: u32,
|
||||
pub ticker: u32,
|
||||
pub reversed: bool,
|
||||
pub paused: bool,
|
||||
}
|
||||
|
||||
impl<'a> AnimatedAtlasTexture<'a> {
|
||||
pub fn new(
|
||||
texture: Texture<'a>,
|
||||
ticks_per_frame: u32,
|
||||
frame_count: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
offset: Option<(i32, i32)>,
|
||||
) -> Self {
|
||||
AnimatedAtlasTexture {
|
||||
atlas: AtlasTexture::new(texture, frame_count, width, height, offset),
|
||||
ticks_per_frame,
|
||||
ticker: 0,
|
||||
reversed: false,
|
||||
paused: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn current_frame(&self) -> u32 {
|
||||
self.ticker / self.ticks_per_frame
|
||||
}
|
||||
|
||||
/// Advances the animation by one tick, unless paused.
|
||||
pub fn tick(&mut self) {
|
||||
if self.paused {
|
||||
return;
|
||||
}
|
||||
if self.reversed {
|
||||
if self.ticker > 0 {
|
||||
self.ticker -= 1;
|
||||
}
|
||||
if self.ticker == 0 {
|
||||
self.reversed = !self.reversed;
|
||||
}
|
||||
} else {
|
||||
self.ticker += 1;
|
||||
if self.ticker + 1 == self.ticks_per_frame * self.atlas.frame_count {
|
||||
self.reversed = !self.reversed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_color_modulation(&mut self, r: u8, g: u8, b: u8) {
|
||||
self.atlas.set_color_modulation(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FrameDrawn for AnimatedAtlasTexture<'a> {
|
||||
fn render(&self, canvas: &mut Canvas<Window>, position: (i32, i32), direction: Direction, frame: Option<u32>) {
|
||||
let frame = frame.unwrap_or_else(|| self.current_frame());
|
||||
self.atlas.render(canvas, position, direction, Some(frame));
|
||||
}
|
||||
}
|
||||
67
src/texture/atlas.rs
Normal file
67
src/texture/atlas.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use sdl2::{
|
||||
rect::Rect,
|
||||
render::{Canvas, Texture},
|
||||
video::Window,
|
||||
};
|
||||
|
||||
use crate::{direction::Direction, texture::FrameDrawn};
|
||||
|
||||
/// A texture atlas abstraction for static (non-animated) rendering.
|
||||
pub struct AtlasTexture<'a> {
|
||||
pub raw_texture: Texture<'a>,
|
||||
pub offset: (i32, i32),
|
||||
pub frame_count: u32,
|
||||
pub frame_width: u32,
|
||||
pub frame_height: u32,
|
||||
}
|
||||
|
||||
impl<'a> AtlasTexture<'a> {
|
||||
pub fn new(texture: Texture<'a>, frame_count: u32, frame_width: u32, frame_height: u32, offset: Option<(i32, i32)>) -> Self {
|
||||
AtlasTexture {
|
||||
raw_texture: texture,
|
||||
frame_count,
|
||||
frame_width,
|
||||
frame_height,
|
||||
offset: offset.unwrap_or((0, 0)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_frame_rect(&self, frame: u32) -> Option<Rect> {
|
||||
if frame >= self.frame_count {
|
||||
return None;
|
||||
}
|
||||
Some(Rect::new(
|
||||
frame as i32 * self.frame_width as i32,
|
||||
0,
|
||||
self.frame_width,
|
||||
self.frame_height,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn set_color_modulation(&mut self, r: u8, g: u8, b: u8) {
|
||||
self.raw_texture.set_color_mod(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FrameDrawn for AtlasTexture<'a> {
|
||||
fn render(&self, canvas: &mut Canvas<Window>, position: (i32, i32), direction: Direction, frame: Option<u32>) {
|
||||
let texture_source_frame_rect = self.get_frame_rect(frame.unwrap_or(0));
|
||||
let canvas_destination_rect = Rect::new(
|
||||
position.0 + self.offset.0,
|
||||
position.1 + self.offset.1,
|
||||
self.frame_width,
|
||||
self.frame_height,
|
||||
);
|
||||
canvas
|
||||
.copy_ex(
|
||||
&self.raw_texture,
|
||||
texture_source_frame_rect,
|
||||
Some(canvas_destination_rect),
|
||||
direction.angle(),
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.expect("Could not render texture on canvas");
|
||||
}
|
||||
}
|
||||
11
src/texture/mod.rs
Normal file
11
src/texture/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use sdl2::{render::Canvas, video::Window};
|
||||
|
||||
use crate::direction::Direction;
|
||||
|
||||
/// Trait for drawable atlas-based textures
|
||||
pub trait FrameDrawn {
|
||||
fn render(&self, canvas: &mut Canvas<Window>, position: (i32, i32), direction: Direction, frame: Option<u32>);
|
||||
}
|
||||
|
||||
pub mod animated;
|
||||
pub mod atlas;
|
||||
Reference in New Issue
Block a user