Compare commits

..

4 Commits

11 changed files with 94 additions and 24 deletions

View File

@@ -40,5 +40,6 @@ samply:
samply record ./target/profile/pacman{{ binary_extension }} samply record ./target/profile/pacman{{ binary_extension }}
# Build the project for Emscripten # Build the project for Emscripten
web: web *args:
bun run web.build.ts; caddy file-server --root dist bun run web.build.ts {{args}};
caddy file-server --root dist

View File

@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::error::{GameError, GameResult}; use crate::error::{GameError, GameResult};
@@ -5,7 +6,10 @@ use crate::error::{GameError, GameResult};
use crate::constants::{CANVAS_SIZE, LOOP_TIME, SCALE}; use crate::constants::{CANVAS_SIZE, LOOP_TIME, SCALE};
use crate::game::Game; use crate::game::Game;
use crate::platform; use crate::platform;
use sdl2::pixels::PixelFormatEnum;
use sdl2::render::RendererInfo;
use sdl2::{AudioSubsystem, Sdl}; use sdl2::{AudioSubsystem, Sdl};
use tracing::debug;
/// Main application wrapper that manages SDL initialization, window lifecycle, and the game loop. /// Main application wrapper that manages SDL initialization, window lifecycle, and the game loop.
/// ///
@@ -50,15 +54,51 @@ impl App {
.build() .build()
.map_err(|e| GameError::Sdl(e.to_string()))?; .map_err(|e| GameError::Sdl(e.to_string()))?;
#[derive(Debug)]
struct DriverDetail {
info: RendererInfo,
index: usize,
}
let drivers: HashMap<&'static str, DriverDetail> = sdl2::render::drivers()
.enumerate()
.map(|(index, d)| (d.name, DriverDetail { info: d, index }))
.collect::<HashMap<_, _>>();
let get_driver =
|name: &'static str| -> Option<u32> { drivers.get(name.to_lowercase().as_str()).map(|d| d.index as u32) };
{
let mut names = drivers.keys().collect::<Vec<_>>();
names.sort_by_key(|k| get_driver(k));
debug!("Drivers: {names:?}")
}
// Count the number of times each pixel format is supported by each driver
let pixel_format_counts: HashMap<PixelFormatEnum, usize> = drivers
.values()
.flat_map(|d| d.info.texture_formats.iter())
.fold(HashMap::new(), |mut counts, format| {
*counts.entry(*format).or_insert(0) += 1;
counts
});
debug!("Pixel format counts: {pixel_format_counts:?}");
let index = get_driver("direct3d");
debug!("Driver index: {index:?}");
let mut canvas = window let mut canvas = window
.into_canvas() .into_canvas()
.accelerated() .accelerated()
// .index(index)
.build() .build()
.map_err(|e| GameError::Sdl(e.to_string()))?; .map_err(|e| GameError::Sdl(e.to_string()))?;
canvas canvas
.set_logical_size(CANVAS_SIZE.x, CANVAS_SIZE.y) .set_logical_size(CANVAS_SIZE.x, CANVAS_SIZE.y)
.map_err(|e| GameError::Sdl(e.to_string()))?; .map_err(|e| GameError::Sdl(e.to_string()))?;
debug!("Renderer: {:?}", canvas.info());
let texture_creator = canvas.texture_creator(); let texture_creator = canvas.texture_creator();

View File

@@ -49,6 +49,13 @@ pub const CANVAS_SIZE: UVec2 = UVec2::new(
(BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE, (BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE,
); );
pub const LARGE_SCALE: f32 = 2.6;
pub const LARGE_CANVAS_SIZE: UVec2 = UVec2::new(
(((BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x) * CELL_SIZE) as f32 * LARGE_SCALE) as u32,
(((BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE) as f32 * LARGE_SCALE) as u32,
);
/// Collider size constants for different entity types /// Collider size constants for different entity types
pub mod collider { pub mod collider {
use super::CELL_SIZE; use super::CELL_SIZE;

View File

@@ -157,9 +157,9 @@ impl Game {
map_texture.set_scale_mode(ScaleMode::Nearest); map_texture.set_scale_mode(ScaleMode::Nearest);
// Create debug texture at output resolution for crisp debug rendering // Create debug texture at output resolution for crisp debug rendering
let output_size = canvas.output_size().unwrap(); let output_size = constants::LARGE_CANVAS_SIZE;
let mut debug_texture = texture_creator let mut debug_texture = texture_creator
.create_texture_target(Some(sdl2::pixels::PixelFormatEnum::ARGB8888), output_size.0, output_size.1) .create_texture_target(Some(sdl2::pixels::PixelFormatEnum::ARGB8888), output_size.x, output_size.y)
.map_err(|e| GameError::Sdl(e.to_string()))?; .map_err(|e| GameError::Sdl(e.to_string()))?;
// Debug texture is copied over the backbuffer, it requires transparency abilities // Debug texture is copied over the backbuffer, it requires transparency abilities

View File

@@ -1,3 +1,5 @@
#![allow(dead_code)]
//! Buffered writer for tracing logs that can store logs before console attachment. //! Buffered writer for tracing logs that can store logs before console attachment.
use parking_lot::Mutex; use parking_lot::Mutex;

View File

@@ -1,3 +1,5 @@
#![allow(dead_code)]
//! Buffered tracing setup for handling logs before console attachment. //! Buffered tracing setup for handling logs before console attachment.
use crate::platform::buffered_writer::BufferedWriter; use crate::platform::buffered_writer::BufferedWriter;

View File

@@ -142,8 +142,6 @@ pub fn ghost_collision_system(
events.write(AudioEvent::PlayEat); events.write(AudioEvent::PlayEat);
} else { } else {
// Pac-Man dies (this would need a death system) // Pac-Man dies (this would need a death system)
// For now, just log it
tracing::warn!("Pac-Man collided with ghost while not frightened!");
} }
} }
} }

View File

@@ -1,13 +1,13 @@
//! Debug rendering system //! Debug rendering system
use std::cmp::Ordering; use std::cmp::Ordering;
use crate::constants::{BOARD_PIXEL_OFFSET, CANVAS_SIZE}; use crate::constants::{self, BOARD_PIXEL_OFFSET};
use crate::map::builder::Map; use crate::map::builder::Map;
use crate::systems::{Collider, CursorPosition, NodeId, Position, SystemTimings}; use crate::systems::{Collider, CursorPosition, NodeId, Position, SystemTimings};
use crate::texture::ttf::{TtfAtlas, TtfRenderer}; use crate::texture::ttf::{TtfAtlas, TtfRenderer};
use bevy_ecs::resource::Resource; use bevy_ecs::resource::Resource;
use bevy_ecs::system::{Query, Res}; use bevy_ecs::system::{Query, Res};
use glam::{IVec2, UVec2, Vec2}; use glam::{IVec2, Vec2};
use sdl2::pixels::Color; use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect}; use sdl2::rect::{Point, Rect};
use sdl2::render::{Canvas, Texture}; use sdl2::render::{Canvas, Texture};
@@ -215,10 +215,6 @@ pub fn debug_render_system(
if !debug_state.enabled { if !debug_state.enabled {
return; return;
} }
let output = UVec2::from(canvas.output_size().unwrap()).as_vec2();
let logical = CANVAS_SIZE.as_vec2();
let scale = (output / logical).min_element();
// Create debug text renderer // Create debug text renderer
let text_renderer = TtfRenderer::new(1.0); let text_renderer = TtfRenderer::new(1.0);
@@ -251,8 +247,8 @@ pub fn debug_render_system(
let pos = position.get_pixel_position(&map.graph).unwrap(); let pos = position.get_pixel_position(&map.graph).unwrap();
// Transform position and size using common methods // Transform position and size using common methods
let pos = (pos * scale).as_ivec2(); let pos = (pos * constants::LARGE_SCALE).as_ivec2();
let size = (collider.size * scale) as u32; let size = (collider.size * constants::LARGE_SCALE) as u32;
Rect::from_center(Point::from((pos.x, pos.y)), size, size) Rect::from_center(Point::from((pos.x, pos.y)), size, size)
}) })
@@ -268,7 +264,7 @@ pub fn debug_render_system(
} }
canvas.set_draw_color(Color { canvas.set_draw_color(Color {
a: f32_to_u8(0.6), a: f32_to_u8(0.65),
..Color::RED ..Color::RED
}); });
canvas.set_blend_mode(sdl2::render::BlendMode::Blend); canvas.set_blend_mode(sdl2::render::BlendMode::Blend);
@@ -282,8 +278,8 @@ pub fn debug_render_system(
.nodes() .nodes()
.enumerate() .enumerate()
.filter_map(|(id, node)| { .filter_map(|(id, node)| {
let pos = transform_position_with_offset(node.position, scale); let pos = transform_position_with_offset(node.position, constants::LARGE_SCALE);
let size = (2.0 * scale) as u32; let size = (2.0 * constants::LARGE_SCALE) as u32;
let rect = Rect::new(pos.x - (size as i32 / 2), pos.y - (size as i32 / 2), size, size); let rect = Rect::new(pos.x - (size as i32 / 2), pos.y - (size as i32 / 2), size, size);
// If the node is the one closest to the cursor, draw it immediately // If the node is the one closest to the cursor, draw it immediately
@@ -313,7 +309,7 @@ pub fn debug_render_system(
// Render node ID if a node is highlighted // Render node ID if a node is highlighted
if let Some(closest_node_id) = closest_node { if let Some(closest_node_id) = closest_node {
let node = map.graph.get_node(closest_node_id as NodeId).unwrap(); let node = map.graph.get_node(closest_node_id as NodeId).unwrap();
let pos = transform_position_with_offset(node.position, scale); let pos = transform_position_with_offset(node.position, constants::LARGE_SCALE);
let node_id_text = closest_node_id.to_string(); let node_id_text = closest_node_id.to_string();
let text_pos = Vec2::new((pos.x + 10) as f32, (pos.y - 5) as f32); let text_pos = Vec2::new((pos.x + 10) as f32, (pos.y - 5) as f32);
@@ -325,7 +321,7 @@ pub fn debug_render_system(
&node_id_text, &node_id_text,
text_pos, text_pos,
Color { Color {
a: f32_to_u8(0.4), a: f32_to_u8(0.9),
..Color::WHITE ..Color::WHITE
}, },
) )

View File

@@ -6,8 +6,13 @@ use bevy_ecs::{
system::{NonSendMut, Res, ResMut}, system::{NonSendMut, Res, ResMut},
}; };
use glam::Vec2; use glam::Vec2;
use sdl2::{event::Event, keyboard::Keycode, EventPump}; use sdl2::{
event::{Event, WindowEvent},
keyboard::Keycode,
EventPump,
};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use tracing::{debug, info};
use crate::systems::components::DeltaTime; use crate::systems::components::DeltaTime;
use crate::{ use crate::{
@@ -293,7 +298,15 @@ pub fn input_system(
simple_key_events.push(SimpleKeyEvent::KeyUp(key)); simple_key_events.push(SimpleKeyEvent::KeyUp(key));
} }
} }
Event::RenderTargetsReset { .. } | Event::Window { .. } => { Event::Window { win_event, .. } => match win_event {
WindowEvent::Resized(w, h) => {
info!("Window resized to {}x{}", w, h);
}
_ => {
debug!("Window event: {:?}", win_event);
}
},
Event::RenderTargetsReset { .. } => {
// No-op // No-op
} }
_ => { _ => {

View File

@@ -50,7 +50,7 @@ fn test_atlas_mapper_multiple_frames() {
assert!(mapper.frames.contains_key("tile1")); assert!(mapper.frames.contains_key("tile1"));
assert!(mapper.frames.contains_key("tile2")); assert!(mapper.frames.contains_key("tile2"));
assert!(!mapper.frames.contains_key("tile3")); assert!(!mapper.frames.contains_key("tile3"));
assert!(mapper.frames.get("nonexistent").is_none()); assert!(!mapper.frames.contains_key("nonexistent"));
} }
#[test] #[test]

View File

@@ -501,7 +501,6 @@ async function activateEmsdk(
return { vars }; return { vars };
} }
async function main() { async function main() {
// Print the OS detected // Print the OS detected
logger.debug( logger.debug(
@@ -515,7 +514,19 @@ async function main() {
.exhaustive() .exhaustive()
); );
const release = process.env.RELEASE !== "0"; // Parse command line args for build mode
const args = process.argv.slice(2);
let release = true; // Default to release mode
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === "-d" || arg === "--debug") {
release = false;
} else if (arg === "-r" || arg === "--release") {
release = true;
}
}
const emsdkDir = resolve("./emsdk"); const emsdkDir = resolve("./emsdk");
// Activate the Emscripten SDK (returns null if already activated) // Activate the Emscripten SDK (returns null if already activated)