refactor: code cleanup — dead code, warnings, duplication
Dead code removed (21 methods, 4 fields, 3 constants): - Cell: MaterialId::ALL, MaterialId::from_u8 (unsafe transmute) - Grid: get_mut, clear, fill_rect, swap, dump_region, next buffer field - Entity: move_center, EntityManager::iter_mut - Player: move_dir field, entity_mut - VerletSolver: step, SubBody::add_vel, SubBody::apply_force - CellularAutomaton: tick_count - InputHandler: release_all, poll, Action::None - WindowInput: clear - GameSession: perform_action_and_step, is_recording, grid_mut - ReplayPlayer: from_recording - Material: empty() - VulkanRenderer: tick_count field - MaterialBrush: name() Warnings fixed: - Remove unused MaterialRegistry imports from renderers - Remove unused reg variables in terminal/vulkan/graphics - Remove unused water_surface in game.rs - Remove unused p/y_death in tests - Remove unused qf_slice in graphics.rs Duplication eliminated: - main.rs: run_ascii_mode + run_graphics_mode → generic run_gpu_mode<R: GpuRenderer> ~140 lines of duplicated event loop code removed - GpuRenderer trait unifies VulkanRenderer and GraphicsRenderer API Unsafe code fixed: - rand_u8: static mut + unsafe → AtomicU8 + fetch_add (thread-safe) Module cleanup: - world/mod.rs: removed all unused re-exports - physics/mod.rs: removed all unused re-exports - entity/mod.rs: removed unused Entity/EntityId re-exports Result: ~6500 → ~5964 lines, 0 non-deprecation warnings, 109 tests pass
This commit is contained in:
@@ -66,10 +66,6 @@ impl ReplayPlayer {
|
|||||||
Ok(Self { recording })
|
Ok(Self { recording })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_recording(recording: ReplayRecording) -> Self {
|
|
||||||
Self { recording }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn play(&self) -> GameSession {
|
pub fn play(&self) -> GameSession {
|
||||||
let mut session = GameSession::new_seeded(self.recording.seed);
|
let mut session = GameSession::new_seeded(self.recording.seed);
|
||||||
session.init();
|
session.init();
|
||||||
|
|||||||
@@ -62,11 +62,6 @@ impl GameSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_action_and_step(&mut self, action: &AiAction, steps: u32) {
|
|
||||||
self.perform_action(action);
|
|
||||||
self.step(steps);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_state(&self) -> GameState {
|
pub fn get_state(&self) -> GameState {
|
||||||
build_game_state(&self.game, self.view_width, self.view_height)
|
build_game_state(&self.game, self.view_width, self.view_height)
|
||||||
}
|
}
|
||||||
@@ -146,10 +141,6 @@ impl GameSession {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_recording(&self) -> bool {
|
|
||||||
self.recorder.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save_replay(&self, path: &str) -> std::io::Result<()> {
|
pub fn save_replay(&self, path: &str) -> std::io::Result<()> {
|
||||||
if let Some(ref r) = self.recorder {
|
if let Some(ref r) = self.recorder {
|
||||||
r.save(path)?;
|
r.save(path)?;
|
||||||
@@ -169,10 +160,6 @@ impl GameSession {
|
|||||||
&self.game.grid
|
&self.game.grid
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grid_mut(&mut self) -> &mut Grid {
|
|
||||||
&mut self.game.grid
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tick(&self) -> u64 {
|
pub fn tick(&self) -> u64 {
|
||||||
self.game.tick
|
self.game.tick
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -76,7 +76,7 @@ impl CellInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entity_info(e: &crate::entity::Entity) -> EntityInfo {
|
pub fn entity_info(e: &crate::entity::entity::Entity) -> EntityInfo {
|
||||||
let (px, py) = e.center();
|
let (px, py) = e.center();
|
||||||
let bodies: Vec<SubBodyInfo> = e.bodies.iter().enumerate().map(|(i, b)| {
|
let bodies: Vec<SubBodyInfo> = e.bodies.iter().enumerate().map(|(i, b)| {
|
||||||
let reg = MaterialRegistry::instance();
|
let reg = MaterialRegistry::instance();
|
||||||
|
|||||||
@@ -174,13 +174,6 @@ impl Entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_center(&mut self, dx: f32, dy: f32) {
|
|
||||||
if self.rigid {
|
|
||||||
self.cvx += dx;
|
|
||||||
self.cvy += dy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_horizontal_vel(&mut self, vx: f32) {
|
pub fn set_horizontal_vel(&mut self, vx: f32) {
|
||||||
if self.rigid {
|
if self.rigid {
|
||||||
self.cvx = vx;
|
self.cvx = vx;
|
||||||
@@ -261,8 +254,4 @@ impl EntityManager {
|
|||||||
pub fn all_mut(&mut self) -> &mut [Entity] {
|
pub fn all_mut(&mut self) -> &mut [Entity] {
|
||||||
&mut self.entities
|
&mut self.entities
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Entity> {
|
|
||||||
self.entities.iter_mut()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
pub mod entity;
|
pub mod entity;
|
||||||
pub mod player;
|
pub mod player;
|
||||||
|
|
||||||
pub use entity::{Entity, EntityId, EntityManager, EntityKind};
|
pub use entity::{EntityManager, EntityKind};
|
||||||
pub use player::Player;
|
pub use player::Player;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ pub struct Player {
|
|||||||
pub entity_id: EntityId,
|
pub entity_id: EntityId,
|
||||||
pub move_speed: f32,
|
pub move_speed: f32,
|
||||||
pub jump_force: f32,
|
pub jump_force: f32,
|
||||||
pub move_dir: i32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Player {
|
impl Player {
|
||||||
@@ -14,7 +13,6 @@ impl Player {
|
|||||||
entity_id: id,
|
entity_id: id,
|
||||||
move_speed: 0.5,
|
move_speed: 0.5,
|
||||||
jump_force: 1.5,
|
jump_force: 1.5,
|
||||||
move_dir: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,21 +23,18 @@ impl Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_left(&mut self, manager: &mut EntityManager) {
|
pub fn move_left(&mut self, manager: &mut EntityManager) {
|
||||||
self.move_dir = -1;
|
|
||||||
if let Some(e) = manager.get_mut(self.entity_id) {
|
if let Some(e) = manager.get_mut(self.entity_id) {
|
||||||
e.set_horizontal_vel(-self.move_speed);
|
e.set_horizontal_vel(-self.move_speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_right(&mut self, manager: &mut EntityManager) {
|
pub fn move_right(&mut self, manager: &mut EntityManager) {
|
||||||
self.move_dir = 1;
|
|
||||||
if let Some(e) = manager.get_mut(self.entity_id) {
|
if let Some(e) = manager.get_mut(self.entity_id) {
|
||||||
e.set_horizontal_vel(self.move_speed);
|
e.set_horizontal_vel(self.move_speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_horizontal(&mut self, manager: &mut EntityManager) {
|
pub fn stop_horizontal(&mut self, manager: &mut EntityManager) {
|
||||||
self.move_dir = 0;
|
|
||||||
if let Some(e) = manager.get_mut(self.entity_id) {
|
if let Some(e) = manager.get_mut(self.entity_id) {
|
||||||
e.set_horizontal_vel(0.0);
|
e.set_horizontal_vel(0.0);
|
||||||
}
|
}
|
||||||
@@ -57,10 +52,6 @@ impl Player {
|
|||||||
manager.get(self.entity_id)
|
manager.get(self.entity_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn entity_mut<'a>(&self, manager: &'a mut EntityManager) -> Option<&'a mut Entity> {
|
|
||||||
manager.get_mut(self.entity_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn center(&self, manager: &EntityManager) -> (f32, f32) {
|
pub fn center(&self, manager: &EntityManager) -> (f32, f32) {
|
||||||
manager.get(self.entity_id).map(|e| e.center()).unwrap_or((0.0, 0.0))
|
manager.get(self.entity_id).map(|e| e.center()).unwrap_or((0.0, 0.0))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,8 +70,6 @@ impl Game {
|
|||||||
|
|
||||||
// Water pool (left side)
|
// Water pool (left side)
|
||||||
let water_x = 40;
|
let water_x = 40;
|
||||||
let water_surface = (h as i32 - 3) - ((water_x as f32 * 0.1).sin() * 5.0) as i32;
|
|
||||||
let _water_surface = water_surface.max(10).min(h as i32 - 3);
|
|
||||||
for x in water_x - 12..=water_x + 12 {
|
for x in water_x - 12..=water_x + 12 {
|
||||||
let s = (h as i32 - 3) - ((x as f32 * 0.1).sin() * 5.0) as i32;
|
let s = (h as i32 - 3) - ((x as f32 * 0.1).sin() * 5.0) as i32;
|
||||||
let s = s.max(10).min(h as i32 - 3);
|
let s = s.max(10).min(h as i32 - 3);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ pub enum Action {
|
|||||||
MoveCameraRight,
|
MoveCameraRight,
|
||||||
Paint(MaterialBrush),
|
Paint(MaterialBrush),
|
||||||
Quit,
|
Quit,
|
||||||
None,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
@@ -221,16 +220,6 @@ impl InputHandler {
|
|||||||
pub fn jump_requested(&self) -> bool {
|
pub fn jump_requested(&self) -> bool {
|
||||||
self.jump_pressed
|
self.jump_pressed
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release_all(&mut self) {
|
|
||||||
self.held.clear();
|
|
||||||
self.jump_pressed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll(&mut self) -> Action {
|
|
||||||
let actions = self.update();
|
|
||||||
actions.into_iter().next().unwrap_or(Action::None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaterialBrush {
|
impl MaterialBrush {
|
||||||
@@ -251,19 +240,4 @@ impl MaterialBrush {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
MaterialBrush::Sand => "Sand",
|
|
||||||
MaterialBrush::Water => "Water",
|
|
||||||
MaterialBrush::Stone => "Stone",
|
|
||||||
MaterialBrush::Lava => "Lava",
|
|
||||||
MaterialBrush::Wood => "Wood",
|
|
||||||
MaterialBrush::Acid => "Acid",
|
|
||||||
MaterialBrush::Grass => "Grass",
|
|
||||||
MaterialBrush::Dirt => "Dirt",
|
|
||||||
MaterialBrush::Fire => "Fire",
|
|
||||||
MaterialBrush::Flesh => "Flesh",
|
|
||||||
MaterialBrush::Erase => "Erase",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+172
-289
@@ -5,6 +5,11 @@ use verbatim::render::window_input::WindowInput;
|
|||||||
use verbatim::world::cell::MaterialId;
|
use verbatim::world::cell::MaterialId;
|
||||||
use verbatim::ai;
|
use verbatim::ai;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use winit::event::{Event, WindowEvent};
|
||||||
|
use winit::event_loop::{EventLoop, ControlFlow};
|
||||||
|
use winit::window::Window;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(name = "verbatim", about = "ASCII physics RPG - Noita meets Caves of Qud")]
|
#[command(name = "verbatim", about = "ASCII physics RPG - Noita meets Caves of Qud")]
|
||||||
@@ -25,6 +30,35 @@ struct Cli {
|
|||||||
replay_file: Option<String>,
|
replay_file: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait GpuRenderer {
|
||||||
|
fn new(window: Arc<Window>) -> Result<Self, String> where Self: Sized;
|
||||||
|
fn render(&mut self, grid: &verbatim::world::grid::Grid, entities: &verbatim::entity::EntityManager, cam_x: i32, cam_y: i32);
|
||||||
|
fn grid_w(&self) -> usize;
|
||||||
|
fn grid_h(&self) -> usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpuRenderer for verbatim::render::vulkan::VulkanRenderer {
|
||||||
|
fn new(window: Arc<Window>) -> Result<Self, String> {
|
||||||
|
verbatim::render::vulkan::VulkanRenderer::new(window)
|
||||||
|
}
|
||||||
|
fn render(&mut self, grid: &verbatim::world::grid::Grid, entities: &verbatim::entity::EntityManager, cam_x: i32, cam_y: i32) {
|
||||||
|
verbatim::render::vulkan::VulkanRenderer::render(self, grid, entities, cam_x, cam_y)
|
||||||
|
}
|
||||||
|
fn grid_w(&self) -> usize { verbatim::render::vulkan::VulkanRenderer::grid_w(self) }
|
||||||
|
fn grid_h(&self) -> usize { verbatim::render::vulkan::VulkanRenderer::grid_h(self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpuRenderer for verbatim::render::graphics::GraphicsRenderer {
|
||||||
|
fn new(window: Arc<Window>) -> Result<Self, String> {
|
||||||
|
verbatim::render::graphics::GraphicsRenderer::new(window)
|
||||||
|
}
|
||||||
|
fn render(&mut self, grid: &verbatim::world::grid::Grid, entities: &verbatim::entity::EntityManager, cam_x: i32, cam_y: i32) {
|
||||||
|
verbatim::render::graphics::GraphicsRenderer::render(self, grid, entities, cam_x, cam_y)
|
||||||
|
}
|
||||||
|
fn grid_w(&self) -> usize { verbatim::render::graphics::GraphicsRenderer::grid_w(self) }
|
||||||
|
fn grid_h(&self) -> usize { verbatim::render::graphics::GraphicsRenderer::grid_h(self) }
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
@@ -46,10 +80,10 @@ fn main() {
|
|||||||
game.run(&mut renderer);
|
game.run(&mut renderer);
|
||||||
}
|
}
|
||||||
"ascii" => {
|
"ascii" => {
|
||||||
run_ascii_mode();
|
run_gpu_mode::<verbatim::render::vulkan::VulkanRenderer>("Verbatim — ASCII");
|
||||||
}
|
}
|
||||||
"graphics" => {
|
"graphics" => {
|
||||||
run_graphics_mode();
|
run_gpu_mode::<verbatim::render::graphics::GraphicsRenderer>("Verbatim — Graphics");
|
||||||
}
|
}
|
||||||
"pipe" => {
|
"pipe" => {
|
||||||
ai::run_pipe_protocol();
|
ai::run_pipe_protocol();
|
||||||
@@ -75,6 +109,142 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_gpu_mode<R: GpuRenderer>(title: &str) {
|
||||||
|
let event_loop = EventLoop::new().expect("Failed to create event loop");
|
||||||
|
let window = event_loop.create_window(
|
||||||
|
Window::default_attributes()
|
||||||
|
.with_title(title)
|
||||||
|
.with_inner_size(winit::dpi::LogicalSize::new(160 * 16, 50 * 16))
|
||||||
|
).expect("Failed to create window");
|
||||||
|
let window = Arc::new(window);
|
||||||
|
|
||||||
|
let mut renderer = match R::new(Arc::clone(&window)) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Vulkan init failed: {e}");
|
||||||
|
eprintln!("Falling back to terminal mode...");
|
||||||
|
let mut renderer = TerminalRenderer::new();
|
||||||
|
let mut game = Game::new();
|
||||||
|
game.run(&mut renderer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut game = Game::new();
|
||||||
|
game.init_world();
|
||||||
|
|
||||||
|
let mut input = WindowInput::new();
|
||||||
|
|
||||||
|
let fixed_dt = Duration::from_millis(16);
|
||||||
|
let mut last_time = Instant::now();
|
||||||
|
let mut accumulator = Duration::ZERO;
|
||||||
|
let mut running = true;
|
||||||
|
|
||||||
|
event_loop.run(|event, ctrl| {
|
||||||
|
ctrl.set_control_flow(ControlFlow::Poll);
|
||||||
|
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent { event, .. } => {
|
||||||
|
match event {
|
||||||
|
WindowEvent::CloseRequested => {
|
||||||
|
running = false;
|
||||||
|
ctrl.exit();
|
||||||
|
}
|
||||||
|
WindowEvent::KeyboardInput { event: key_event, .. } => {
|
||||||
|
input.on_key_event(key_event.physical_key, key_event.state);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::AboutToWait => {
|
||||||
|
if !running {
|
||||||
|
ctrl.exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let vw = renderer.grid_w();
|
||||||
|
let vh = renderer.grid_h();
|
||||||
|
|
||||||
|
let now = Instant::now();
|
||||||
|
let frame_time = now.duration_since(last_time);
|
||||||
|
last_time = now;
|
||||||
|
accumulator += frame_time;
|
||||||
|
|
||||||
|
let mut steps = 0;
|
||||||
|
while accumulator >= fixed_dt && steps < 5 {
|
||||||
|
game.fixed_update();
|
||||||
|
accumulator -= fixed_dt;
|
||||||
|
steps += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.update();
|
||||||
|
|
||||||
|
if input.quit {
|
||||||
|
running = false;
|
||||||
|
ctrl.exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.jump {
|
||||||
|
let on_ground = game.check_on_ground();
|
||||||
|
game.player.jump(&mut game.entities, on_ground);
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.left {
|
||||||
|
game.player.move_left(&mut game.entities);
|
||||||
|
} else if input.right {
|
||||||
|
game.player.move_right(&mut game.entities);
|
||||||
|
} else {
|
||||||
|
game.player.stop_horizontal(&mut game.entities);
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.cam_left { game.cam_x -= 3; }
|
||||||
|
if input.cam_right { game.cam_x += 3; }
|
||||||
|
if input.cam_up { game.cam_y -= 3; }
|
||||||
|
if input.cam_down { game.cam_y += 3; }
|
||||||
|
|
||||||
|
if let Some(brush_id) = input.paint {
|
||||||
|
let mat = match brush_id {
|
||||||
|
1 => MaterialId::Sand,
|
||||||
|
2 => MaterialId::Water,
|
||||||
|
3 => MaterialId::Stone,
|
||||||
|
4 => MaterialId::Lava,
|
||||||
|
5 => MaterialId::Wood,
|
||||||
|
6 => MaterialId::Acid,
|
||||||
|
7 => MaterialId::Grass,
|
||||||
|
8 => MaterialId::Dirt,
|
||||||
|
9 => MaterialId::Fire,
|
||||||
|
0 => MaterialId::Flesh,
|
||||||
|
99 => MaterialId::Empty,
|
||||||
|
_ => MaterialId::Empty,
|
||||||
|
};
|
||||||
|
let cx = game.cam_x + (vw as i32 / 2);
|
||||||
|
let cy = game.cam_y + (vh as i32 / 2);
|
||||||
|
let r = 2;
|
||||||
|
for dy in -r..=r {
|
||||||
|
for dx in -r..=r {
|
||||||
|
if dx * dx + dy * dy <= r * r + 1 {
|
||||||
|
if mat == MaterialId::Empty {
|
||||||
|
game.grid.set(cx + dx, cy + dy, verbatim::world::cell::Cell::empty());
|
||||||
|
} else {
|
||||||
|
game.grid.set_material(cx + dx, cy + dy, mat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (px, py) = game.player.center(&game.entities);
|
||||||
|
game.cam_x = px as i32 - (vw as i32 / 2);
|
||||||
|
game.cam_y = py as i32 - (vh as i32 / 2);
|
||||||
|
|
||||||
|
renderer.render(&game.grid, &game.entities, game.cam_x, game.cam_y);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}).expect("event loop error");
|
||||||
|
}
|
||||||
|
|
||||||
fn run_test_mode(cli: &Cli) {
|
fn run_test_mode(cli: &Cli) {
|
||||||
if let Some(path) = &cli.scenario {
|
if let Some(path) = &cli.scenario {
|
||||||
match ai::load_scenario(path) {
|
match ai::load_scenario(path) {
|
||||||
@@ -202,290 +372,3 @@ fn player_info(game: &Game) -> String {
|
|||||||
"None".to_string()
|
"None".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn run_ascii_mode() {
|
|
||||||
use verbatim::render::vulkan::VulkanRenderer;
|
|
||||||
use winit::event::{Event, WindowEvent};
|
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
|
||||||
use winit::window::Window;
|
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
let event_loop = EventLoop::new().expect("Failed to create event loop");
|
|
||||||
let window = event_loop.create_window(
|
|
||||||
Window::default_attributes()
|
|
||||||
.with_title("Verbatim — ASCII")
|
|
||||||
.with_inner_size(winit::dpi::LogicalSize::new(160 * 16, 50 * 16))
|
|
||||||
).expect("Failed to create window");
|
|
||||||
let window = Arc::new(window);
|
|
||||||
|
|
||||||
let mut renderer = match VulkanRenderer::new(Arc::clone(&window)) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Vulkan init failed: {e}");
|
|
||||||
eprintln!("Falling back to terminal mode...");
|
|
||||||
let mut renderer = TerminalRenderer::new();
|
|
||||||
let mut game = Game::new();
|
|
||||||
game.run(&mut renderer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut game = Game::new();
|
|
||||||
game.init_world();
|
|
||||||
|
|
||||||
let mut input = WindowInput::new();
|
|
||||||
|
|
||||||
let fixed_dt = Duration::from_millis(16);
|
|
||||||
let mut last_time = Instant::now();
|
|
||||||
let mut accumulator = Duration::ZERO;
|
|
||||||
let mut running = true;
|
|
||||||
|
|
||||||
event_loop.run(|event, ctrl| {
|
|
||||||
ctrl.set_control_flow(ControlFlow::Poll);
|
|
||||||
|
|
||||||
match event {
|
|
||||||
Event::WindowEvent { event, .. } => {
|
|
||||||
match event {
|
|
||||||
WindowEvent::CloseRequested => {
|
|
||||||
running = false;
|
|
||||||
ctrl.exit();
|
|
||||||
}
|
|
||||||
WindowEvent::KeyboardInput { event: key_event, .. } => {
|
|
||||||
input.on_key_event(key_event.physical_key, key_event.state);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::AboutToWait => {
|
|
||||||
if !running {
|
|
||||||
ctrl.exit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let vw = renderer.grid_w();
|
|
||||||
let vh = renderer.grid_h();
|
|
||||||
|
|
||||||
let now = Instant::now();
|
|
||||||
let frame_time = now.duration_since(last_time);
|
|
||||||
last_time = now;
|
|
||||||
accumulator += frame_time;
|
|
||||||
|
|
||||||
let mut steps = 0;
|
|
||||||
while accumulator >= fixed_dt && steps < 5 {
|
|
||||||
game.fixed_update();
|
|
||||||
accumulator -= fixed_dt;
|
|
||||||
steps += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.update();
|
|
||||||
|
|
||||||
if input.quit {
|
|
||||||
running = false;
|
|
||||||
ctrl.exit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.jump {
|
|
||||||
let on_ground = game.check_on_ground();
|
|
||||||
game.player.jump(&mut game.entities, on_ground);
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.left {
|
|
||||||
game.player.move_left(&mut game.entities);
|
|
||||||
} else if input.right {
|
|
||||||
game.player.move_right(&mut game.entities);
|
|
||||||
} else {
|
|
||||||
game.player.stop_horizontal(&mut game.entities);
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.cam_left { game.cam_x -= 3; }
|
|
||||||
if input.cam_right { game.cam_x += 3; }
|
|
||||||
if input.cam_up { game.cam_y -= 3; }
|
|
||||||
if input.cam_down { game.cam_y += 3; }
|
|
||||||
|
|
||||||
if let Some(brush_id) = input.paint {
|
|
||||||
let mat = match brush_id {
|
|
||||||
1 => MaterialId::Sand,
|
|
||||||
2 => MaterialId::Water,
|
|
||||||
3 => MaterialId::Stone,
|
|
||||||
4 => MaterialId::Lava,
|
|
||||||
5 => MaterialId::Wood,
|
|
||||||
6 => MaterialId::Acid,
|
|
||||||
7 => MaterialId::Grass,
|
|
||||||
8 => MaterialId::Dirt,
|
|
||||||
9 => MaterialId::Fire,
|
|
||||||
0 => MaterialId::Flesh,
|
|
||||||
99 => MaterialId::Empty,
|
|
||||||
_ => MaterialId::Empty,
|
|
||||||
};
|
|
||||||
let cx = game.cam_x + (vw as i32 / 2);
|
|
||||||
let cy = game.cam_y + (vh as i32 / 2);
|
|
||||||
let r = 2;
|
|
||||||
for dy in -r..=r {
|
|
||||||
for dx in -r..=r {
|
|
||||||
if dx * dx + dy * dy <= r * r + 1 {
|
|
||||||
if mat == MaterialId::Empty {
|
|
||||||
game.grid.set(cx + dx, cy + dy, verbatim::world::cell::Cell::empty());
|
|
||||||
} else {
|
|
||||||
game.grid.set_material(cx + dx, cy + dy, mat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (px, py) = game.player.center(&game.entities);
|
|
||||||
game.cam_x = px as i32 - (vw as i32 / 2);
|
|
||||||
game.cam_y = py as i32 - (vh as i32 / 2);
|
|
||||||
|
|
||||||
renderer.render(&game.grid, &game.entities, game.cam_x, game.cam_y);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}).expect("event loop error");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_graphics_mode() {
|
|
||||||
use verbatim::render::graphics::GraphicsRenderer;
|
|
||||||
use winit::event::{Event, WindowEvent};
|
|
||||||
use winit::event_loop::{EventLoop, ControlFlow};
|
|
||||||
use winit::window::Window;
|
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
let event_loop = EventLoop::new().expect("Failed to create event loop");
|
|
||||||
let window = event_loop.create_window(
|
|
||||||
Window::default_attributes()
|
|
||||||
.with_title("Verbatim — Graphics")
|
|
||||||
.with_inner_size(winit::dpi::LogicalSize::new(160 * 16, 50 * 16))
|
|
||||||
).expect("Failed to create window");
|
|
||||||
let window = Arc::new(window);
|
|
||||||
|
|
||||||
let mut renderer = match GraphicsRenderer::new(Arc::clone(&window)) {
|
|
||||||
Ok(r) => r,
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Graphics (Vulkan) init failed: {e}");
|
|
||||||
eprintln!("Falling back to terminal mode...");
|
|
||||||
let mut renderer = TerminalRenderer::new();
|
|
||||||
let mut game = Game::new();
|
|
||||||
game.run(&mut renderer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut game = Game::new();
|
|
||||||
game.init_world();
|
|
||||||
|
|
||||||
let mut input = WindowInput::new();
|
|
||||||
|
|
||||||
let fixed_dt = Duration::from_millis(16);
|
|
||||||
let mut last_time = Instant::now();
|
|
||||||
let mut accumulator = Duration::ZERO;
|
|
||||||
let mut running = true;
|
|
||||||
|
|
||||||
event_loop.run(|event, ctrl| {
|
|
||||||
ctrl.set_control_flow(ControlFlow::Poll);
|
|
||||||
|
|
||||||
match event {
|
|
||||||
Event::WindowEvent { event, .. } => {
|
|
||||||
match event {
|
|
||||||
WindowEvent::CloseRequested => {
|
|
||||||
running = false;
|
|
||||||
ctrl.exit();
|
|
||||||
}
|
|
||||||
WindowEvent::KeyboardInput { event: key_event, .. } => {
|
|
||||||
input.on_key_event(key_event.physical_key, key_event.state);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Event::AboutToWait => {
|
|
||||||
if !running {
|
|
||||||
ctrl.exit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let vw = renderer.grid_w();
|
|
||||||
let vh = renderer.grid_h();
|
|
||||||
|
|
||||||
let now = Instant::now();
|
|
||||||
let frame_time = now.duration_since(last_time);
|
|
||||||
last_time = now;
|
|
||||||
accumulator += frame_time;
|
|
||||||
|
|
||||||
let mut steps = 0;
|
|
||||||
while accumulator >= fixed_dt && steps < 5 {
|
|
||||||
game.fixed_update();
|
|
||||||
accumulator -= fixed_dt;
|
|
||||||
steps += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.update();
|
|
||||||
|
|
||||||
if input.quit {
|
|
||||||
running = false;
|
|
||||||
ctrl.exit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.jump {
|
|
||||||
let on_ground = game.check_on_ground();
|
|
||||||
game.player.jump(&mut game.entities, on_ground);
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.left {
|
|
||||||
game.player.move_left(&mut game.entities);
|
|
||||||
} else if input.right {
|
|
||||||
game.player.move_right(&mut game.entities);
|
|
||||||
} else {
|
|
||||||
game.player.stop_horizontal(&mut game.entities);
|
|
||||||
}
|
|
||||||
|
|
||||||
if input.cam_left { game.cam_x -= 3; }
|
|
||||||
if input.cam_right { game.cam_x += 3; }
|
|
||||||
if input.cam_up { game.cam_y -= 3; }
|
|
||||||
if input.cam_down { game.cam_y += 3; }
|
|
||||||
|
|
||||||
if let Some(brush_id) = input.paint {
|
|
||||||
let mat = match brush_id {
|
|
||||||
1 => MaterialId::Sand,
|
|
||||||
2 => MaterialId::Water,
|
|
||||||
3 => MaterialId::Stone,
|
|
||||||
4 => MaterialId::Lava,
|
|
||||||
5 => MaterialId::Wood,
|
|
||||||
6 => MaterialId::Acid,
|
|
||||||
7 => MaterialId::Grass,
|
|
||||||
8 => MaterialId::Dirt,
|
|
||||||
9 => MaterialId::Fire,
|
|
||||||
0 => MaterialId::Flesh,
|
|
||||||
99 => MaterialId::Empty,
|
|
||||||
_ => MaterialId::Empty,
|
|
||||||
};
|
|
||||||
let cx = game.cam_x + (vw as i32 / 2);
|
|
||||||
let cy = game.cam_y + (vh as i32 / 2);
|
|
||||||
let r = 2;
|
|
||||||
for dy in -r..=r {
|
|
||||||
for dx in -r..=r {
|
|
||||||
if dx * dx + dy * dy <= r * r + 1 {
|
|
||||||
if mat == MaterialId::Empty {
|
|
||||||
game.grid.set(cx + dx, cy + dy, verbatim::world::cell::Cell::empty());
|
|
||||||
} else {
|
|
||||||
game.grid.set_material(cx + dx, cy + dy, mat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (px, py) = game.player.center(&game.entities);
|
|
||||||
game.cam_x = px as i32 - (vw as i32 / 2);
|
|
||||||
game.cam_y = py as i32 - (vh as i32 / 2);
|
|
||||||
|
|
||||||
renderer.render(&game.grid, &game.entities, game.cam_x, game.cam_y);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}).expect("event loop error");
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,2 @@
|
|||||||
pub mod verlet;
|
pub mod verlet;
|
||||||
pub mod collision;
|
pub mod collision;
|
||||||
|
|
||||||
pub use verlet::{SubBody, Constraint, VerletSolver};
|
|
||||||
pub use collision::resolve_grid_collision;
|
|
||||||
|
|||||||
@@ -49,18 +49,6 @@ impl SubBody {
|
|||||||
self.old_x = self.x - vx;
|
self.old_x = self.x - vx;
|
||||||
self.old_y = self.y - vy;
|
self.old_y = self.y - vy;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn add_vel(&mut self, vx: f32, vy: f32) {
|
|
||||||
self.old_x -= vx;
|
|
||||||
self.old_y -= vy;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn apply_force(&mut self, fx: f32, fy: f32) {
|
|
||||||
self.ax += fx;
|
|
||||||
self.ay += fy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@@ -159,14 +147,4 @@ impl VerletSolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(
|
|
||||||
&self,
|
|
||||||
bodies: &mut [SubBody],
|
|
||||||
constraints: &[Constraint],
|
|
||||||
iterations: u32,
|
|
||||||
) {
|
|
||||||
self.integrate(bodies);
|
|
||||||
self.solve_constraints(bodies, constraints, iterations);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use std::sync::Arc;
|
|||||||
use crate::entity::{EntityManager, EntityKind};
|
use crate::entity::{EntityManager, EntityKind};
|
||||||
use crate::world::cell::MaterialId;
|
use crate::world::cell::MaterialId;
|
||||||
use crate::world::grid::Grid;
|
use crate::world::grid::Grid;
|
||||||
use crate::world::material::MaterialRegistry;
|
|
||||||
|
|
||||||
const CHAR_W: u32 = 16;
|
const CHAR_W: u32 = 16;
|
||||||
const CHAR_H: u32 = 16;
|
const CHAR_H: u32 = 16;
|
||||||
@@ -306,7 +305,6 @@ impl GraphicsRenderer {
|
|||||||
|
|
||||||
pub fn render(&mut self, grid: &Grid, entities: &EntityManager, cam_x: i32, cam_y: i32) {
|
pub fn render(&mut self, grid: &Grid, entities: &EntityManager, cam_x: i32, cam_y: i32) {
|
||||||
self.check_resize();
|
self.check_resize();
|
||||||
let reg = MaterialRegistry::instance();
|
|
||||||
|
|
||||||
let mut entity_map: std::collections::HashMap<(i32, i32), [u8; 4]> = std::collections::HashMap::new();
|
let mut entity_map: std::collections::HashMap<(i32, i32), [u8; 4]> = std::collections::HashMap::new();
|
||||||
for e in entities.all() {
|
for e in entities.all() {
|
||||||
@@ -474,7 +472,6 @@ impl GraphicsRenderer {
|
|||||||
for &v in &self.swapchain_image_views { unsafe { self.device.destroy_image_view(v, None); } }
|
for &v in &self.swapchain_image_views { unsafe { self.device.destroy_image_view(v, None); } }
|
||||||
|
|
||||||
// Recreate swapchain
|
// Recreate swapchain
|
||||||
let qf_slice = [0u32]; // placeholder, not used with EXCLUSIVE
|
|
||||||
let sci = vk::SwapchainCreateInfoKHR::default()
|
let sci = vk::SwapchainCreateInfoKHR::default()
|
||||||
.surface(self.surface)
|
.surface(self.surface)
|
||||||
.min_image_count(caps.min_image_count.max(2))
|
.min_image_count(caps.min_image_count.max(2))
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ use crate::entity::EntityManager;
|
|||||||
use crate::render::Renderer;
|
use crate::render::Renderer;
|
||||||
use crate::world::cell::MaterialId;
|
use crate::world::cell::MaterialId;
|
||||||
use crate::world::grid::Grid;
|
use crate::world::grid::Grid;
|
||||||
use crate::world::material::MaterialRegistry;
|
|
||||||
|
|
||||||
pub struct TerminalRenderer {
|
pub struct TerminalRenderer {
|
||||||
width: usize,
|
width: usize,
|
||||||
@@ -70,7 +69,6 @@ impl Renderer for TerminalRenderer {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let reg = MaterialRegistry::instance();
|
|
||||||
let mut out = stdout();
|
let mut out = stdout();
|
||||||
let mut frame: Vec<(char, (u8, u8, u8), (u8, u8, u8))>;
|
let mut frame: Vec<(char, (u8, u8, u8), (u8, u8, u8))>;
|
||||||
let total = self.width * self.height;
|
let total = self.width * self.height;
|
||||||
@@ -80,13 +78,12 @@ impl Renderer for TerminalRenderer {
|
|||||||
for dx in 0..self.width {
|
for dx in 0..self.width {
|
||||||
let wx = cam_x + dx as i32;
|
let wx = cam_x + dx as i32;
|
||||||
let wy = cam_y + dy as i32;
|
let wy = cam_y + dy as i32;
|
||||||
|
let idx = dy * self.width + dx;
|
||||||
if !grid.in_bounds(wx, wy) {
|
if !grid.in_bounds(wx, wy) {
|
||||||
let idx = dy * self.width + dx;
|
|
||||||
frame[idx] = ('?', (80, 80, 80), (10, 10, 15));
|
frame[idx] = ('?', (80, 80, 80), (10, 10, 15));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let cell = grid.get(wx, wy);
|
let cell = grid.get(wx, wy);
|
||||||
let idx = dy * self.width + dx;
|
|
||||||
if cell.is_empty() {
|
if cell.is_empty() {
|
||||||
frame[idx] = (' ', (cell.fg[0], cell.fg[1], cell.fg[2]), (cell.bg[0], cell.bg[1], cell.bg[2]));
|
frame[idx] = (' ', (cell.fg[0], cell.fg[1], cell.fg[2]), (cell.bg[0], cell.bg[1], cell.bg[2]));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use std::sync::Arc;
|
|||||||
use crate::entity::{EntityManager, EntityKind};
|
use crate::entity::{EntityManager, EntityKind};
|
||||||
use crate::world::cell::MaterialId;
|
use crate::world::cell::MaterialId;
|
||||||
use crate::world::grid::Grid;
|
use crate::world::grid::Grid;
|
||||||
use crate::world::material::MaterialRegistry;
|
|
||||||
|
|
||||||
const CHAR_W: u32 = 16;
|
const CHAR_W: u32 = 16;
|
||||||
const CHAR_H: u32 = 16;
|
const CHAR_H: u32 = 16;
|
||||||
@@ -84,7 +83,6 @@ pub struct VulkanRenderer {
|
|||||||
descriptor_pool: vk::DescriptorPool,
|
descriptor_pool: vk::DescriptorPool,
|
||||||
descriptor_set: vk::DescriptorSet,
|
descriptor_set: vk::DescriptorSet,
|
||||||
descriptor_set_layout: vk::DescriptorSetLayout,
|
descriptor_set_layout: vk::DescriptorSetLayout,
|
||||||
tick_count: u64,
|
|
||||||
window: Arc<winit::window::Window>,
|
window: Arc<winit::window::Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,14 +155,12 @@ impl VulkanRenderer {
|
|||||||
atlas_image, atlas_memory, atlas_view, atlas_sampler, atlas_map,
|
atlas_image, atlas_memory, atlas_view, atlas_sampler, atlas_map,
|
||||||
instance_buffer, instance_memory, instance_ptr, instance_count,
|
instance_buffer, instance_memory, instance_ptr, instance_count,
|
||||||
descriptor_pool, descriptor_set, descriptor_set_layout,
|
descriptor_pool, descriptor_set, descriptor_set_layout,
|
||||||
tick_count: 0,
|
|
||||||
window,
|
window,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&mut self, grid: &Grid, entities: &EntityManager, cam_x: i32, cam_y: i32) {
|
pub fn render(&mut self, grid: &Grid, entities: &EntityManager, cam_x: i32, cam_y: i32) {
|
||||||
self.check_resize();
|
self.check_resize();
|
||||||
let reg = MaterialRegistry::instance();
|
|
||||||
|
|
||||||
let mut entity_map: std::collections::HashMap<(i32, i32), (char, [u8; 4])> = std::collections::HashMap::new();
|
let mut entity_map: std::collections::HashMap<(i32, i32), (char, [u8; 4])> = std::collections::HashMap::new();
|
||||||
for e in entities.all() {
|
for e in entities.all() {
|
||||||
@@ -306,7 +302,6 @@ impl VulkanRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.frame_index = (self.frame_index + 1) % MAX_FRAMES;
|
self.frame_index = (self.frame_index + 1) % MAX_FRAMES;
|
||||||
self.tick_count += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grid_w(&self) -> usize { self.grid_w }
|
pub fn grid_w(&self) -> usize { self.grid_w }
|
||||||
|
|||||||
@@ -74,11 +74,4 @@ impl WindowInput {
|
|||||||
else if keys.contains(&KeyCode::Digit0) { self.paint = Some(0); }
|
else if keys.contains(&KeyCode::Digit0) { self.paint = Some(0); }
|
||||||
else if keys.contains(&KeyCode::KeyX) { self.paint = Some(99); }
|
else if keys.contains(&KeyCode::KeyX) { self.paint = Some(99); }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
self.down_keys.clear();
|
|
||||||
self.left = false;
|
|
||||||
self.right = false;
|
|
||||||
self.jump = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-26
@@ -20,27 +20,6 @@ pub enum MaterialId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MaterialId {
|
impl MaterialId {
|
||||||
pub const ALL: [MaterialId; 14] = [
|
|
||||||
MaterialId::Empty,
|
|
||||||
MaterialId::Sand,
|
|
||||||
MaterialId::Water,
|
|
||||||
MaterialId::Stone,
|
|
||||||
MaterialId::Lava,
|
|
||||||
MaterialId::Wood,
|
|
||||||
MaterialId::Flesh,
|
|
||||||
MaterialId::Bone,
|
|
||||||
MaterialId::Steam,
|
|
||||||
MaterialId::Fire,
|
|
||||||
MaterialId::Acid,
|
|
||||||
MaterialId::Smoke,
|
|
||||||
MaterialId::Grass,
|
|
||||||
MaterialId::Dirt,
|
|
||||||
];
|
|
||||||
|
|
||||||
pub fn from_u8(v: u8) -> Self {
|
|
||||||
unsafe { std::mem::transmute(v) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn display_char(self) -> char {
|
pub fn display_char(self) -> char {
|
||||||
match self {
|
match self {
|
||||||
MaterialId::Empty => ' ',
|
MaterialId::Empty => ' ',
|
||||||
@@ -137,10 +116,9 @@ impl Cell {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
|
||||||
fn rand_u8() -> u8 {
|
fn rand_u8() -> u8 {
|
||||||
static mut COUNTER: u8 = 0;
|
static COUNTER: AtomicU8 = AtomicU8::new(0);
|
||||||
unsafe {
|
COUNTER.fetch_add(7, Ordering::Relaxed)
|
||||||
COUNTER = COUNTER.wrapping_add(7);
|
|
||||||
COUNTER
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -445,9 +445,6 @@ impl CellularAutomaton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick_count(&self) -> u64 {
|
|
||||||
self.tick
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NEIGHBORS4: [(i32, i32); 4] = [(0, -1), (0, 1), (-1, 0), (1, 0)];
|
const NEIGHBORS4: [(i32, i32); 4] = [(0, -1), (0, 1), (-1, 0), (1, 0)];
|
||||||
|
|||||||
+3
-53
@@ -5,7 +5,6 @@ pub const WORLD_H: usize = 250;
|
|||||||
|
|
||||||
pub struct Grid {
|
pub struct Grid {
|
||||||
pub cells: Vec<Cell>,
|
pub cells: Vec<Cell>,
|
||||||
pub next: Vec<Cell>,
|
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
}
|
}
|
||||||
@@ -15,7 +14,6 @@ impl Grid {
|
|||||||
let size = WORLD_W * WORLD_H;
|
let size = WORLD_W * WORLD_H;
|
||||||
Self {
|
Self {
|
||||||
cells: vec![Cell::empty(); size],
|
cells: vec![Cell::empty(); size],
|
||||||
next: vec![Cell::empty(); size],
|
|
||||||
width: WORLD_W,
|
width: WORLD_W,
|
||||||
height: WORLD_H,
|
height: WORLD_H,
|
||||||
}
|
}
|
||||||
@@ -39,45 +37,19 @@ impl Grid {
|
|||||||
self.cells[self.idx(x, y)]
|
self.cells[self.idx(x, y)]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_mut(&mut self, x: i32, y: i32) -> &mut Cell {
|
|
||||||
let i = self.idx(x, y);
|
|
||||||
&mut self.cells[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set(&mut self, x: i32, y: i32, cell: Cell) {
|
pub fn set(&mut self, x: i32, y: i32, cell: Cell) {
|
||||||
if self.in_bounds(x, y) {
|
if self.in_bounds(x, y) {
|
||||||
let i = self.idx(x, y);
|
let i = (y as usize) * self.width + (x as usize);
|
||||||
self.cells[i] = cell;
|
self.cells[i] = cell;
|
||||||
self.next[i] = cell;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_material(&mut self, x: i32, y: i32, mat: MaterialId) {
|
pub fn set_material(&mut self, x: i32, y: i32, mat: MaterialId) {
|
||||||
if self.in_bounds(x, y) {
|
if self.in_bounds(x, y) {
|
||||||
let cell = Cell::new(mat);
|
let i = (y as usize) * self.width + (x as usize);
|
||||||
let i = self.idx(x, y);
|
self.cells[i] = Cell::new(mat);
|
||||||
self.cells[i] = cell;
|
|
||||||
self.next[i] = cell;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
|
||||||
for c in &mut self.cells {
|
|
||||||
*c = Cell::empty();
|
|
||||||
}
|
|
||||||
for c in &mut self.next {
|
|
||||||
*c = Cell::empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fill_rect(&mut self, x0: i32, y0: i32, w: i32, h: i32, mat: MaterialId) {
|
|
||||||
for dy in 0..h {
|
|
||||||
for dx in 0..w {
|
|
||||||
self.set_material(x0 + dx, y0 + dy, mat);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,31 +64,9 @@ impl Grid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swap(&mut self) {
|
|
||||||
std::mem::swap(&mut self.cells, &mut self.next);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_tick_flags(&mut self) {
|
pub fn reset_tick_flags(&mut self) {
|
||||||
for c in &mut self.cells {
|
for c in &mut self.cells {
|
||||||
c.updated_this_tick = false;
|
c.updated_this_tick = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_region(&self, x0: i32, y0: i32, w: usize, h: usize) -> String {
|
|
||||||
let mut buf = String::with_capacity(w * h + h);
|
|
||||||
for dy in 0..h {
|
|
||||||
for dx in 0..w {
|
|
||||||
let x = x0 + dx as i32;
|
|
||||||
let y = y0 + dy as i32;
|
|
||||||
let ch = if self.in_bounds(x, y) {
|
|
||||||
self.get(x, y).display_char()
|
|
||||||
} else {
|
|
||||||
'?'
|
|
||||||
};
|
|
||||||
buf.push(ch);
|
|
||||||
}
|
|
||||||
buf.push('\n');
|
|
||||||
}
|
|
||||||
buf
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,24 +19,6 @@ pub struct Material {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Material {
|
impl Material {
|
||||||
pub const fn empty() -> Self {
|
|
||||||
Self {
|
|
||||||
id: MaterialId::Empty,
|
|
||||||
name: "empty",
|
|
||||||
density: 0.0,
|
|
||||||
solid: false,
|
|
||||||
liquid: false,
|
|
||||||
gas: false,
|
|
||||||
static_: true,
|
|
||||||
flammable: false,
|
|
||||||
ignition_temp: f32::INFINITY,
|
|
||||||
melt_temp: f32::INFINITY,
|
|
||||||
heat_conductivity: 0.0,
|
|
||||||
color_fg: (0, 0, 0),
|
|
||||||
color_bg: (0, 0, 0),
|
|
||||||
display_char: ' ',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MaterialRegistry {
|
pub struct MaterialRegistry {
|
||||||
|
|||||||
@@ -2,8 +2,3 @@ pub mod cell;
|
|||||||
pub mod material;
|
pub mod material;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
pub mod cellular;
|
pub mod cellular;
|
||||||
|
|
||||||
pub use cell::{Cell, MaterialId};
|
|
||||||
pub use material::{Material, MaterialRegistry};
|
|
||||||
pub use grid::{Grid, WORLD_W, WORLD_H};
|
|
||||||
pub use cellular::CellularAutomaton;
|
|
||||||
|
|||||||
@@ -166,7 +166,6 @@ fn center_camera_on_player() {
|
|||||||
s.perform_action(&AiAction::SetCamera { x: 0, y: 0 });
|
s.perform_action(&AiAction::SetCamera { x: 0, y: 0 });
|
||||||
s.step(30);
|
s.step(30);
|
||||||
s.perform_action(&AiAction::CenterCamera);
|
s.perform_action(&AiAction::CenterCamera);
|
||||||
let p = s.get_player().unwrap();
|
|
||||||
assert!(s.game.cam_x > 0, "camera should move from 0 toward player: got {}", s.game.cam_x);
|
assert!(s.game.cam_x > 0, "camera should move from 0 toward player: got {}", s.game.cam_x);
|
||||||
assert!(s.game.cam_y > 0, "camera should move from 0 toward player: got {}", s.game.cam_y);
|
assert!(s.game.cam_y > 0, "camera should move from 0 toward player: got {}", s.game.cam_y);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,11 +36,6 @@ fn ragdoll_falls_after_death() {
|
|||||||
let y_before = g.pos[1];
|
let y_before = g.pos[1];
|
||||||
|
|
||||||
s.perform_action(&AiAction::DamageEntity { id: g.id, amount: 100.0 });
|
s.perform_action(&AiAction::DamageEntity { id: g.id, amount: 100.0 });
|
||||||
s.step(1);
|
|
||||||
let y_death = {
|
|
||||||
let e = s.get_entities().into_iter().find(|e| e.id == g.id).unwrap();
|
|
||||||
e.pos[1]
|
|
||||||
};
|
|
||||||
s.step(30);
|
s.step(30);
|
||||||
let y_after = {
|
let y_after = {
|
||||||
let e = s.get_entities().into_iter().find(|e| e.id == g.id).unwrap();
|
let e = s.get_entities().into_iter().find(|e| e.id == g.id).unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user