Skip to content

Instantly share code, notes, and snippets.

@jsimmons
Created December 30, 2020 13:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsimmons/9da60b8f8d1c717f8f8def2e30114752 to your computer and use it in GitHub Desktop.
Save jsimmons/9da60b8f8d1c717f8f8def2e30114752 to your computer and use it in GitHub Desktop.
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