230 lines
8.6 KiB
Rust
230 lines
8.6 KiB
Rust
use crate::{BG, GAME_SIZE};
|
|
|
|
use self::objs::{obj_traits::MovingObject, World};
|
|
use std::{
|
|
collections::{HashMap, HashSet},
|
|
num::NonZeroU32,
|
|
process,
|
|
rc::Rc,
|
|
time::{Duration, Instant},
|
|
};
|
|
use winit::{
|
|
dpi::PhysicalSize,
|
|
event::{Event, KeyEvent, StartCause, WindowEvent},
|
|
event_loop::{ControlFlow, EventLoop},
|
|
keyboard::{Key, KeyCode, NamedKey, PhysicalKey},
|
|
raw_window_handle::{HasDisplayHandle, HasWindowHandle},
|
|
window::WindowBuilder,
|
|
};
|
|
|
|
pub mod objs;
|
|
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<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();
|
|
|
|
Self {
|
|
event_loop,
|
|
render_fn: |_, _, _| {},
|
|
resize_fn: |_, _, _| {},
|
|
kb_handlers: HashMap::new(),
|
|
down_keys: HashSet::new(),
|
|
world: World::new(),
|
|
}
|
|
}
|
|
|
|
pub fn insert_into_world(&mut self, obj: Rc<dyn MovingObject>) -> usize {
|
|
self.world.insert(obj)
|
|
}
|
|
|
|
// sets the render function for the game
|
|
pub fn set_render_fn(mut self, f: RenderFn) -> Self {
|
|
self.render_fn = f;
|
|
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
|
|
let window = WindowBuilder::new()
|
|
.with_inner_size(winit::dpi::Size::Physical(PhysicalSize::new(1200, 700)))
|
|
.build(&event_loop)
|
|
.unwrap();
|
|
|
|
// set up softbuffer
|
|
let context = softbuffer::Context::new(window.display_handle().unwrap()).unwrap();
|
|
let mut surface =
|
|
softbuffer::Surface::new(&context, window.window_handle().unwrap()).unwrap();
|
|
|
|
let mut timer = timer::GameTimer::new();
|
|
|
|
event_loop
|
|
.run(|event, elwt| {
|
|
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 }),
|
|
} => {
|
|
if window_id == window.id() {
|
|
if let (Some(width), Some(height)) =
|
|
(NonZeroU32::new(width), NonZeroU32::new(height))
|
|
{
|
|
surface.resize(width, height).unwrap();
|
|
let mut buffer = surface.buffer_mut().unwrap();
|
|
buffer.fill(BG);
|
|
|
|
let mut ctx =
|
|
render::RenderCtx::new(buffer, (width, height), GAME_SIZE);
|
|
resize_fn(&mut ctx, &mut world, &timer);
|
|
}
|
|
}
|
|
}
|
|
Event::WindowEvent {
|
|
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();
|
|
|
|
let mut ctx =
|
|
render::RenderCtx::new(buffer, (width, height), GAME_SIZE);
|
|
|
|
// render
|
|
render_fn(&mut ctx, &mut world, &timer);
|
|
ctx.force_present();
|
|
timer.frame_update();
|
|
}
|
|
}
|
|
}
|
|
// crash game to exit lol
|
|
Event::WindowEvent {
|
|
window_id: _window_id,
|
|
event:
|
|
WindowEvent::CloseRequested
|
|
| WindowEvent::KeyboardInput {
|
|
event:
|
|
KeyEvent {
|
|
logical_key: Key::Named(NamedKey::Escape),
|
|
..
|
|
},
|
|
..
|
|
},
|
|
} => todo!(),
|
|
// potential future keyboard handling
|
|
Event::WindowEvent {
|
|
window_id: window_id,
|
|
event:
|
|
WindowEvent::KeyboardInput {
|
|
device_id: _device_id,
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
})
|
|
.unwrap();
|
|
process::exit(0);
|
|
}
|
|
}
|