diff options
author | metamuffin <metamuffin@disroot.org> | 2024-07-17 20:32:06 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-07-17 20:32:06 +0200 |
commit | 356e6976f10973ec5e1678534c9d8d9742033bee (patch) | |
tree | 455e671ff0c24b876f3156ee56e61e43d608decb | |
parent | 4e2f42cc87e33752c76e866009786d4f827d9cb2 (diff) | |
download | hurrycurry-356e6976f10973ec5e1678534c9d8d9742033bee.tar hurrycurry-356e6976f10973ec5e1678534c9d8d9742033bee.tar.bz2 hurrycurry-356e6976f10973ec5e1678534c9d8d9742033bee.tar.zst |
a
-rw-r--r-- | Cargo.lock | 7 | ||||
-rw-r--r-- | pixel-client/Cargo.toml | 2 | ||||
-rw-r--r-- | pixel-client/src/game.rs | 159 | ||||
-rw-r--r-- | pixel-client/src/main.rs | 65 | ||||
-rw-r--r-- | pixel-client/src/menu.rs | 17 |
5 files changed, 160 insertions, 90 deletions
@@ -313,6 +313,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" [[package]] +name = "c_vec" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd7a427adc0135366d99db65b36dae9237130997e560ed61118041fb72be6e8" + +[[package]] name = "cc" version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1628,6 +1634,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b498da7d14d1ad6c839729bd4ad6fc11d90a57583605f3b4df2cd709a9cd380" dependencies = [ "bitflags 1.3.2", + "c_vec", "lazy_static", "libc", "sdl2-sys", diff --git a/pixel-client/Cargo.toml b/pixel-client/Cargo.toml index bd441236..dd46a9b6 100644 --- a/pixel-client/Cargo.toml +++ b/pixel-client/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -sdl2 = { version = "0.37.0", features = [] } +sdl2 = { version = "0.37.0", features = ["gfx", "ttf", "mixer"] } hurrycurry-protocol = { path = "../server/protocol" } tungstenite = { version = "0.23.0", features = ["rustls-tls-native-roots"] } serde_json = "1.0.120" diff --git a/pixel-client/src/game.rs b/pixel-client/src/game.rs index 170e6a6e..cbc9954c 100644 --- a/pixel-client/src/game.rs +++ b/pixel-client/src/game.rs @@ -17,6 +17,7 @@ */ use crate::{ helper::InterpolateExt, + network::Network, render::{ misc::MiscTextures, sprite::{Sprite, SpriteDraw}, @@ -34,9 +35,11 @@ use sdl2::{ keyboard::{KeyboardState, Scancode}, rect::Rect, }; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::{HashMap, HashSet}; pub struct Game { + network: Network, + data: ClientGamedata, tiles: HashMap<IVec2, Tile>, tilemap: Tilemap, @@ -82,8 +85,16 @@ pub struct Item { } impl Game { - pub fn new(layout: &AtlasLayout) -> Self { + pub fn new(mut network: Network, layout: &AtlasLayout) -> Self { + network + .queue_out + .push_back(hurrycurry_protocol::PacketS::Join { + name: "light".to_string(), + character: 0, + }); + Self { + network, tiles: HashMap::new(), players: HashMap::new(), tilemap: Tilemap::default(), @@ -100,18 +111,90 @@ impl Game { } } - pub fn packet_in(&mut self, packet: PacketC, renderer: &mut SpriteRenderer) { + pub fn tick(&mut self, dt: f32, keyboard: &KeyboardState, layout: &AtlasLayout) { + self.network.poll(); + + // TODO perf + for packet in self.network.queue_in.drain(..).collect::<Vec<_>>() { + self.packet_in(packet, layout); + } + + let mut direction = IVec2::new( + keyboard.is_scancode_pressed(Scancode::D) as i32 + - keyboard.is_scancode_pressed(Scancode::A) as i32, + keyboard.is_scancode_pressed(Scancode::S) as i32 + - keyboard.is_scancode_pressed(Scancode::W) as i32, + ) + .as_vec2(); + let boost = keyboard.is_scancode_pressed(Scancode::K); + let interact = keyboard.is_scancode_pressed(Scancode::Space) + | keyboard.is_scancode_pressed(Scancode::J); + + if interact { + direction *= 0.; + } + + self.movement_send_cooldown -= dt; + let send_movement = self.movement_send_cooldown < 0.; + if send_movement { + self.movement_send_cooldown += 0.04 + } + + self.score.time_remaining -= dt; + self.score.time_remaining -= self.score.time_remaining.max(0.); + + if interact != self.interacting { + if interact { + self.network.queue_out.push_back(PacketS::Interact { + pos: Some(self.players[&self.my_id].movement.get_interact_target()), + }); + } else { + self.network + .queue_out + .push_back(PacketS::Interact { pos: None }); + } + self.interacting = interact; + } + + if let Some(player) = self.players.get_mut(&self.my_id) { + let movement_packet = player + .movement + .update(&self.collision_map, direction, boost, dt); + if send_movement { + self.network.queue_out.push_back(movement_packet); + } + + self.camera_center.exp_to(player.movement.position, dt * 5.); + } + + for (_pid, player) in &mut self.players { + if let Some(item) = &mut player.item { + item.parent_position = player.movement.position; + item.tick(1., dt); + } + } + for (_pos, tile) in &mut self.tiles { + if let Some(item) = &mut tile.item { + item.tick(1., dt) + } + } + self.items_removed.retain_mut(|i| { + i.tick(0., dt); + i.alive > 0.01 + }) + } + + pub fn packet_in(&mut self, packet: PacketC, layout: &AtlasLayout) { match packet { PacketC::Init { id } => self.my_id = id, PacketC::Data { data } => { - self.tilemap.init(&data.tile_names, renderer.atlas_layout()); + self.tilemap.init(&data.tile_names, layout); self.item_sprites = data .item_names .iter() .map(|name| { Sprite::new( - renderer - .atlas_layout() + layout .get(&format!("{name}+a")) .copied() .unwrap_or_else(|| { @@ -264,70 +347,6 @@ impl Game { } } - pub fn tick(&mut self, dt: f32, keyboard: &KeyboardState, packet_out: &mut VecDeque<PacketS>) { - let mut direction = IVec2::new( - keyboard.is_scancode_pressed(Scancode::D) as i32 - - keyboard.is_scancode_pressed(Scancode::A) as i32, - keyboard.is_scancode_pressed(Scancode::S) as i32 - - keyboard.is_scancode_pressed(Scancode::W) as i32, - ) - .as_vec2(); - let boost = keyboard.is_scancode_pressed(Scancode::K); - let interact = keyboard.is_scancode_pressed(Scancode::Space) - | keyboard.is_scancode_pressed(Scancode::J); - - if interact { - direction *= 0.; - } - - self.movement_send_cooldown -= dt; - let send_movement = self.movement_send_cooldown < 0.; - if send_movement { - self.movement_send_cooldown += 0.04 - } - - self.score.time_remaining -= dt; - self.score.time_remaining -= self.score.time_remaining.max(0.); - - if interact != self.interacting { - if interact { - packet_out.push_back(PacketS::Interact { - pos: Some(self.players[&self.my_id].movement.get_interact_target()), - }); - } else { - packet_out.push_back(PacketS::Interact { pos: None }); - } - self.interacting = interact; - } - - if let Some(player) = self.players.get_mut(&self.my_id) { - let movement_packet = player - .movement - .update(&self.collision_map, direction, boost, dt); - if send_movement { - packet_out.push_back(movement_packet); - } - - self.camera_center.exp_to(player.movement.position, dt * 5.); - } - - for (_pid, player) in &mut self.players { - if let Some(item) = &mut player.item { - item.parent_position = player.movement.position; - item.tick(1., dt); - } - } - for (_pos, tile) in &mut self.tiles { - if let Some(item) = &mut tile.item { - item.tick(1., dt) - } - } - self.items_removed.retain_mut(|i| { - i.tick(0., dt); - i.alive > 0.01 - }) - } - pub fn draw(&self, ctx: &mut SpriteRenderer) { ctx.set_view(-self.camera_center + (ctx.size / ctx.get_scale() / 2.), 1.); diff --git a/pixel-client/src/main.rs b/pixel-client/src/main.rs index 76735c35..db2585af 100644 --- a/pixel-client/src/main.rs +++ b/pixel-client/src/main.rs @@ -1,5 +1,3 @@ -use anyhow::anyhow; -use clap::Parser; /* Hurry Curry! - a game about cooking Copyright 2024 metamuffin @@ -17,8 +15,11 @@ use clap::Parser; along with this program. If not, see <https://www.gnu.org/licenses/>. */ +use anyhow::anyhow; +use clap::{Parser, Subcommand}; use game::Game; use hurrycurry_protocol::glam::{UVec2, Vec2}; +use menu::Menu; use network::Network; use render::SpriteRenderer; use sdl2::{ @@ -33,17 +34,28 @@ use std::{ pub mod game; pub mod helper; +pub mod menu; pub mod network; pub mod render; pub mod tilemap; #[derive(Debug, Parser)] pub struct Args { - #[arg(default_value = "ws://127.0.0.1/")] - server_address: String, - #[arg(short = 'r', long, default_value = "320x240")] logical_resolution: Resolution, + + #[clap(subcommand)] + action: Option<Action>, +} + +#[derive(Debug, Subcommand, Default)] +pub enum Action { + #[default] + Menu, + Join { + #[arg(default_value = "ws://127.0.0.1/")] + server_address: String, + }, } #[derive(Debug, Clone)] @@ -56,6 +68,11 @@ impl FromStr for Resolution { } } +enum State { + Ingame(Game), + Menu(Menu), +} + fn main() { env_logger::init_from_env("LOG"); @@ -66,6 +83,7 @@ fn main() { .unwrap(); let sdl_context = sdl2::init().unwrap(); + let ttf_context = sdl2::ttf::init().unwrap(); let video_subsystem = sdl_context.video().unwrap(); let window = video_subsystem @@ -82,16 +100,24 @@ fn main() { .build() .map_err(|e| e.to_string()) .unwrap(); + let texture_creator = canvas.texture_creator(); - let mut net = Network::connect(&args.server_address).unwrap(); let mut renderer = SpriteRenderer::init(&texture_creator); - let mut game = Game::new(&renderer.atlas_layout()); - net.queue_out.push_back(hurrycurry_protocol::PacketS::Join { - name: "light".to_string(), - character: 0, - }); + let mut state = match args.action.unwrap_or_default() { + Action::Menu => State::Menu(Menu::new()), + Action::Join { server_address } => State::Ingame(Game::new( + Network::connect(&server_address).unwrap(), + &renderer.atlas_layout(), + )), + }; + + // let font = ttf_context + // .load_font("/usr/share/fonts/noto/NotoSansMono-Regular.ttf", 24) + // .unwrap(); + // let text = font.render("Hello world").blended(Color::WHITE).unwrap(); + // texture_creator.create_texture_from_surface(text).unwrap(); let mut events = sdl_context.event_pump().unwrap(); @@ -102,21 +128,22 @@ fn main() { .unwrap(); 'mainloop: loop { - net.poll(); - let (width, height) = canvas.logical_size(); renderer.size = Vec2::new(width as f32, height as f32); - for packet in net.queue_in.drain(..) { - game.packet_in(packet, &mut renderer); - } - let keyboard = KeyboardState::new(&events); let dt = last_tick.elapsed().min(Duration::from_secs_f32(1. / 30.)); - game.tick(dt.as_secs_f32(), &keyboard, &mut net.queue_out); + match &mut state { + State::Ingame(x) => x.tick(dt.as_secs_f32(), &keyboard, renderer.atlas_layout()), + State::Menu(x) => x.tick(dt.as_secs_f32(), &keyboard, renderer.atlas_layout()), + } + last_tick += dt; - game.draw(&mut renderer); + match &mut state { + State::Ingame(x) => x.draw(&mut renderer), + State::Menu(x) => x.draw(&mut renderer), + } canvas.set_draw_color(Color::BLACK); canvas.clear(); diff --git a/pixel-client/src/menu.rs b/pixel-client/src/menu.rs new file mode 100644 index 00000000..d1f43a84 --- /dev/null +++ b/pixel-client/src/menu.rs @@ -0,0 +1,17 @@ +use crate::render::{AtlasLayout, SpriteRenderer}; +use sdl2::keyboard::KeyboardState; + +pub struct Menu {} + +impl Menu { + pub fn new() -> Self { + Self {} + } + pub fn tick(&mut self, dt: f32, keyboard: &KeyboardState, layout: &AtlasLayout) {} + pub fn draw(&self, ctx: &mut SpriteRenderer) { + + + + + } +} |