Compare commits

..

1 Commits

Author SHA1 Message Date
db8cd6220a feat: cache dynamicly rendered map texture 2025-08-13 19:48:50 -05:00
3 changed files with 47 additions and 27 deletions

View File

@@ -9,15 +9,18 @@ use sdl2::{
video::WindowContext,
};
use crate::entity::r#trait::Entity;
use crate::error::{EntityError, GameError, GameResult};
use crate::entity::{
collision::{Collidable, CollisionSystem, EntityId},
ghost::{Ghost, GhostType},
pacman::Pacman,
r#trait::Entity,
};
use crate::map::render::MapRenderer;
use crate::{constants, texture::sprite::SpriteAtlas};
pub mod state;
use state::GameState;
@@ -168,13 +171,36 @@ impl Game {
}
pub fn draw<T: RenderTarget>(&mut self, canvas: &mut Canvas<T>, backbuffer: &mut Texture) -> GameResult<()> {
// Only render the map texture once and cache it
if !self.state.map_rendered {
let mut map_texture = self
.state
.texture_creator
.create_texture_target(None, constants::CANVAS_SIZE.x, constants::CANVAS_SIZE.y)
.map_err(|e| GameError::Sdl(e.to_string()))?;
canvas
.with_texture_canvas(&mut map_texture, |map_canvas| {
let mut map_tiles = Vec::with_capacity(35);
for i in 0..35 {
let tile_name = format!("maze/tiles/{}.png", i);
let tile = SpriteAtlas::get_tile(&self.state.atlas, &tile_name).unwrap();
map_tiles.push(tile);
}
MapRenderer::render_map(map_canvas, &mut self.state.atlas, &mut map_tiles);
})
.map_err(|e| GameError::Sdl(e.to_string()))?;
self.state.map_texture = Some(map_texture);
self.state.map_rendered = true;
}
canvas
.with_texture_canvas(backbuffer, |canvas| {
canvas.set_draw_color(Color::BLACK);
canvas.clear();
self.state
.map
.render(canvas, &mut self.state.atlas, &mut self.state.map_tiles);
if let Some(ref map_texture) = self.state.map_texture {
canvas.copy(map_texture, None, None).unwrap();
}
// Render all items
for item in &self.state.items {

View File

@@ -1,4 +1,8 @@
use sdl2::{image::LoadTexture, render::TextureCreator, video::WindowContext};
use sdl2::{
image::LoadTexture,
render::{Texture, TextureCreator},
video::WindowContext,
};
use smallvec::SmallVec;
use crate::{
@@ -15,7 +19,7 @@ use crate::{
game::EntityId,
map::Map,
texture::{
sprite::{AtlasMapper, AtlasTile, SpriteAtlas},
sprite::{AtlasMapper, SpriteAtlas},
text::TextTexture,
},
};
@@ -31,7 +35,6 @@ include!(concat!(env!("OUT_DIR"), "/atlas_data.rs"));
pub struct GameState {
pub score: u32,
pub map: Map,
pub map_tiles: Vec<AtlasTile>,
pub pacman: Pacman,
pub pacman_id: EntityId,
pub ghosts: SmallVec<[Ghost; 4]>,
@@ -49,6 +52,11 @@ pub struct GameState {
// Audio
pub audio: Audio,
// Map texture pre-rendering
pub(crate) map_texture: Option<Texture<'static>>,
pub(crate) map_rendered: bool,
pub(crate) texture_creator: &'static TextureCreator<WindowContext>,
}
impl GameState {
@@ -60,7 +68,7 @@ impl GameState {
pub fn new(texture_creator: &'static TextureCreator<WindowContext>) -> GameResult<Self> {
let map = Map::new(RAW_BOARD)?;
let pacman_start_node = map.start_positions.pacman;
let start_node = map.start_positions.pacman;
let atlas_bytes = get_asset_bytes(Asset::Atlas)?;
let atlas_texture = texture_creator.load_texture_bytes(&atlas_bytes).map_err(|e| {
@@ -76,17 +84,9 @@ impl GameState {
};
let atlas = SpriteAtlas::new(atlas_texture, atlas_mapper);
let mut map_tiles = Vec::with_capacity(35);
for i in 0..35 {
let tile_name = format!("maze/tiles/{}.png", i);
let tile = SpriteAtlas::get_tile(&atlas, &tile_name)
.ok_or(GameError::Texture(TextureError::AtlasTileNotFound(tile_name)))?;
map_tiles.push(tile);
}
let text_texture = TextTexture::new(1.0);
let audio = Audio::new();
let pacman = Pacman::new(&map.graph, pacman_start_node, &atlas)?;
let pacman = Pacman::new(&map.graph, start_node, &atlas)?;
// Generate items (pellets and energizers)
let items = map.generate_items(&atlas)?;
@@ -127,7 +127,6 @@ impl GameState {
Ok(Self {
map,
atlas,
map_tiles,
pacman,
pacman_id,
ghosts,
@@ -139,6 +138,9 @@ impl GameState {
score: 0,
debug_mode: false,
collision_system,
map_texture: None,
map_rendered: false,
texture_creator,
})
}
}

View File

@@ -6,7 +6,7 @@ use crate::entity::graph::{EdgePermissions, Graph, Node, NodeId};
use crate::entity::item::{Item, ItemType};
use crate::map::parser::MapTileParser;
use crate::map::render::MapRenderer;
use crate::texture::sprite::{AtlasTile, Sprite, SpriteAtlas};
use crate::texture::sprite::{Sprite, SpriteAtlas};
use glam::{IVec2, Vec2};
use sdl2::render::{Canvas, RenderTarget};
use std::collections::{HashMap, VecDeque};
@@ -154,14 +154,6 @@ impl Map {
})
}
/// Renders the map to the given canvas.
///
/// This function draws the static map texture to the screen at the correct
/// position and scale.
pub fn render<T: RenderTarget>(&self, canvas: &mut Canvas<T>, atlas: &mut SpriteAtlas, map_tiles: &mut [AtlasTile]) {
MapRenderer::render_map(canvas, atlas, map_tiles);
}
/// Generates Item entities for pellets and energizers from the parsed map.
pub fn generate_items(&self, atlas: &SpriteAtlas) -> GameResult<Vec<Item>> {
// Pre-load sprites to avoid repeated texture lookups