Created
December 30, 2020 13:00
-
-
Save jsimmons/9da60b8f8d1c717f8f8def2e30114752 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::{ | |
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}, | |
time::{Duration, Instant}, | |
}; | |
use sdl2::{event::Event, rect::Rect, render::WindowCanvas, Sdl}; | |
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] | |
pub struct Vec2 { | |
pub x: i32, | |
pub y: i32, | |
} | |
impl Vec2 { | |
pub const fn new(x: i32, y: i32) -> Self { | |
Self { x, y } | |
} | |
pub const fn zero() -> Self { | |
Self { x: 0, y: 0 } | |
} | |
} | |
impl Add for Vec2 { | |
type Output = Vec2; | |
fn add(self, rhs: Self) -> Self::Output { | |
Self::Output { | |
x: self.x + rhs.x, | |
y: self.y + rhs.y, | |
} | |
} | |
} | |
impl AddAssign for Vec2 { | |
fn add_assign(&mut self, rhs: Self) { | |
self.x += rhs.x; | |
self.y += rhs.y; | |
} | |
} | |
impl Sub for Vec2 { | |
type Output = Vec2; | |
fn sub(self, rhs: Self) -> Self::Output { | |
Self::Output { | |
x: self.x - rhs.x, | |
y: self.y - rhs.y, | |
} | |
} | |
} | |
impl SubAssign for Vec2 { | |
fn sub_assign(&mut self, rhs: Self) { | |
self.x += rhs.x; | |
self.y += rhs.y; | |
} | |
} | |
impl Mul for Vec2 { | |
type Output = Vec2; | |
fn mul(self, rhs: Self) -> Self::Output { | |
Self::Output { | |
x: self.x * rhs.x, | |
y: self.y * rhs.y, | |
} | |
} | |
} | |
impl MulAssign for Vec2 { | |
fn mul_assign(&mut self, rhs: Self) { | |
self.x *= rhs.x; | |
self.y *= rhs.y; | |
} | |
} | |
impl Div for Vec2 { | |
type Output = Vec2; | |
fn div(self, rhs: Self) -> Self::Output { | |
Self::Output { | |
x: self.x / rhs.x, | |
y: self.y / rhs.y, | |
} | |
} | |
} | |
impl DivAssign for Vec2 { | |
fn div_assign(&mut self, rhs: Self) { | |
self.x *= rhs.x; | |
self.y *= rhs.y; | |
} | |
} | |
impl From<Vec2> for sdl2::rect::Point { | |
fn from(point: Vec2) -> Self { | |
Self::new(point.x, point.y) | |
} | |
} | |
#[derive(Copy, Clone, Debug, Default, PartialEq)] | |
pub struct Colour { | |
pub r: u8, | |
pub g: u8, | |
pub b: u8, | |
pub a: u8, | |
} | |
impl Colour { | |
pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self { | |
Self { r, g, b, a } | |
} | |
} | |
impl From<Colour> for sdl2::pixels::Color { | |
fn from(colour: Colour) -> Self { | |
sdl2::pixels::Color::from((colour.r, colour.g, colour.b, colour.a)) | |
} | |
} | |
pub trait Input { | |
fn process(&mut self, event: &sdl2::event::Event); | |
} | |
pub enum TickState { | |
Continue, | |
Terminate, | |
} | |
pub struct Draw { | |
canvas: WindowCanvas, | |
canvas_size: Vec2, | |
} | |
impl Draw { | |
fn new(context: &Sdl, title: &str) -> Self { | |
let video_subsystem = context.video().unwrap(); | |
let window = video_subsystem | |
.window(title, 800, 600) | |
.position_centered() | |
.build() | |
.unwrap(); | |
let canvas = window.into_canvas().build().unwrap(); | |
Self { | |
canvas, | |
canvas_size: Vec2 { x: 800, y: 600 }, | |
} | |
} | |
pub fn canvas_size(&self) -> Vec2 { | |
self.canvas_size | |
} | |
pub fn clear(&mut self, colour: Colour) { | |
self.canvas.set_draw_color(colour); | |
self.canvas.clear(); | |
} | |
pub fn line(&mut self, a: Vec2, b: Vec2, colour: Colour) { | |
self.canvas.set_draw_color(colour); | |
self.canvas.draw_line(a, b).unwrap(); | |
} | |
pub fn rectangle_fill(&mut self, position: Vec2, size: Vec2, colour: Colour) { | |
self.canvas.set_draw_color(colour); | |
self.canvas | |
.fill_rect(Rect::new( | |
position.x, | |
position.y, | |
size.x as u32, | |
size.y as u32, | |
)) | |
.unwrap(); | |
} | |
pub fn rectangle_outline(&mut self, position: Vec2, size: Vec2, colour: Colour) { | |
self.canvas.set_draw_color(colour); | |
self.canvas | |
.draw_rect(Rect::new( | |
position.x, | |
position.y, | |
size.x as u32, | |
size.y as u32, | |
)) | |
.unwrap(); | |
} | |
fn present(&mut self) { | |
self.canvas.present() | |
} | |
} | |
pub trait Loop<I: Input + Default> { | |
const TICK_HZ: u64 = 100; | |
const NAME: &'static str; | |
fn tick(&mut self, frame: u64, input: &I) -> TickState; | |
fn draw(&self, drawer: &mut Draw); | |
fn run(&mut self) { | |
let tick_time = Duration::from_secs_f64(1.0 / Self::TICK_HZ as f64); | |
let context = sdl2::init().unwrap(); | |
let mut drawer = Draw::new(&context, Self::NAME); | |
let mut event_pump = context.event_pump().unwrap(); | |
let mut input = I::default(); | |
let mut last_update = Instant::now(); | |
let mut frame = 0; | |
let mut tick_accumulator = tick_time; | |
'running: loop { | |
while tick_accumulator >= tick_time { | |
for event in event_pump.poll_iter() { | |
match event { | |
Event::Quit { .. } => break 'running, | |
_ => { | |
input.process(&event); | |
} | |
} | |
} | |
self.tick(frame, &input); | |
frame += 1; | |
tick_accumulator -= tick_time; | |
} | |
self.draw(&mut drawer); | |
drawer.present(); | |
let now = Instant::now(); | |
tick_accumulator += now - last_update; | |
last_update = now; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment