From 62571655ae858d939cd9144f952ff87f505286a8 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Fri, 23 Feb 2024 10:11:52 +0100 Subject: [PATCH] add paddles that can move --- src/engine.rs | 84 +++++++++++++++++++++++--- src/engine/objs/geometry.rs | 2 +- src/engine/objs/obj_traits.rs | 28 +++++++++ src/engine/objs/primitive_shapes.rs | 6 +- src/main.rs | 94 ++++++++++++++++++++++++++--- 5 files changed, 194 insertions(+), 20 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index bb4240b..fe746df 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -2,6 +2,7 @@ use crate::{BG, GAME_SIZE}; use self::objs::{obj_traits::MovingObject, World}; use std::{ + collections::{HashMap, HashSet}, num::NonZeroU32, process, rc::Rc, @@ -11,7 +12,7 @@ use winit::{ dpi::PhysicalSize, event::{Event, KeyEvent, StartCause, WindowEvent}, event_loop::{ControlFlow, EventLoop}, - keyboard::{Key, NamedKey}, + keyboard::{Key, KeyCode, NamedKey, PhysicalKey}, raw_window_handle::{HasDisplayHandle, HasWindowHandle}, window::WindowBuilder, }; @@ -21,14 +22,25 @@ mod render; mod timer; type RenderFn = fn(&mut render::RenderCtx<'_, '_>, &mut World, &timer::GameTimer); +type KeyHandlerFn = fn(&mut World, &timer::GameTimer); + // core game engine struct pub struct Engine { event_loop: EventLoop<()>, render_fn: RenderFn, resize_fn: RenderFn, + kb_handlers: HashMap, + down_keys: HashSet, world: World, } +#[derive(PartialEq, Eq, Hash)] +pub enum KeyEventType { + KeyDown(KeyCode), + KeyDownFrameUpdate(KeyCode), + KeyUp(KeyCode), +} + impl Engine { pub fn new() -> Self { let event_loop = EventLoop::new().unwrap(); @@ -37,6 +49,8 @@ impl Engine { event_loop, render_fn: |_, _, _| {}, resize_fn: |_, _, _| {}, + kb_handlers: HashMap::new(), + down_keys: HashSet::new(), world: World::new(), } } @@ -57,6 +71,11 @@ impl Engine { self } + pub fn register_handler(mut self, ev_type: KeyEventType, f: KeyHandlerFn) -> Self { + self.kb_handlers.insert(ev_type, f); + self + } + // runs the game and consumes self, this will finish the process pub fn run(self) -> ! { let Self { @@ -64,6 +83,8 @@ impl Engine { mut world, render_fn, resize_fn, + kb_handlers, + mut down_keys, } = self; // set up window @@ -81,16 +102,17 @@ impl Engine { event_loop .run(|event, elwt| { - // shoddy vsync - elwt.set_control_flow(ControlFlow::WaitUntil( - Instant::now() + Duration::from_millis(1000 / 60), - )); - match event { // redraw Event::NewEvents(StartCause::ResumeTimeReached { .. }) => { window.request_redraw(); } + Event::NewEvents(StartCause::WaitCancelled { + start, + requested_resume, + }) => { + elwt.set_control_flow(ControlFlow::WaitUntil(requested_resume.unwrap())); + } Event::WindowEvent { window_id, event: WindowEvent::Resized(PhysicalSize { width, height }), @@ -113,11 +135,30 @@ impl Engine { window_id, event: WindowEvent::RedrawRequested, } => { + // shoddy vsync + elwt.set_control_flow(ControlFlow::WaitUntil( + Instant::now() + Duration::from_millis(1000 / 60), + )); if window_id == window.id() { if let (Some(width), Some(height)) = { let size = window.inner_size(); (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) } { + for frame_handler in + kb_handlers.iter().filter_map(|(ev, handler)| { + if let KeyEventType::KeyDownFrameUpdate(keycode) = ev { + if down_keys.contains(keycode) { + Some(handler) + } else { + None + } + } else { + None + } + }) + { + frame_handler(&mut world, &timer) + } surface.resize(width, height).unwrap(); let buffer = surface.buffer_mut().unwrap(); @@ -147,14 +188,39 @@ impl Engine { } => todo!(), // potential future keyboard handling Event::WindowEvent { - window_id: _window_id, + window_id: window_id, event: WindowEvent::KeyboardInput { device_id: _device_id, - event: _event, + event: + KeyEvent { + physical_key, + state, + repeat, + .. + }, is_synthetic: _is_synthetic, }, - } => {} + } => { + if !repeat { + if let PhysicalKey::Code(keycode) = physical_key { + let ev_type = match state { + winit::event::ElementState::Pressed => { + down_keys.insert(keycode); + KeyEventType::KeyDown(keycode) + } + winit::event::ElementState::Released => { + down_keys.remove(&keycode); + KeyEventType::KeyUp(keycode) + } + }; + + if let Some(handler) = kb_handlers.get(&ev_type) { + handler(&mut world, &timer) + } + } + } + } _ => {} } }) diff --git a/src/engine/objs/geometry.rs b/src/engine/objs/geometry.rs index 9766c6a..0555eb3 100644 --- a/src/engine/objs/geometry.rs +++ b/src/engine/objs/geometry.rs @@ -5,7 +5,7 @@ pub struct Position { } impl Position { - pub fn new(x: u32, y: u32) -> Self { + pub const fn new(x: u32, y: u32) -> Self { Self { x, y } } } diff --git a/src/engine/objs/obj_traits.rs b/src/engine/objs/obj_traits.rs index 4d0431f..701671a 100644 --- a/src/engine/objs/obj_traits.rs +++ b/src/engine/objs/obj_traits.rs @@ -38,4 +38,32 @@ pub trait MovingObject: Object { ctx.rect(prev_x, prev_y, width, height, BG); self.display(ctx); } + + fn move_constrained( + &mut self, + x: i32, + y: i32, + constraint_start: Position, + constraint_end: Position, + ) { + let Position { x: cur_x, y: cur_y } = self.position(); + let Size { width, height } = self.size(); + + let new_x = if cur_x.saturating_add_signed(x) <= constraint_start.x { + constraint_start.x + } else if (cur_x + width.saturating_add_signed(y)) > constraint_end.x { + constraint_end.x - width + } else { + cur_x.saturating_add_signed(x) + }; + + let new_y = if cur_y.saturating_add_signed(y) < constraint_start.y { + constraint_start.y + } else if (cur_y + height.saturating_add_signed(y)) >= constraint_end.y { + constraint_end.y - height + } else { + cur_y.saturating_add_signed(y) + }; + self.update_pos(new_x, new_y) + } } diff --git a/src/engine/objs/primitive_shapes.rs b/src/engine/objs/primitive_shapes.rs index 32c1748..549c6cf 100644 --- a/src/engine/objs/primitive_shapes.rs +++ b/src/engine/objs/primitive_shapes.rs @@ -10,7 +10,7 @@ pub struct Rect { } impl Rect { - pub fn new(x: u32, y: u32, height: u32, width: u32) -> Self { + pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self { Self { pos: Position::new(x, y), size: Size::new(width, height), @@ -42,10 +42,10 @@ pub struct MovingRect { } impl MovingRect { - pub fn new(x: u32, y: u32, height: u32, width: u32) -> Self { + pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self { Self { prev_pos: Position::new(x, y), - current: Rect::new(x, y, height, width), + current: Rect::new(x, y, width, height), } } diff --git a/src/main.rs b/src/main.rs index 2d26fb4..7bf159c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,99 @@ use std::rc::Rc; -use engine::Engine; +use engine::{ + objs::{geometry::Position, primitive_shapes::MovingRect}, + Engine, +}; +use winit::{ + event::KeyEvent, + keyboard::{Key, KeyCode, NamedKey, PhysicalKey, SmolStr}, +}; const GAME_SIZE: (u32, u32) = (1200, 800); const BORDER_WIDTH: u32 = 10; +const PADDLE_SIZE: (u32, u32) = (BORDER_WIDTH, 100); +const PADDLE_OFFSET: u32 = 20; +const PADDLE_SPEED: i32 = 10; const FG: u32 = 0xebdbb2; const BG: u32 = 0x282828; fn main() { let mut engine = Engine::new(); - // let _ = engine.insert_into_world(Rc::new(MovingRect::new(0, 0, 50, 100))); + + // left paddle + let _left_paddle_id = engine.insert_into_world(Rc::new(MovingRect::new( + BORDER_WIDTH + PADDLE_OFFSET, + GAME_SIZE.1 / 2 - PADDLE_SIZE.1 / 2, + PADDLE_SIZE.0, + PADDLE_SIZE.1, + ))); + let _right_paddle_id = engine.insert_into_world(Rc::new(MovingRect::new( + GAME_SIZE.0 - (BORDER_WIDTH + PADDLE_OFFSET + PADDLE_SIZE.0), + GAME_SIZE.1 / 2 - PADDLE_SIZE.1 / 2, + PADDLE_SIZE.0, + PADDLE_SIZE.1, + ))); + + const LEFT_PADDLE_CONSTRAINTS: (Position, Position) = ( + Position::new(BORDER_WIDTH + PADDLE_OFFSET, BORDER_WIDTH), + Position::new(BORDER_WIDTH * 2 + PADDLE_OFFSET, GAME_SIZE.1 - BORDER_WIDTH), + ); + const RIGHT_PADDLE_CONSTRAINTS: (Position, Position) = ( + Position::new( + GAME_SIZE.0 - (BORDER_WIDTH + PADDLE_OFFSET + PADDLE_SIZE.0), + BORDER_WIDTH, + ), + Position::new( + GAME_SIZE.0 - (BORDER_WIDTH + PADDLE_OFFSET), + GAME_SIZE.1 - BORDER_WIDTH, + ), + ); + engine + .register_handler( + engine::KeyEventType::KeyDownFrameUpdate(KeyCode::KeyW), + |world, timer| { + Rc::get_mut(world.get_mut(0)).unwrap().move_constrained( + 0, + -PADDLE_SPEED, + LEFT_PADDLE_CONSTRAINTS.0, + LEFT_PADDLE_CONSTRAINTS.1, + ) + }, + ) + .register_handler( + engine::KeyEventType::KeyDownFrameUpdate(KeyCode::KeyS), + |world, timer| { + Rc::get_mut(world.get_mut(0)).unwrap().move_constrained( + 0, + PADDLE_SPEED, + LEFT_PADDLE_CONSTRAINTS.0, + LEFT_PADDLE_CONSTRAINTS.1, + ) + }, + ) + .register_handler( + engine::KeyEventType::KeyDownFrameUpdate(KeyCode::KeyK), + |world, timer| { + Rc::get_mut(world.get_mut(1)).unwrap().move_constrained( + 0, + -PADDLE_SPEED, + RIGHT_PADDLE_CONSTRAINTS.0, + RIGHT_PADDLE_CONSTRAINTS.1, + ) + }, + ) + .register_handler( + engine::KeyEventType::KeyDownFrameUpdate(KeyCode::KeyJ), + |world, timer| { + Rc::get_mut(world.get_mut(1)).unwrap().move_constrained( + 0, + PADDLE_SPEED, + RIGHT_PADDLE_CONSTRAINTS.0, + RIGHT_PADDLE_CONSTRAINTS.1, + ) + }, + ) .set_resize_fn(|ctx, world, timer| { // top ctx.rect(0, 0, GAME_SIZE.0, BORDER_WIDTH, FG); @@ -34,11 +117,8 @@ fn main() { ctx.rect(0, GAME_SIZE.1 - BORDER_WIDTH, GAME_SIZE.0, 10, FG); }) .set_render_fn(|ctx, world, timer| { - // println!("t: {}", timer.game_time_passed()); - // let obj = Rc::get_mut(world.get_mut(0)).unwrap(); - // obj.move_obj(1, 0); - // obj.draw_move(ctx) - // Rect::square((timer.game_time_passed() * 20.) as u32, 0, 200).display(ctx); + Rc::get_mut(world.get_mut(0)).unwrap().draw_move(ctx); + Rc::get_mut(world.get_mut(1)).unwrap().draw_move(ctx); }) .run(); }