Compare commits

..

2 commits

Author SHA1 Message Date
62571655ae
add paddles that can move 2024-02-23 10:11:52 +01:00
a1346780ab
move constants to main and add resize fn 2024-02-23 08:42:03 +01:00
6 changed files with 238 additions and 48 deletions

View file

@ -1,5 +1,8 @@
use crate::{BG, GAME_SIZE};
use self::objs::{obj_traits::MovingObject, World}; use self::objs::{obj_traits::MovingObject, World};
use std::{ use std::{
collections::{HashMap, HashSet},
num::NonZeroU32, num::NonZeroU32,
process, process,
rc::Rc, rc::Rc,
@ -9,7 +12,7 @@ use winit::{
dpi::PhysicalSize, dpi::PhysicalSize,
event::{Event, KeyEvent, StartCause, WindowEvent}, event::{Event, KeyEvent, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop}, event_loop::{ControlFlow, EventLoop},
keyboard::{Key, NamedKey}, keyboard::{Key, KeyCode, NamedKey, PhysicalKey},
raw_window_handle::{HasDisplayHandle, HasWindowHandle}, raw_window_handle::{HasDisplayHandle, HasWindowHandle},
window::WindowBuilder, window::WindowBuilder,
}; };
@ -18,19 +21,26 @@ pub mod objs;
mod render; mod render;
mod timer; mod timer;
const GAME_SIZE: (u32, u32) = (1200, 800);
const BORDER_WIDTH: u32 = 10;
const FG: u32 = 0xebdbb2;
const BG: u32 = 0x282828;
type RenderFn = fn(&mut render::RenderCtx<'_, '_>, &mut World, &timer::GameTimer); type RenderFn = fn(&mut render::RenderCtx<'_, '_>, &mut World, &timer::GameTimer);
type KeyHandlerFn = fn(&mut World, &timer::GameTimer);
// core game engine struct // core game engine struct
pub struct Engine { pub struct Engine {
event_loop: EventLoop<()>, event_loop: EventLoop<()>,
render_fn: RenderFn, render_fn: RenderFn,
resize_fn: RenderFn,
kb_handlers: HashMap<KeyEventType, KeyHandlerFn>,
down_keys: HashSet<KeyCode>,
world: World, world: World,
} }
#[derive(PartialEq, Eq, Hash)]
pub enum KeyEventType {
KeyDown(KeyCode),
KeyDownFrameUpdate(KeyCode),
KeyUp(KeyCode),
}
impl Engine { impl Engine {
pub fn new() -> Self { pub fn new() -> Self {
let event_loop = EventLoop::new().unwrap(); let event_loop = EventLoop::new().unwrap();
@ -38,6 +48,9 @@ impl Engine {
Self { Self {
event_loop, event_loop,
render_fn: |_, _, _| {}, render_fn: |_, _, _| {},
resize_fn: |_, _, _| {},
kb_handlers: HashMap::new(),
down_keys: HashSet::new(),
world: World::new(), world: World::new(),
} }
} }
@ -52,12 +65,26 @@ impl Engine {
self self
} }
// sets the resize render function for the game
pub fn set_resize_fn(mut self, f: RenderFn) -> Self {
self.resize_fn = f;
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 // runs the game and consumes self, this will finish the process
pub fn run(self) -> ! { pub fn run(self) -> ! {
let Self { let Self {
event_loop, event_loop,
mut world, mut world,
render_fn, render_fn,
resize_fn,
kb_handlers,
mut down_keys,
} = self; } = self;
// set up window // set up window
@ -75,16 +102,17 @@ impl Engine {
event_loop event_loop
.run(|event, elwt| { .run(|event, elwt| {
// shoddy vsync
elwt.set_control_flow(ControlFlow::WaitUntil(
Instant::now() + Duration::from_millis(1000 / 60),
));
match event { match event {
// redraw // redraw
Event::NewEvents(StartCause::ResumeTimeReached { .. }) => { Event::NewEvents(StartCause::ResumeTimeReached { .. }) => {
window.request_redraw(); window.request_redraw();
} }
Event::NewEvents(StartCause::WaitCancelled {
start,
requested_resume,
}) => {
elwt.set_control_flow(ControlFlow::WaitUntil(requested_resume.unwrap()));
}
Event::WindowEvent { Event::WindowEvent {
window_id, window_id,
event: WindowEvent::Resized(PhysicalSize { width, height }), event: WindowEvent::Resized(PhysicalSize { width, height }),
@ -99,27 +127,7 @@ impl Engine {
let mut ctx = let mut ctx =
render::RenderCtx::new(buffer, (width, height), GAME_SIZE); render::RenderCtx::new(buffer, (width, height), GAME_SIZE);
resize_fn(&mut ctx, &mut world, &timer);
// top
ctx.rect(0, 0, GAME_SIZE.0, BORDER_WIDTH, FG);
// left
ctx.rect(
0,
BORDER_WIDTH,
BORDER_WIDTH,
GAME_SIZE.1 - BORDER_WIDTH * 2,
FG,
);
// right
ctx.rect(
GAME_SIZE.0 - BORDER_WIDTH,
BORDER_WIDTH,
BORDER_WIDTH,
GAME_SIZE.1 - BORDER_WIDTH * 2,
FG,
);
// bottom
ctx.rect(0, GAME_SIZE.1 - BORDER_WIDTH, GAME_SIZE.0, 10, FG);
} }
} }
} }
@ -127,11 +135,30 @@ impl Engine {
window_id, window_id,
event: WindowEvent::RedrawRequested, event: WindowEvent::RedrawRequested,
} => { } => {
// shoddy vsync
elwt.set_control_flow(ControlFlow::WaitUntil(
Instant::now() + Duration::from_millis(1000 / 60),
));
if window_id == window.id() { if window_id == window.id() {
if let (Some(width), Some(height)) = { if let (Some(width), Some(height)) = {
let size = window.inner_size(); let size = window.inner_size();
(NonZeroU32::new(size.width), NonZeroU32::new(size.height)) (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(); surface.resize(width, height).unwrap();
let buffer = surface.buffer_mut().unwrap(); let buffer = surface.buffer_mut().unwrap();
@ -161,14 +188,39 @@ impl Engine {
} => todo!(), } => todo!(),
// potential future keyboard handling // potential future keyboard handling
Event::WindowEvent { Event::WindowEvent {
window_id: _window_id, window_id: window_id,
event: event:
WindowEvent::KeyboardInput { WindowEvent::KeyboardInput {
device_id: _device_id, device_id: _device_id,
event: _event, event:
KeyEvent {
physical_key,
state,
repeat,
..
},
is_synthetic: _is_synthetic, 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)
}
}
}
}
_ => {} _ => {}
} }
}) })

View file

@ -2,7 +2,7 @@ use std::rc::Rc;
use self::obj_traits::MovingObject; use self::obj_traits::MovingObject;
use super::{render::RenderCtx, BG, FG}; use super::render::RenderCtx;
pub mod geometry; pub mod geometry;
pub mod obj_traits; pub mod obj_traits;

View file

@ -5,7 +5,7 @@ pub struct Position {
} }
impl Position { impl Position {
pub fn new(x: u32, y: u32) -> Self { pub const fn new(x: u32, y: u32) -> Self {
Self { x, y } Self { x, y }
} }
} }

View file

@ -1,4 +1,7 @@
use crate::engine::{render::RenderCtx, BG, FG}; use crate::{
engine::{render::RenderCtx, BG},
FG,
};
use super::geometry::{Position, Size}; use super::geometry::{Position, Size};
@ -35,4 +38,32 @@ pub trait MovingObject: Object {
ctx.rect(prev_x, prev_y, width, height, BG); ctx.rect(prev_x, prev_y, width, height, BG);
self.display(ctx); 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)
}
} }

View file

@ -10,7 +10,7 @@ pub struct Rect {
} }
impl 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 { Self {
pos: Position::new(x, y), pos: Position::new(x, y),
size: Size::new(width, height), size: Size::new(width, height),
@ -42,10 +42,10 @@ pub struct MovingRect {
} }
impl 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 { Self {
prev_pos: Position::new(x, y), prev_pos: Position::new(x, y),
current: Rect::new(x, y, height, width), current: Rect::new(x, y, width, height),
} }
} }

View file

@ -1,17 +1,124 @@
use std::rc::Rc; 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() { fn main() {
let mut engine = Engine::new(); 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 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);
// left
ctx.rect(
0,
BORDER_WIDTH,
BORDER_WIDTH,
GAME_SIZE.1 - BORDER_WIDTH * 2,
FG,
);
// right
ctx.rect(
GAME_SIZE.0 - BORDER_WIDTH,
BORDER_WIDTH,
BORDER_WIDTH,
GAME_SIZE.1 - BORDER_WIDTH * 2,
FG,
);
// bottom
ctx.rect(0, GAME_SIZE.1 - BORDER_WIDTH, GAME_SIZE.0, 10, FG);
})
.set_render_fn(|ctx, world, timer| { .set_render_fn(|ctx, world, timer| {
// println!("t: {}", timer.game_time_passed()); Rc::get_mut(world.get_mut(0)).unwrap().draw_move(ctx);
// let obj = Rc::get_mut(world.get_mut(0)).unwrap(); Rc::get_mut(world.get_mut(1)).unwrap().draw_move(ctx);
// obj.move_obj(1, 0);
// obj.draw_move(ctx)
// Rect::square((timer.game_time_passed() * 20.) as u32, 0, 200).display(ctx);
}) })
.run(); .run();
} }