Compare commits
2 commits
11f9fecba1
...
62571655ae
Author | SHA1 | Date | |
---|---|---|---|
62571655ae | |||
a1346780ab |
6 changed files with 238 additions and 48 deletions
122
src/engine.rs
122
src/engine.rs
|
@ -1,5 +1,8 @@
|
|||
use crate::{BG, GAME_SIZE};
|
||||
|
||||
use self::objs::{obj_traits::MovingObject, World};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
num::NonZeroU32,
|
||||
process,
|
||||
rc::Rc,
|
||||
|
@ -9,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,
|
||||
};
|
||||
|
@ -18,19 +21,26 @@ pub mod objs;
|
|||
mod render;
|
||||
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 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<KeyEventType, KeyHandlerFn>,
|
||||
down_keys: HashSet<KeyCode>,
|
||||
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();
|
||||
|
@ -38,6 +48,9 @@ impl Engine {
|
|||
Self {
|
||||
event_loop,
|
||||
render_fn: |_, _, _| {},
|
||||
resize_fn: |_, _, _| {},
|
||||
kb_handlers: HashMap::new(),
|
||||
down_keys: HashSet::new(),
|
||||
world: World::new(),
|
||||
}
|
||||
}
|
||||
|
@ -52,12 +65,26 @@ impl Engine {
|
|||
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
|
||||
pub fn run(self) -> ! {
|
||||
let Self {
|
||||
event_loop,
|
||||
mut world,
|
||||
render_fn,
|
||||
resize_fn,
|
||||
kb_handlers,
|
||||
mut down_keys,
|
||||
} = self;
|
||||
|
||||
// set up window
|
||||
|
@ -75,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 }),
|
||||
|
@ -99,27 +127,7 @@ impl Engine {
|
|||
|
||||
let mut ctx =
|
||||
render::RenderCtx::new(buffer, (width, height), GAME_SIZE);
|
||||
|
||||
// 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);
|
||||
resize_fn(&mut ctx, &mut world, &timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,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();
|
||||
|
||||
|
@ -161,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::rc::Rc;
|
|||
|
||||
use self::obj_traits::MovingObject;
|
||||
|
||||
use super::{render::RenderCtx, BG, FG};
|
||||
use super::render::RenderCtx;
|
||||
|
||||
pub mod geometry;
|
||||
pub mod obj_traits;
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::engine::{render::RenderCtx, BG, FG};
|
||||
use crate::{
|
||||
engine::{render::RenderCtx, BG},
|
||||
FG,
|
||||
};
|
||||
|
||||
use super::geometry::{Position, Size};
|
||||
|
||||
|
@ -35,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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
121
src/main.rs
121
src/main.rs
|
@ -1,17 +1,124 @@
|
|||
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);
|
||||
// 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| {
|
||||
// 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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue