From dad94f7e8caa011c3d37f650470913c4e46cdc5c Mon Sep 17 00:00:00 2001 From: sfja Date: Wed, 1 Apr 2026 16:26:20 +0200 Subject: [PATCH] make executables game and editor --- game/Cargo.toml | 1 + game/src/bin/editor.rs | 4 + game/src/bin/game.rs | 4 + game/src/{main.rs => editor.rs} | 6 +- game/src/game.rs | 400 ++++++++++++++++++++++++++++++++ game/src/lib.rs | 5 + 6 files changed, 416 insertions(+), 4 deletions(-) create mode 100644 game/src/bin/editor.rs create mode 100644 game/src/bin/game.rs rename game/src/{main.rs => editor.rs} (99%) create mode 100644 game/src/game.rs create mode 100644 game/src/lib.rs diff --git a/game/Cargo.toml b/game/Cargo.toml index 0ec6a64..460f6b3 100644 --- a/game/Cargo.toml +++ b/game/Cargo.toml @@ -2,6 +2,7 @@ name = "skate-slope" version = "0.1.0" edition = "2021" +default-run = "game" [dependencies] sdl3 = "0.17.3" diff --git a/game/src/bin/editor.rs b/game/src/bin/editor.rs new file mode 100644 index 0000000..a74e210 --- /dev/null +++ b/game/src/bin/editor.rs @@ -0,0 +1,4 @@ + +fn main() -> Result<(), Box> { + skate_slope::game::game_main() +} diff --git a/game/src/bin/game.rs b/game/src/bin/game.rs new file mode 100644 index 0000000..a74e210 --- /dev/null +++ b/game/src/bin/game.rs @@ -0,0 +1,4 @@ + +fn main() -> Result<(), Box> { + skate_slope::game::game_main() +} diff --git a/game/src/main.rs b/game/src/editor.rs similarity index 99% rename from game/src/main.rs rename to game/src/editor.rs index 87c6b20..ac27d38 100644 --- a/game/src/main.rs +++ b/game/src/editor.rs @@ -13,9 +13,7 @@ use crate::{ vermiparous::Server, }; -mod engine; -mod event_queue; -mod vermiparous; +use crate::engine; struct Game { objects: Vec, @@ -362,7 +360,7 @@ impl Object { } } -fn main() -> Result<(), Box> { +pub fn game_main() -> Result<(), Box> { let mut sdl_io = engine::SdlIo::new()?; let event_queue = Arc::new(Mutex::new(EventQueue::new())); let mut game = Game::new(event_queue.clone()); diff --git a/game/src/game.rs b/game/src/game.rs new file mode 100644 index 0000000..ac27d38 --- /dev/null +++ b/game/src/game.rs @@ -0,0 +1,400 @@ +#![allow(dead_code)] + +use std::{ + collections::HashSet, + f64::consts::PI, + sync::{Arc, Mutex}, + time::Duration, +}; + +use crate::{ + engine::{Color, Key, Renderer, Scene, Shape, V3}, + event_queue::EventQueue, + vermiparous::Server, +}; + +use crate::engine; + +struct Game { + objects: Vec, + next_object_id: u32, + event_queue: Arc>, + keys_pressed: HashSet, +} + +impl Game { + fn new(event_queue: Arc>) -> Self { + Self { + objects: Vec::new(), + next_object_id: 0, + event_queue, + keys_pressed: HashSet::new(), + } + } + + fn spawn(&mut self, object_kind: ObjectKind) { + let object = Object { + kind: object_kind, + id: self.next_object_id, + }; + self.objects.push(object); + self.next_object_id += 1 + } + + fn despawn(&mut self, id: u32) { + let index = self + .objects + .iter() + .position(|o| o.id == id) + .expect("doesn't exist"); + self.objects.remove(index); + } +} + +impl engine::Game for Game { + fn update(&mut self, delta_time: Duration) { + for object in &mut self.objects { + if self.keys_pressed.contains(&Key::Left) == self.keys_pressed.contains(&Key::Right) { + if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind { + let decay_rate = 1.0 - (2.0 * delta_time.as_secs_f64()); + *pivot_deg *= decay_rate; + } + } + if self.keys_pressed.contains(&Key::Left) { + if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind { + *pivot_deg -= 18.0 * delta_time.as_secs_f64(); + if *pivot_deg < -12.5 { + *pivot_deg = -12.5; + } + } + } + if self.keys_pressed.contains(&Key::Right) { + if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind { + *pivot_deg += 18.0 * delta_time.as_secs_f64(); + if *pivot_deg > 12.5 { + *pivot_deg = 12.5; + } + } + } + + object.update(delta_time); + } + } + + fn render(&mut self, r: &mut R) { + let mut scene = Scene::new(); + for object in &self.objects { + object.render(&mut scene); + } + scene.render(r, V3(0.0, 0.0, -1.0)); + } + + fn event(&mut self, event: engine::Event) { + match event { + engine::Event::KeyDown { key } => self.keys_pressed.insert(key), + engine::Event::KeyUp { key } => self.keys_pressed.remove(&key), + }; + } +} + +struct Object { + kind: ObjectKind, + id: u32, +} + +enum ObjectKind { + SkateBoard { + pos: V3, + vel: V3, + rot: V3, + nyoom_factor: f64, + pivot_deg: f64, + }, + Obstacle { + pos: V3, + vel: V3, + }, + Ground { + original_pos: V3, + pos: V3, + vel: V3, + rot: V3, + grid_item_size: f64, + grid_width: i32, + grid_depth: i32, + }, +} + +struct ShapeGroupShape { + shape: Shape, + offset: V3, +} + +struct ShapeGroup { + pub shapes: Vec, +} + +impl ShapeGroup { + pub fn new(shapes: Vec) -> Self { + Self { shapes } + } + pub fn rotate(mut self, rot: V3) -> Self { + for shape in &mut self.shapes { + shape.shape = shape + .shape + .translate(shape.offset) + .rotate(rot) + .translate(shape.offset * -1.0); + } + self + } + pub fn translate(mut self, offset: V3) -> Self { + for shape in &mut self.shapes { + shape.shape = shape.shape.translate(offset); + } + self + } + pub fn draw(self, pos: V3, scene: &mut Scene, outline_color: Color, fill_color: Color) { + for shape in self.shapes { + scene.draw_shape( + pos, + &shape.shape.translate(shape.offset), + outline_color, + fill_color, + ); + } + } +} + +impl Object { + fn update(&mut self, delta_time: Duration) { + match &mut self.kind { + ObjectKind::SkateBoard { + pos, + vel, + nyoom_factor, + pivot_deg: pivot_factor, + .. + } => { + vel.0 = *pivot_factor * delta_time.as_secs_f64(); + *pos += *vel * delta_time.as_secs_f64(); + *nyoom_factor += 16.0 * delta_time.as_secs_f64(); + + // rot.0 += delta_time.as_secs_f64() * PI * 1.0; + // rot.1 += delta_time.as_secs_f64() * PI * 0.2; + // rot.2 += delta_time.as_secs_f64() * PI * 2.0; + } + ObjectKind::Obstacle { pos, vel } => { + *pos += *vel * delta_time.as_secs_f64(); + } + ObjectKind::Ground { + pos, + vel, + grid_depth, + grid_item_size, + original_pos, + .. + } => { + *pos += *vel * delta_time.as_secs_f64(); + *vel += V3(vel.0, vel.1, vel.0 - 0.01 * delta_time.as_secs_f64()); + if pos.2 <= original_pos.2 - *grid_depth as f64 * *grid_item_size { + pos.2 += *grid_depth as f64 * *grid_item_size + } + } + } + } + + fn render(&self, scene: &mut Scene) { + match self.kind { + ObjectKind::SkateBoard { + pos, + rot, + nyoom_factor, + pivot_deg, + .. + } => { + let board_size = V3(0.175, 0.005, 0.05); + let trucks = { + let anchor_size = V3(0.005, 0.01, 0.005); + let anchor_y = -anchor_size.1 - board_size.1 * 0.5; + let pivot = vec![ + ShapeGroupShape { + shape: Shape::new_cube(anchor_size), + offset: V3( + anchor_size.0 * -0.5 + board_size.0 * 0.4, + anchor_y, + anchor_size.2 * -0.5, + ), + }, + ShapeGroupShape { + shape: Shape::new_cube(anchor_size), + offset: V3( + anchor_size.0 * -0.5 - board_size.0 * 0.4, + anchor_y, + anchor_size.2 * -0.5, + ), + }, + ]; + let wheel_rail_size = V3(anchor_size.0, anchor_size.0, board_size.2 * 0.8); + let wheel_rail_y = anchor_y - wheel_rail_size.1; + let wheel_rail = vec![ + ShapeGroupShape { + shape: Shape::new_cube(wheel_rail_size), + offset: V3( + wheel_rail_size.0 * -0.5 + board_size.0 * 0.4, + wheel_rail_y, + wheel_rail_size.2 * -0.5, + ), + }, + ShapeGroupShape { + shape: Shape::new_cube(wheel_rail_size), + offset: V3( + wheel_rail_size.0 * -0.5 - board_size.0 * 0.4, + wheel_rail_y, + wheel_rail_size.2 * -0.5, + ), + }, + ]; + let wheel_size = V3(0.01, 0.01, 0.0025); + let wheel_y = wheel_rail_y - wheel_size.1 * 0.25; + let wheel_rot = V3(0.0, 0.0, nyoom_factor); + let wheel_rot_trans = V3(0.5, 0.5, 0.0); + let wheel = vec![ + ShapeGroupShape { + shape: Shape::new_cube(wheel_size) + .translate(wheel_size * wheel_rot_trans * -1.0) + .rotate(wheel_rot) + .translate(wheel_size * wheel_rot_trans), + offset: V3( + wheel_size.0 * -0.5 + board_size.0 * 0.4, + wheel_y, + wheel_rail_size.2 * -0.5 - wheel_size.2, + ), + }, + ShapeGroupShape { + shape: Shape::new_cube(wheel_size) + .translate(wheel_size * wheel_rot_trans * -1.0) + .rotate(wheel_rot) + .translate(wheel_size * wheel_rot_trans), + + offset: V3( + wheel_size.0 * -0.5 - board_size.0 * 0.4, + wheel_y, + wheel_rail_size.2 * -0.5 - wheel_size.2, + ), + }, + ShapeGroupShape { + shape: Shape::new_cube(wheel_size) + .translate(wheel_size * wheel_rot_trans * -1.0) + .rotate(wheel_rot) + .translate(wheel_size * wheel_rot_trans), + + offset: V3( + wheel_size.0 * -0.5 + board_size.0 * 0.4, + wheel_y, + wheel_rail_size.2 * 0.5, + ), + }, + ShapeGroupShape { + shape: Shape::new_cube(wheel_size) + .translate(wheel_size * wheel_rot_trans * -1.0) + .rotate(wheel_rot) + .translate(wheel_size * wheel_rot_trans), + + offset: V3( + wheel_size.0 * -0.5 - board_size.0 * 0.4, + wheel_y, + wheel_rail_size.2 * 0.5, + ), + }, + ]; + vec![pivot, wheel_rail, wheel].into_iter().flatten() + }; + let board_pivot_trans = V3(0.0, 0.5, 0.5); + let mut board = vec![ShapeGroupShape { + shape: Shape::new_cube(board_size) + .translate(board_size * board_pivot_trans * -1.0) + .rotate(V3(pivot_deg * (PI / 180.0), 0.0, 0.0)) + .translate(board_size * board_pivot_trans), + offset: board_size * -0.5, + }]; + board.extend(trucks); + let board = ShapeGroup::new(board).rotate(rot); + board.draw(pos, scene, Color::Green, Color::Black); + } + ObjectKind::Obstacle { pos, .. } => { + scene.draw_shape( + pos, + &Shape::new_cube(V3(0.2, 0.1, 0.2)), + Color::Green, + Color::Black, + ); + } + ObjectKind::Ground { + pos, + grid_depth, + grid_item_size, + grid_width, + .. + } => { + for grid in 0..5 { + let mut shapes = Vec::new(); + for z in 0..grid_depth { + for x in -grid_width / 2..grid_width / 2 { + shapes.push(ShapeGroupShape { + shape: Shape::new_plane(V3(grid_item_size, 0.0, grid_item_size)), + offset: V3( + x as f64 * grid_item_size, + 0.0, + z as f64 * grid_item_size + + grid as f64 * grid_depth as f64 * grid_item_size, + ), + }); + } + } + let ground = ShapeGroup::new(shapes); + ground.draw(pos, scene, Color::Cyan, Color::Black); + } + } + } + } +} + +pub fn game_main() -> Result<(), Box> { + let mut sdl_io = engine::SdlIo::new()?; + let event_queue = Arc::new(Mutex::new(EventQueue::new())); + let mut game = Game::new(event_queue.clone()); + std::thread::spawn(move || { + let server = Server::bind("10.133.51.127:5000"); + server.start(event_queue); + }); + let objects: Vec = vec![ + ObjectKind::SkateBoard { + pos: V3(0.0, -0.1, -0.7), + vel: V3(0.0, 0.0, 0.0), + rot: V3(0.0, PI * 0.5, 0.0), + nyoom_factor: 0.0, + pivot_deg: 0.0, + }, + ObjectKind::Ground { + original_pos: V3(0.0, -0.25, -0.6), + pos: V3(0.0, -0.25, -0.6), + vel: V3(0.0, 0.0, -0.1), + rot: V3(0.0, 0.0, 0.0), + grid_item_size: 0.1, + grid_width: 10, + grid_depth: 10, + }, + ObjectKind::Obstacle { + pos: V3(0.5, -0.2, 0.0), + vel: V3(0.0, 0.0, -0.1), + }, + ]; + + for object in objects { + game.spawn(object) + } + + sdl_io.run(&mut game); + Ok(()) +} diff --git a/game/src/lib.rs b/game/src/lib.rs new file mode 100644 index 0000000..fbd6b62 --- /dev/null +++ b/game/src/lib.rs @@ -0,0 +1,5 @@ +mod engine; +mod event_queue; +mod vermiparous; +pub mod game; +pub mod editor;