basic refactoring

This commit is contained in:
Schrottkatze 2024-02-23 08:37:13 +01:00
parent b8d27eb909
commit 11f9fecba1
Signed by: schrottkatze
SSH key fingerprint: SHA256:hXb3t1vINBFCiDCmhRABHX5ocdbLiKyCdKI4HK2Rbbc
8 changed files with 238 additions and 230 deletions

View file

@ -1,16 +1,10 @@
const GAME_SIZE: (u32, u32) = (1200, 800); use self::objs::{obj_traits::MovingObject, World};
const BORDER_WIDTH: u32 = 10;
const FG: u32 = 0xebdbb2;
const BG: u32 = 0x282828;
use std::{ use std::{
collections::HashMap,
num::NonZeroU32, num::NonZeroU32,
process, process,
rc::Rc, rc::Rc,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use softbuffer::Buffer;
use winit::{ use winit::{
dpi::PhysicalSize, dpi::PhysicalSize,
event::{Event, KeyEvent, StartCause, WindowEvent}, event::{Event, KeyEvent, StartCause, WindowEvent},
@ -20,9 +14,16 @@ use winit::{
window::WindowBuilder, window::WindowBuilder,
}; };
use self::objs::{MovingObject, World}; pub mod objs;
mod render;
mod timer;
type RenderFn = fn(&mut render::RenderCtx<'_, '_>, &mut World, &GameTimer); 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);
// core game engine struct // core game engine struct
pub struct Engine { pub struct Engine {
event_loop: EventLoop<()>, event_loop: EventLoop<()>,
@ -70,7 +71,7 @@ impl Engine {
let mut surface = let mut surface =
softbuffer::Surface::new(&context, window.window_handle().unwrap()).unwrap(); softbuffer::Surface::new(&context, window.window_handle().unwrap()).unwrap();
let mut timer = GameTimer::new(); let mut timer = timer::GameTimer::new();
event_loop event_loop
.run(|event, elwt| { .run(|event, elwt| {
@ -132,7 +133,7 @@ impl Engine {
(NonZeroU32::new(size.width), NonZeroU32::new(size.height)) (NonZeroU32::new(size.width), NonZeroU32::new(size.height))
} { } {
surface.resize(width, height).unwrap(); surface.resize(width, height).unwrap();
let mut buffer = surface.buffer_mut().unwrap(); let buffer = surface.buffer_mut().unwrap();
let mut ctx = let mut ctx =
render::RenderCtx::new(buffer, (width, height), GAME_SIZE); render::RenderCtx::new(buffer, (width, height), GAME_SIZE);
@ -175,216 +176,3 @@ impl Engine {
process::exit(0); 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, BG, FG};
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, FG);
}
}
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, BG);
self.display(ctx);
}
}
}

38
src/engine/objs.rs Normal file
View file

@ -0,0 +1,38 @@
use std::rc::Rc;
use self::obj_traits::MovingObject;
use super::{render::RenderCtx, BG, FG};
pub mod geometry;
pub mod obj_traits;
pub mod primitive_shapes;
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))
}
}

View file

@ -0,0 +1,22 @@
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Position {
pub x: u32,
pub y: u32,
}
impl Position {
pub fn new(x: u32, y: u32) -> Self {
Self { x, y }
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Size {
pub width: u32,
pub height: u32,
}
impl Size {
pub fn new(width: u32, height: u32) -> Self {
Self { width, height }
}
}

View file

@ -0,0 +1,38 @@
use crate::engine::{render::RenderCtx, BG, FG};
use super::geometry::{Position, Size};
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, FG);
}
}
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, BG);
self.display(ctx);
}
}

View file

@ -0,0 +1,79 @@
use super::{
geometry::{Position, Size},
obj_traits::{MovingObject, Object},
};
#[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);
}
}

View file

@ -6,8 +6,6 @@ use winit::raw_window_handle::DisplayHandle;
use softbuffer::Buffer; use softbuffer::Buffer;
use super::objs::Object;
// render context // render context
pub struct RenderCtx<'buf, 'win> { pub struct RenderCtx<'buf, 'win> {
pub(crate) buffer: Buffer<'buf, DisplayHandle<'win>, WindowHandle<'win>>, pub(crate) buffer: Buffer<'buf, DisplayHandle<'win>, WindowHandle<'win>>,
@ -58,6 +56,9 @@ impl<'buf, 'win> RenderCtx<'buf, 'win> {
} }
} }
/// draw a rectangle in a context
///
/// this method limits overflows etc
pub fn rect(&mut self, x: u32, y: u32, width: u32, height: u32, color: u32) { pub fn rect(&mut self, x: u32, y: u32, width: u32, height: u32, color: u32) {
if x >= self.context_size.0 || y >= self.context_size.1 || width == 0 || height == 0 { if x >= self.context_size.0 || y >= self.context_size.1 || width == 0 || height == 0 {
} else { } else {

45
src/engine/timer.rs Normal file
View file

@ -0,0 +1,45 @@
use std::collections::HashMap;
use std::time::Instant;
pub struct GameTimer {
pub(crate) game_start: Instant,
pub(crate) last_frame: Instant,
pub(crate) 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);
}
}

View file

@ -1,9 +1,6 @@
use std::rc::Rc; use std::rc::Rc;
use engine::{ use engine::Engine;
objs::{MovingRect, Object, Rect},
Engine,
};
fn main() { fn main() {
let mut engine = Engine::new(); let mut engine = Engine::new();