feat: square cells (16x16), slope stepping collision
Square cells: - CHAR_W and CHAR_H both 16 (was 8x16, non-square) - Window size updated to 160*16 x 50*16 = 2560x800 - Applies to both ascii and graphics renderers Slope stepping collision: - Before resolving X, check if new position overlaps solid - If overlap, try stepping up 1 cell — if clear, snap up (walk up slope) - If can't step up, resolve X normally (wall block) - aabb_overlaps_solid() helper for fast overlap check - Player can now walk up 1-cell-high steps and slopes 109 tests, 0 failures
This commit is contained in:
+45
-15
@@ -354,9 +354,7 @@ impl Game {
|
|||||||
|
|
||||||
let mut nx = cx;
|
let mut nx = cx;
|
||||||
let mut ny = cy;
|
let mut ny = cy;
|
||||||
// Horizontal: direct velocity, no damping (vector movement)
|
|
||||||
let mut nvx = cvx;
|
let mut nvx = cvx;
|
||||||
// Vertical: gravity + light damping for natural fall
|
|
||||||
let mut nvy = cvy * 0.99;
|
let mut nvy = cvy * 0.99;
|
||||||
nvy += gravity;
|
nvy += gravity;
|
||||||
|
|
||||||
@@ -366,25 +364,28 @@ impl Game {
|
|||||||
nvy = nvy / v_mag * max_vel;
|
nvy = nvy / v_mag * max_vel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move X then resolve X collisions
|
// Step 1: Try horizontal movement with slope stepping
|
||||||
nx += nvx;
|
nx += nvx;
|
||||||
let (resolved_x, hit_wall_x) = self.resolve_aabb_x(idx, nx, ny, half_w, half_h, nvx);
|
if self.aabb_overlaps_solid(nx, ny, half_w, half_h) {
|
||||||
nx = resolved_x;
|
// Try stepping up 1 cell
|
||||||
if hit_wall_x {
|
let step = 1.0;
|
||||||
if nvx > 0.0 { nvx = 0.0; }
|
if !self.aabb_overlaps_solid(nx, ny - step, half_w, half_h) {
|
||||||
else if nvx < 0.0 { nvx = 0.0; }
|
// Can step up — snap to top of the obstacle
|
||||||
|
ny -= step;
|
||||||
|
} else {
|
||||||
|
// Blocked — resolve X
|
||||||
|
let (resolved_x, hit) = self.resolve_aabb_x(idx, nx, ny, half_w, half_h, nvx);
|
||||||
|
nx = resolved_x;
|
||||||
|
if hit { nvx = 0.0; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move Y then resolve Y collisions
|
// Step 2: Vertical movement
|
||||||
ny += nvy;
|
ny += nvy;
|
||||||
let (resolved_y, hit_floor, hit_ceiling) = self.resolve_aabb_y(idx, nx, ny, half_w, half_h, nvy > 0.0);
|
let (resolved_y, hit_floor, hit_ceiling) = self.resolve_aabb_y(idx, nx, ny, half_w, half_h, nvy > 0.0);
|
||||||
ny = resolved_y;
|
ny = resolved_y;
|
||||||
if hit_floor {
|
if hit_floor { nvy = 0.0; }
|
||||||
nvy = 0.0;
|
if hit_ceiling { nvy = 0.0; }
|
||||||
}
|
|
||||||
if hit_ceiling {
|
|
||||||
nvy = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check material contacts
|
// Check material contacts
|
||||||
let (touching_lava, touching_fire, touching_acid, in_liquid) = {
|
let (touching_lava, touching_fire, touching_acid, in_liquid) = {
|
||||||
@@ -445,6 +446,35 @@ impl Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn aabb_overlaps_solid(&self, cx: f32, cy: f32, hw: f32, hh: f32) -> bool {
|
||||||
|
let grid = &self.grid;
|
||||||
|
let left = cx - hw;
|
||||||
|
let right = cx + hw;
|
||||||
|
let top = cy - hh;
|
||||||
|
let bottom = cy + hh;
|
||||||
|
|
||||||
|
let min_x = left.floor() as i32;
|
||||||
|
let max_x = right.ceil() as i32;
|
||||||
|
let min_y = top.floor() as i32;
|
||||||
|
let max_y = bottom.ceil() as i32;
|
||||||
|
|
||||||
|
for y in min_y..=max_y {
|
||||||
|
for x in min_x..=max_x {
|
||||||
|
if !grid.in_bounds(x, y) { continue; }
|
||||||
|
let cell = grid.get(x, y);
|
||||||
|
if !cell.is_solid() { continue; }
|
||||||
|
let cl = x as f32;
|
||||||
|
let cr = (x + 1) as f32;
|
||||||
|
let ct = y as f32;
|
||||||
|
let cb = (y + 1) as f32;
|
||||||
|
if right > cl && left < cr && bottom > ct && top < cb {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_aabb_x(&self, _idx: usize, cx: f32, cy: f32, hw: f32, hh: f32, vx: f32) -> (f32, bool) {
|
fn resolve_aabb_x(&self, _idx: usize, cx: f32, cy: f32, hw: f32, hh: f32, vx: f32) -> (f32, bool) {
|
||||||
let grid = &self.grid;
|
let grid = &self.grid;
|
||||||
let left = cx - hw;
|
let left = cx - hw;
|
||||||
|
|||||||
+2
-2
@@ -216,7 +216,7 @@ fn run_ascii_mode() {
|
|||||||
let window = event_loop.create_window(
|
let window = event_loop.create_window(
|
||||||
Window::default_attributes()
|
Window::default_attributes()
|
||||||
.with_title("Verbatim — ASCII")
|
.with_title("Verbatim — ASCII")
|
||||||
.with_inner_size(winit::dpi::LogicalSize::new(160 * 8, 50 * 16))
|
.with_inner_size(winit::dpi::LogicalSize::new(160 * 16, 50 * 16))
|
||||||
).expect("Failed to create window");
|
).expect("Failed to create window");
|
||||||
let window = Arc::new(window);
|
let window = Arc::new(window);
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ fn run_graphics_mode() {
|
|||||||
let window = event_loop.create_window(
|
let window = event_loop.create_window(
|
||||||
Window::default_attributes()
|
Window::default_attributes()
|
||||||
.with_title("Verbatim — Graphics")
|
.with_title("Verbatim — Graphics")
|
||||||
.with_inner_size(winit::dpi::LogicalSize::new(160 * 8, 50 * 16))
|
.with_inner_size(winit::dpi::LogicalSize::new(160 * 16, 50 * 16))
|
||||||
).expect("Failed to create window");
|
).expect("Failed to create window");
|
||||||
let window = Arc::new(window);
|
let window = Arc::new(window);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use crate::world::cell::MaterialId;
|
|||||||
use crate::world::grid::Grid;
|
use crate::world::grid::Grid;
|
||||||
use crate::world::material::MaterialRegistry;
|
use crate::world::material::MaterialRegistry;
|
||||||
|
|
||||||
const CHAR_W: u32 = 8;
|
const CHAR_W: u32 = 16;
|
||||||
const CHAR_H: u32 = 16;
|
const CHAR_H: u32 = 16;
|
||||||
const MAX_FRAMES: usize = 2;
|
const MAX_FRAMES: usize = 2;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::world::cell::MaterialId;
|
|||||||
use crate::world::grid::Grid;
|
use crate::world::grid::Grid;
|
||||||
use crate::world::material::MaterialRegistry;
|
use crate::world::material::MaterialRegistry;
|
||||||
|
|
||||||
const CHAR_W: u32 = 8;
|
const CHAR_W: u32 = 16;
|
||||||
const CHAR_H: u32 = 16;
|
const CHAR_H: u32 = 16;
|
||||||
const ATLAS_COLS: usize = 16;
|
const ATLAS_COLS: usize = 16;
|
||||||
const ATLAS_ROWS: usize = 16;
|
const ATLAS_ROWS: usize = 16;
|
||||||
|
|||||||
Reference in New Issue
Block a user