mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-07 09:15:49 -06:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f41c550bb8 | |||
| 829462d3b6 | |||
| 002da46045 | |||
| cfa73c58a8 | |||
| 5728effcc6 | |||
| fa1a0175b0 | |||
| 85edb18380 |
8
.github/workflows/build.yaml
vendored
8
.github/workflows/build.yaml
vendored
@@ -44,18 +44,16 @@ jobs:
|
|||||||
- name: Cache vcpkg
|
- name: Cache vcpkg
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
save-always: true # deprecated
|
|
||||||
path: target/vcpkg
|
path: target/vcpkg
|
||||||
key: vcpkg-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('Cargo.toml', 'Cargo.lock') }}
|
key: A-vcpkg-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('Cargo.toml', 'Cargo.lock') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-vcpkg
|
A-vcpkg-${{ runner.os }}-${{ matrix.target }}-
|
||||||
vcpkg-${{ runner.os }}-${{ matrix.target }}-
|
|
||||||
|
|
||||||
- name: Vcpkg Linux Dependencies
|
- name: Vcpkg Linux Dependencies
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential gettext libltdl-dev zlib1g-dev
|
sudo apt-get install -y libltdl-dev
|
||||||
|
|
||||||
- name: Vcpkg
|
- name: Vcpkg
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -174,7 +174,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pacman"
|
name = "pacman"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"glam",
|
"glam",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pacman"
|
name = "pacman"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -19,6 +19,12 @@ thiserror = "1.0"
|
|||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
glam = "0.30.4"
|
glam = "0.30.4"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
panic = "abort"
|
||||||
|
panic-strategy = "abort"
|
||||||
|
opt-level = "z"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies.winapi]
|
[target.'cfg(target_os = "windows")'.dependencies.winapi]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
features = ["consoleapi", "fileapi", "handleapi", "processenv", "winbase", "wincon", "winnt", "winuser", "windef", "minwindef"]
|
features = ["consoleapi", "fileapi", "handleapi", "processenv", "winbase", "wincon", "winnt", "winuser", "windef", "minwindef"]
|
||||||
|
|||||||
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,7 +1,7 @@
|
|||||||
//! Debug rendering utilities for Pac-Man.
|
//! Debug rendering utilities for Pac-Man.
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{MapTile, BOARD_HEIGHT, BOARD_WIDTH},
|
constants::{MapTile, BOARD_HEIGHT, BOARD_WIDTH},
|
||||||
ghosts::blinky::Blinky,
|
entity::blinky::Blinky,
|
||||||
map::Map,
|
map::Map,
|
||||||
};
|
};
|
||||||
use glam::{IVec2, UVec2};
|
use glam::{IVec2, UVec2};
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ use std::rc::Rc;
|
|||||||
use sdl2::render::{Canvas, Texture};
|
use sdl2::render::{Canvas, Texture};
|
||||||
use sdl2::video::Window;
|
use sdl2::video::Window;
|
||||||
|
|
||||||
use crate::direction::Direction;
|
use crate::entity::direction::Direction;
|
||||||
|
use crate::entity::ghost::{Ghost, GhostMode, GhostType};
|
||||||
|
use crate::entity::pacman::Pacman;
|
||||||
use crate::entity::{Entity, Moving, Renderable, StaticEntity};
|
use crate::entity::{Entity, Moving, Renderable, StaticEntity};
|
||||||
use crate::ghost::{Ghost, GhostMode, GhostType};
|
|
||||||
use crate::map::Map;
|
use crate::map::Map;
|
||||||
use crate::pacman::Pacman;
|
|
||||||
use glam::{IVec2, UVec2};
|
use glam::{IVec2, UVec2};
|
||||||
|
|
||||||
pub struct Blinky<'a> {
|
pub struct Blinky<'a> {
|
||||||
@@ -29,7 +29,7 @@ impl<'a> Blinky<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets Blinky's chase target - directly targets Pac-Man's current position
|
/// Gets Blinky's chase target - directly targets Pac-Man's current position
|
||||||
fn get_chase_target(&self) -> IVec2 {
|
pub fn get_chase_target(&self) -> IVec2 {
|
||||||
let pacman = self.ghost.pacman.borrow();
|
let pacman = self.ghost.pacman.borrow();
|
||||||
let cell = pacman.base().cell_position;
|
let cell = pacman.base().cell_position;
|
||||||
IVec2::new(cell.x as i32, cell.y as i32)
|
IVec2::new(cell.x as i32, cell.y as i32)
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
//! Edible entity for Pac-Man: pellets, power pellets, and fruits.
|
//! 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::constants::{FruitType, MapTile, BOARD_HEIGHT, BOARD_WIDTH};
|
||||||
use crate::direction::Direction;
|
use crate::entity::direction::Direction;
|
||||||
use crate::entity::{Entity, Renderable, StaticEntity};
|
use crate::entity::{Entity, Renderable, StaticEntity};
|
||||||
use crate::map::Map;
|
use crate::map::Map;
|
||||||
|
use crate::texture::atlas::AtlasTexture;
|
||||||
|
use crate::texture::FrameDrawn;
|
||||||
use glam::{IVec2, UVec2};
|
use glam::{IVec2, UVec2};
|
||||||
use sdl2::{render::Canvas, video::Window};
|
use sdl2::{render::Canvas, video::Window};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@@ -2,13 +2,14 @@ use rand::rngs::SmallRng;
|
|||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rand::SeedableRng;
|
use rand::SeedableRng;
|
||||||
|
|
||||||
use crate::animation::{AnimatedAtlasTexture, FrameDrawn};
|
|
||||||
use crate::constants::{MapTile, BOARD_WIDTH};
|
use crate::constants::{MapTile, BOARD_WIDTH};
|
||||||
use crate::direction::Direction;
|
use crate::entity::direction::Direction;
|
||||||
|
use crate::entity::pacman::Pacman;
|
||||||
use crate::entity::{Entity, MovableEntity, Moving, Renderable};
|
use crate::entity::{Entity, MovableEntity, Moving, Renderable};
|
||||||
use crate::map::Map;
|
use crate::map::Map;
|
||||||
use crate::modulation::{SimpleTickModulator, TickModulator};
|
use crate::modulation::{SimpleTickModulator, TickModulator};
|
||||||
use crate::pacman::Pacman;
|
use crate::texture::animated::AnimatedAtlasTexture;
|
||||||
|
use crate::texture::FrameDrawn;
|
||||||
use glam::{IVec2, UVec2};
|
use glam::{IVec2, UVec2};
|
||||||
use sdl2::pixels::Color;
|
use sdl2::pixels::Color;
|
||||||
use sdl2::render::Texture;
|
use sdl2::render::Texture;
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
|
pub mod blinky;
|
||||||
|
pub mod direction;
|
||||||
|
pub mod edible;
|
||||||
|
pub mod ghost;
|
||||||
|
pub mod pacman;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{MapTile, BOARD_OFFSET, BOARD_WIDTH, CELL_SIZE},
|
constants::{MapTile, BOARD_OFFSET, BOARD_WIDTH, CELL_SIZE},
|
||||||
direction::Direction,
|
entity::direction::Direction,
|
||||||
map::Map,
|
map::Map,
|
||||||
modulation::SimpleTickModulator,
|
modulation::SimpleTickModulator,
|
||||||
};
|
};
|
||||||
@@ -8,11 +8,11 @@ use sdl2::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
animation::{AnimatedAtlasTexture, FrameDrawn},
|
entity::{direction::Direction, Entity, MovableEntity, Moving, Renderable, StaticEntity},
|
||||||
direction::Direction,
|
|
||||||
entity::{Entity, MovableEntity, Moving, Renderable, StaticEntity},
|
|
||||||
map::Map,
|
map::Map,
|
||||||
modulation::{SimpleTickModulator, TickModulator},
|
modulation::{SimpleTickModulator, TickModulator},
|
||||||
|
texture::animated::AnimatedAtlasTexture,
|
||||||
|
texture::FrameDrawn,
|
||||||
};
|
};
|
||||||
|
|
||||||
use glam::{IVec2, UVec2};
|
use glam::{IVec2, UVec2};
|
||||||
12
src/game.rs
12
src/game.rs
@@ -15,17 +15,17 @@ use sdl2::ttf::Font;
|
|||||||
use sdl2::video::WindowContext;
|
use sdl2::video::WindowContext;
|
||||||
use sdl2::{pixels::Color, render::Canvas, video::Window};
|
use sdl2::{pixels::Color, render::Canvas, video::Window};
|
||||||
|
|
||||||
use crate::animation::AtlasTexture;
|
|
||||||
use crate::asset::{get_asset_bytes, Asset};
|
use crate::asset::{get_asset_bytes, Asset};
|
||||||
use crate::audio::Audio;
|
use crate::audio::Audio;
|
||||||
use crate::constants::RAW_BOARD;
|
use crate::constants::RAW_BOARD;
|
||||||
use crate::debug::{DebugMode, DebugRenderer};
|
use crate::debug::{DebugMode, DebugRenderer};
|
||||||
use crate::direction::Direction;
|
use crate::entity::blinky::Blinky;
|
||||||
use crate::edible::{reconstruct_edibles, Edible, EdibleKind};
|
use crate::entity::direction::Direction;
|
||||||
|
use crate::entity::edible::{reconstruct_edibles, Edible, EdibleKind};
|
||||||
|
use crate::entity::pacman::Pacman;
|
||||||
use crate::entity::Renderable;
|
use crate::entity::Renderable;
|
||||||
use crate::ghosts::blinky::Blinky;
|
|
||||||
use crate::map::Map;
|
use crate::map::Map;
|
||||||
use crate::pacman::Pacman;
|
use crate::texture::atlas::AtlasTexture;
|
||||||
|
|
||||||
/// The main game state.
|
/// The main game state.
|
||||||
///
|
///
|
||||||
@@ -232,7 +232,7 @@ impl<'a> Game<'a> {
|
|||||||
self.blinky.base.base.cell_position = *pos;
|
self.blinky.base.base.cell_position = *pos;
|
||||||
self.blinky.base.in_tunnel = false;
|
self.blinky.base.in_tunnel = false;
|
||||||
self.blinky.base.direction = Direction::Left;
|
self.blinky.base.direction = Direction::Left;
|
||||||
self.blinky.mode = crate::ghost::GhostMode::Chase;
|
self.blinky.mode = crate::entity::ghost::GhostMode::Chase;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
pub mod blinky;
|
|
||||||
@@ -52,23 +52,18 @@ unsafe fn attach_console() {
|
|||||||
// Do NOT call AllocConsole here - we don't want a console when launched from Explorer
|
// Do NOT call AllocConsole here - we don't want a console when launched from Explorer
|
||||||
}
|
}
|
||||||
|
|
||||||
mod animation;
|
|
||||||
mod asset;
|
mod asset;
|
||||||
mod audio;
|
mod audio;
|
||||||
mod constants;
|
mod constants;
|
||||||
mod debug;
|
mod debug;
|
||||||
mod direction;
|
|
||||||
mod edible;
|
|
||||||
#[cfg(target_os = "emscripten")]
|
#[cfg(target_os = "emscripten")]
|
||||||
mod emscripten;
|
mod emscripten;
|
||||||
mod entity;
|
mod entity;
|
||||||
mod game;
|
mod game;
|
||||||
mod ghost;
|
|
||||||
mod ghosts;
|
|
||||||
mod helper;
|
mod helper;
|
||||||
mod map;
|
mod map;
|
||||||
mod modulation;
|
mod modulation;
|
||||||
mod pacman;
|
mod texture;
|
||||||
|
|
||||||
#[cfg(not(target_os = "emscripten"))]
|
#[cfg(not(target_os = "emscripten"))]
|
||||||
fn sleep(value: Duration) {
|
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::entity::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::{entity::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::entity::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