add moving objects and stuff
This commit is contained in:
parent
b495dbbdcd
commit
93af87b482
5 changed files with 431 additions and 253 deletions
77
Cargo.lock
generated
77
Cargo.lock
generated
|
@ -290,12 +290,6 @@ dependencies = [
|
||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "downcast-rs"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "drm"
|
name = "drm"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
@ -521,15 +515,6 @@ version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memmap2"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk"
|
name = "ndk"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -685,15 +670,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quick-xml"
|
|
||||||
version = "0.31.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.35"
|
version = "1.0.35"
|
||||||
|
@ -749,12 +725,6 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scoped-tls"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.196"
|
version = "1.0.196"
|
||||||
|
@ -784,12 +754,6 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.13.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smol_str"
|
name = "smol_str"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -815,15 +779,12 @@ dependencies = [
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"memmap2",
|
|
||||||
"objc",
|
"objc",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"redox_syscall 0.4.1",
|
"redox_syscall 0.4.1",
|
||||||
"rustix",
|
"rustix",
|
||||||
"tiny-xlib",
|
"tiny-xlib",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wayland-backend",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-sys",
|
"wayland-sys",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
|
@ -994,43 +955,6 @@ version = "0.2.90"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-backend"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"downcast-rs",
|
|
||||||
"rustix",
|
|
||||||
"scoped-tls",
|
|
||||||
"smallvec",
|
|
||||||
"wayland-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-client"
|
|
||||||
version = "0.31.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.2",
|
|
||||||
"rustix",
|
|
||||||
"wayland-backend",
|
|
||||||
"wayland-scanner",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-scanner"
|
|
||||||
version = "0.31.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quick-xml",
|
|
||||||
"quote",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-sys"
|
name = "wayland-sys"
|
||||||
version = "0.31.1"
|
version = "0.31.1"
|
||||||
|
@ -1039,7 +963,6 @@ checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dlib",
|
"dlib",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -6,5 +6,5 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
softbuffer = { version = "0.4.1" }
|
softbuffer = { version = "0.4.1", default-features = false, features = [ "kms", "x11", "x11-dlopen"] }
|
||||||
winit = { version = "0.29.10", default-features = false, features = [ "x11", "rwh_06" ] }
|
winit = { version = "0.29.10", default-features = false, features = [ "x11", "rwh_06" ] }
|
||||||
|
|
349
src/engine.rs
Normal file
349
src/engine.rs
Normal file
|
@ -0,0 +1,349 @@
|
||||||
|
const GAME_SIZE: (u32, u32) = (500, 800);
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
num::NonZeroU32,
|
||||||
|
process,
|
||||||
|
rc::Rc,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
use softbuffer::Buffer;
|
||||||
|
use winit::{
|
||||||
|
dpi::PhysicalSize,
|
||||||
|
event::{Event, KeyEvent, StartCause, WindowEvent},
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
keyboard::{Key, NamedKey},
|
||||||
|
raw_window_handle::{HasDisplayHandle, HasWindowHandle},
|
||||||
|
window::WindowBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
|
use self::objs::{MovingObject, World};
|
||||||
|
|
||||||
|
type RenderFn = fn(&mut render::RenderCtx<'_, '_>, &mut World, &GameTimer);
|
||||||
|
// core game engine struct
|
||||||
|
pub struct Engine {
|
||||||
|
event_loop: EventLoop<()>,
|
||||||
|
render_fn: RenderFn,
|
||||||
|
world: World,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
event_loop,
|
||||||
|
render_fn: |_, _, _| {},
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// runs the game and consumes self, this will finish the process
|
||||||
|
pub fn run(self) -> ! {
|
||||||
|
let Self {
|
||||||
|
event_loop,
|
||||||
|
mut world,
|
||||||
|
render_fn,
|
||||||
|
} = 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 = GameTimer::new();
|
||||||
|
|
||||||
|
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::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::RedrawRequested,
|
||||||
|
} => {
|
||||||
|
if window_id == window.id() {
|
||||||
|
if let (Some(width), Some(height)) = {
|
||||||
|
let size = window.inner_size();
|
||||||
|
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
|
||||||
|
} {
|
||||||
|
surface.resize(width, height).unwrap();
|
||||||
|
let mut 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: _event,
|
||||||
|
is_synthetic: _is_synthetic,
|
||||||
|
},
|
||||||
|
} => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
process::exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GameTimer {
|
||||||
|
game_start: Instant,
|
||||||
|
last_frame: Instant,
|
||||||
|
stopwatches: HashMap<String, Instant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameTimer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
game_start: Instant::now(),
|
||||||
|
last_frame: Instant::now(),
|
||||||
|
stopwatches: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn frame_update(&mut self) {
|
||||||
|
self.last_frame = Instant::now()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delta_t(&self) -> f32 {
|
||||||
|
Instant::now().duration_since(self.last_frame).as_secs_f32()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn game_time_passed(&self) -> f32 {
|
||||||
|
Instant::now().duration_since(self.game_start).as_secs_f32()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_stopwatch(&mut self, name: impl ToString) {
|
||||||
|
let _ = self.stopwatches.insert(name.to_string(), Instant::now());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_stopwatch_time(&self, name: &str) -> Option<f32> {
|
||||||
|
self.stopwatches
|
||||||
|
.get(name)
|
||||||
|
.map(|start_time| Instant::now().duration_since(*start_time).as_secs_f32())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_stopwatch(&mut self, name: &str) {
|
||||||
|
let _ = self.stopwatches.remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod render;
|
||||||
|
|
||||||
|
pub mod objs {
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::render::RenderCtx;
|
||||||
|
|
||||||
|
pub struct World {
|
||||||
|
objects: Vec<Rc<dyn MovingObject>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl World {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
objects: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, obj: Rc<dyn MovingObject>) -> usize {
|
||||||
|
self.objects.push(obj);
|
||||||
|
self.objects.len() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, i: usize) -> Rc<dyn MovingObject> {
|
||||||
|
self.objects[i].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, i: usize) -> &mut Rc<dyn MovingObject> {
|
||||||
|
&mut self.objects[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw_all(&self, ctx: &mut RenderCtx<'_, '_>) {
|
||||||
|
self.objects.iter().for_each(|obj| obj.display(ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct Rect {
|
||||||
|
pos: Position,
|
||||||
|
size: Size,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rect {
|
||||||
|
pub fn new(x: u32, y: u32, height: u32, width: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
pos: Position::new(x, y),
|
||||||
|
size: Size::new(width, height),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn square(x: u32, y: u32, size: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
pos: Position::new(x, y),
|
||||||
|
size: Size::new(size, size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for Rect {
|
||||||
|
fn position(&self) -> Position {
|
||||||
|
self.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Size {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct MovingRect {
|
||||||
|
prev_pos: Position,
|
||||||
|
current: Rect,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MovingRect {
|
||||||
|
pub fn new(x: u32, y: u32, height: u32, width: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
prev_pos: Position::new(x, y),
|
||||||
|
current: Rect::new(x, y, height, width),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn square(x: u32, y: u32, size: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
prev_pos: Position::new(x, y),
|
||||||
|
current: Rect::square(x, y, size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Object for MovingRect {
|
||||||
|
fn position(&self) -> Position {
|
||||||
|
self.current.position()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Size {
|
||||||
|
self.current.size()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MovingObject for MovingRect {
|
||||||
|
fn previous_pos(&self) -> Position {
|
||||||
|
self.prev_pos
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_pos(&mut self, x: u32, y: u32) {
|
||||||
|
self.prev_pos = self.current.pos;
|
||||||
|
self.current.pos = Position::new(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct Position {
|
||||||
|
x: u32,
|
||||||
|
y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Position {
|
||||||
|
pub fn new(x: u32, y: u32) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct Size {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Size {
|
||||||
|
pub fn new(width: u32, height: u32) -> Self {
|
||||||
|
Self { width, height }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Object {
|
||||||
|
fn position(&self) -> Position;
|
||||||
|
fn size(&self) -> Size;
|
||||||
|
fn display(&self, ctx: &mut RenderCtx<'_, '_>) {
|
||||||
|
let Position { x, y } = self.position();
|
||||||
|
let Size { width, height } = self.size();
|
||||||
|
ctx.rect(x, y, width, height, 0xffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MovingObject: Object {
|
||||||
|
fn previous_pos(&self) -> Position;
|
||||||
|
fn update_pos(&mut self, x: u32, y: u32);
|
||||||
|
fn move_obj(&mut self, x: i32, y: i32) {
|
||||||
|
let Position { x: cur_x, y: cur_y } = self.position();
|
||||||
|
|
||||||
|
self.update_pos(
|
||||||
|
cur_x.saturating_add_signed(x),
|
||||||
|
cur_y.saturating_add_signed(y),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: damage
|
||||||
|
fn draw_move(&self, ctx: &mut RenderCtx<'_, '_>) {
|
||||||
|
let Position {
|
||||||
|
x: prev_x,
|
||||||
|
y: prev_y,
|
||||||
|
} = self.previous_pos();
|
||||||
|
let Size { width, height } = self.size();
|
||||||
|
|
||||||
|
ctx.rect(prev_x, prev_y, width, height, 0x000000);
|
||||||
|
self.display(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
src/engine/render.rs
Normal file
62
src/engine/render.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
use std::num::NonZeroU32;
|
||||||
|
|
||||||
|
use winit::raw_window_handle::WindowHandle;
|
||||||
|
|
||||||
|
use winit::raw_window_handle::DisplayHandle;
|
||||||
|
|
||||||
|
use softbuffer::Buffer;
|
||||||
|
|
||||||
|
use super::objs::Object;
|
||||||
|
|
||||||
|
// render context
|
||||||
|
pub struct RenderCtx<'buf, 'win> {
|
||||||
|
pub(crate) buffer: Buffer<'buf, DisplayHandle<'win>, WindowHandle<'win>>,
|
||||||
|
pub(crate) win_size: (u32, u32),
|
||||||
|
pub(crate) context_size: (u32, u32),
|
||||||
|
pub(crate) context_pos: (u32, u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'buf, 'win> RenderCtx<'buf, 'win> {
|
||||||
|
// create new render context
|
||||||
|
pub fn new(
|
||||||
|
buffer: Buffer<'buf, DisplayHandle<'win>, WindowHandle<'win>>,
|
||||||
|
win_size: (NonZeroU32, NonZeroU32),
|
||||||
|
context_size: (u32, u32),
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
buffer,
|
||||||
|
win_size: (win_size.0.get(), win_size.1.get()),
|
||||||
|
context_size,
|
||||||
|
context_pos: (
|
||||||
|
(win_size.0.get() / 2).saturating_sub(context_size.0 / 2),
|
||||||
|
(win_size.1.get() / 2).saturating_sub(context_size.1 / 2),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self, color: u32) {
|
||||||
|
self.rect(0, 0, self.win_size.0, self.win_size.1, color)
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw a rectangle in the context
|
||||||
|
//
|
||||||
|
// coordinates are relative to the context
|
||||||
|
pub fn rect(&mut self, x: u32, y: u32, width: u32, height: u32, color: u32) {
|
||||||
|
// position in buffer coordinates and not relative coordinates
|
||||||
|
let x_buf_pos = self.context_pos.0 + x;
|
||||||
|
let y_buf_pos = self.context_pos.1 + y;
|
||||||
|
|
||||||
|
for y in y_buf_pos..(y_buf_pos + height) {
|
||||||
|
for x in x_buf_pos..(x_buf_pos + width) {
|
||||||
|
let index = y as usize * self.win_size.0 as usize + x as usize;
|
||||||
|
if let Some(px) = self.buffer.get_mut(index) {
|
||||||
|
*px = color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn force_present(self) {
|
||||||
|
self.buffer.present().unwrap()
|
||||||
|
}
|
||||||
|
}
|
194
src/main.rs
194
src/main.rs
|
@ -1,181 +1,25 @@
|
||||||
use engine::Engine;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use engine::{
|
||||||
|
objs::{MovingRect, Object, Rect},
|
||||||
|
Engine,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Engine::new()
|
let mut engine = Engine::new();
|
||||||
.set_render_fn(|mut ctx| {
|
let rect_id = engine.insert_into_world(Rc::new(MovingRect::square(0, 0, 1)));
|
||||||
// draw three colored rectagles(tm)
|
engine
|
||||||
ctx.rect_unchecked(0, 0, 100, 100, 0xff0000);
|
.set_render_fn(|ctx, world, timer| {
|
||||||
ctx.rect_unchecked(100, 0, 100, 100, 0x00ff00);
|
println!("t: {}", timer.game_time_passed());
|
||||||
ctx.rect_unchecked(0, 100, 100, 100, 0x0000ff);
|
let obj = Rc::get_mut(world.get_mut(0)).unwrap();
|
||||||
|
obj.update_pos(
|
||||||
|
((timer.game_time_passed().sin() + 1.0) * 256.) as u32,
|
||||||
|
((timer.game_time_passed().cos() + 1.0) * 256.) as u32,
|
||||||
|
);
|
||||||
|
obj.display(ctx)
|
||||||
|
// Rect::square((timer.game_time_passed() * 20.) as u32, 0, 200).display(ctx);
|
||||||
})
|
})
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
mod engine {
|
mod engine;
|
||||||
const GAME_SIZE: (u32, u32) = (500, 800);
|
|
||||||
use std::{
|
|
||||||
num::NonZeroU32,
|
|
||||||
process,
|
|
||||||
time::{Duration, Instant},
|
|
||||||
};
|
|
||||||
|
|
||||||
use softbuffer::Buffer;
|
|
||||||
use winit::{
|
|
||||||
dpi::PhysicalSize,
|
|
||||||
event::{Event, KeyEvent, StartCause, WindowEvent},
|
|
||||||
event_loop::{ControlFlow, EventLoop},
|
|
||||||
keyboard::{Key, NamedKey},
|
|
||||||
raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle, WindowHandle},
|
|
||||||
window::WindowBuilder,
|
|
||||||
};
|
|
||||||
|
|
||||||
type RenderFn = fn(&mut RenderCtx<'_, '_>);
|
|
||||||
// core game engine struct
|
|
||||||
pub struct Engine {
|
|
||||||
event_loop: EventLoop<()>,
|
|
||||||
render_fn: RenderFn,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Engine {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let event_loop = EventLoop::new().unwrap();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
event_loop,
|
|
||||||
render_fn: |_| {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sets the render function for the game
|
|
||||||
pub fn set_render_fn(mut self, f: RenderFn) -> Self {
|
|
||||||
self.render_fn = f;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// runs the game and consumes self, this will finish the process
|
|
||||||
pub fn run(self) -> ! {
|
|
||||||
let Self {
|
|
||||||
event_loop,
|
|
||||||
render_fn,
|
|
||||||
} = 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();
|
|
||||||
|
|
||||||
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 {
|
|
||||||
start: _start,
|
|
||||||
requested_resume: _requested_resume,
|
|
||||||
}) => {
|
|
||||||
if let (Some(width), Some(height)) = {
|
|
||||||
let size = window.inner_size();
|
|
||||||
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
|
|
||||||
} {
|
|
||||||
surface.resize(width, height).unwrap();
|
|
||||||
let mut buffer = surface.buffer_mut().unwrap();
|
|
||||||
buffer.fill(0);
|
|
||||||
|
|
||||||
let mut ctx = RenderCtx::new(buffer, (width, height), GAME_SIZE);
|
|
||||||
|
|
||||||
// render
|
|
||||||
render_fn(&mut ctx);
|
|
||||||
ctx.force_present();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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: _event,
|
|
||||||
is_synthetic: _is_synthetic,
|
|
||||||
},
|
|
||||||
} => {}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
process::exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// render context
|
|
||||||
pub struct RenderCtx<'buf, 'win> {
|
|
||||||
buffer: Buffer<'buf, DisplayHandle<'win>, WindowHandle<'win>>,
|
|
||||||
win_size: (u32, u32),
|
|
||||||
context_size: (u32, u32),
|
|
||||||
context_pos: (u32, u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'buf, 'win> RenderCtx<'buf, 'win> {
|
|
||||||
// create new render context
|
|
||||||
pub fn new(
|
|
||||||
buffer: Buffer<'buf, DisplayHandle<'win>, WindowHandle<'win>>,
|
|
||||||
win_size: (NonZeroU32, NonZeroU32),
|
|
||||||
context_size: (u32, u32),
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
buffer,
|
|
||||||
win_size: (win_size.0.get(), win_size.1.get()),
|
|
||||||
context_size,
|
|
||||||
context_pos: (
|
|
||||||
(win_size.0.get() / 2).saturating_sub(context_size.0 / 2),
|
|
||||||
(win_size.1.get() / 2).saturating_sub(context_size.1 / 2),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw a rectangle in the context
|
|
||||||
//
|
|
||||||
// coordinates are relative to the context
|
|
||||||
pub fn rect_unchecked(&mut self, x: u32, y: u32, width: u32, height: u32, color: u32) {
|
|
||||||
// position in buffer coordinates and not relative coordinates
|
|
||||||
let x_buf_pos = self.context_pos.0 + x;
|
|
||||||
let y_buf_pos = self.context_pos.1 + y;
|
|
||||||
|
|
||||||
for y in y_buf_pos..(y_buf_pos + height) {
|
|
||||||
for x in x_buf_pos..(x_buf_pos + width) {
|
|
||||||
let index = y as usize * self.win_size.0 as usize + x as usize;
|
|
||||||
if let Some(px) = self.buffer.get_mut(index) {
|
|
||||||
*px = color
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn force_present(self) {
|
|
||||||
self.buffer.present().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue