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 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
121
src/main.rs
121
src/main.rs
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue