diff options
author | curly <curlybryce@protonmail.com> | 2023-10-03 08:29:52 -0600 |
---|---|---|
committer | curly <curlybryce@protonmail.com> | 2023-10-03 08:29:52 -0600 |
commit | fc49095da2e419c12c50849170bc424c9185de8b (patch) | |
tree | 7d2031f564a513fba70ef0be0a960aa8566ad894 /src | |
download | topdown-master.tar.gz topdown-master.tar.bz2 topdown-master.zip |
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7e882f3 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,438 @@ +use sdl2::gfx::primitives::DrawRenderer; +use sdl2::pixels::Color; +use sdl2::event::Event; +use sdl2::rect::{Rect, Point}; +use sdl2::keyboard::Keycode; +use sdl2::render::Texture; +use std::time::Duration; +use std::collections::HashMap; + +struct Camera { + x: f32, + y: f32, + scale: f32, + offset: Pos, + rotation: Rot, +} +#[allow(dead_code)] +impl Camera { + pub fn new() -> Camera { + Camera { x: 0.0, y: 0.0, scale: 1.0, offset: Pos(0.0, 0.0), rotation: Rot::new() } + } + + fn translate(&mut self, x: f32, y: f32) { + self.x += x; + self.y += y; + } + + fn set_pos(&mut self, x: f32, y: f32) { + self.x = x; + self.y = y; + } + + fn get_pos(&self) -> Pos { + Pos(self.x.into(), self.y.into()) + } + + fn get_scale(&self) -> f32 { + self.scale + } + + fn set_scale(&mut self, d: f32) { + if d.is_finite() { + self.scale = d; + } + } + + fn modify_scale(&mut self, d: f32) { + let d = self.scale + d; + if d < 0.1 { + self.scale = 0.1 + } else { + self.scale = d + } + } + + fn set_rotation(&mut self, deg: f32) { + self.rotation.set(deg); + } + + fn modify_rotation(&mut self, deg: f32) { + self.rotation.modify(deg); + } + + fn rotate_point(&self, p_origin: Pos, p: Pos, deg: Rot) -> Pos { + let deg = deg.get_deg(); + let p = Pos(p.0 - p_origin.0, p.1 - p_origin.1); + let p = Pos( + p.0 * deg.cos() - p.1 * deg.sin(), + p.0 * deg.sin() + p.1 * deg.cos() + ); + p + } + + fn transform(&self, mut p: Pos, window_size: (u32, u32)) -> Pos { + p.0 = self.x + p.0 * self.scale; + p.1 = self.y - p.1 * self.scale; + + let window_size = Pos(window_size.0 as f32, window_size.1 as f32) / 2.0; + let mut p = self.rotate_point(Pos(window_size.0, window_size.1), p, self.rotation); + + p.0 += window_size.0; + p.1 += window_size.1; + + p + } + + fn translate_offset(&mut self, p: Pos) { + self.offset += p * (self.get_scale().powi(-1) + 0.3) + } + + fn reset(&mut self) { + self.offset = Pos(0.0, 0.0); + self.rotation = Rot::new(); + self.scale = 1.0; + } + + fn center_on(&mut self, pos: &Pos, window_size: (u32, u32)) { + self.x = (window_size.0 / 2) as f32 - (pos.0 * self.scale) - (self.offset.0 * self.scale); + self.y = (window_size.1 / 2) as f32 + (pos.1 * self.scale) + (self.offset.1 * self.scale); + } +} + +#[derive(Copy, Clone, Debug)] +struct Pos(f32, f32); +impl std::ops::Add for Pos { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0, self.1 + rhs.1) + } +} +impl std::ops::Sub for Pos { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0, self.1 - rhs.1) + } +} +impl std::ops::Div<f32> for Pos { + type Output = Self; + + fn div(self, rhs: f32) -> Self::Output { + Pos(self.0 / rhs, self.1 / rhs) + } +} +impl std::ops::Mul<f32> for Pos { + type Output = Self; + + fn mul(self, rhs: f32) -> Self::Output { + Pos(self.0 * rhs, self.1 * rhs) + } +} +impl std::ops::AddAssign for Pos { + fn add_assign(&mut self, rhs: Self) { + self.0 += rhs.0; + self.1 += rhs.1; + } +} +impl From<Pos> for Point { + fn from(value: Pos) -> Self { + (value.0 as i32, value.1 as i32).into() + } +} +impl From<Point> for Pos { + fn from(value: Point) -> Self { + Pos(value.x as f32, value.y as f32) + } +} + + +const PI: f32 = 3.14159; +#[derive(Copy, Clone, Debug)] +struct Rot(f32); +impl Rot { + fn new() -> Rot { + Rot(0.0) + } + + fn modify(&mut self, deg: f32) { + self.0 = Rot::sanitize(self.0 + deg); + } + + fn set(&mut self, deg: f32) { + self.0 = Rot::sanitize(deg); + } + + #[allow(dead_code)] + fn get(&self) -> f32 { + self.0 + } + + fn sanitize(deg: f32) -> f32 { + if deg > 360.0 { + -360.0 + deg.fract() + } else if deg < -360.0 { + Rot::sanitize(deg * -1.0) * -1.0 + } else { + deg + } + } + + fn get_deg(&self) -> f32 { + ((self.0 / 360.0) * PI) * -1.0 + } +} + + +#[derive(Copy, Clone)] + +enum Object { + Circle(Pos, Rot, f32), + Rect(Rot, Rect), +} +impl Object { + fn get_pos(&self) -> Pos { + match self { + Self::Circle(p, _, _) => *p, + Self::Rect(_, rect) => {rect.center().into()}, + } + } + + fn translate(&mut self, pos: Pos) { + match self { + Self::Circle(p, _, _) => { + let new = *p + pos; + p.0 = new.0; + p.1 = new.1; + }, + Self::Rect(_, rect) => { + rect.offset(pos.0 as i32, pos.1 as i32) + } + } + } + + fn modify_rotation(&mut self, deg: f32) { + match self { + Self::Circle(_, r, _) => { + r.modify(deg) + }, + Self::Rect(r, _) => { + r.modify(deg) + } + } + } + + fn draw(&mut self, canvas: &mut sdl2::render::Canvas<sdl2::video::Window>, cam: &Camera, color: Color, t: Option<&Texture>) { + let x = match self { + Self::Circle(p, _, rad) => { + let p = cam.transform(*p, canvas.output_size().unwrap()); + canvas.aa_circle(p.0 as i16, p.1 as i16, (*rad * cam.scale) as i16, color) + }, + Self::Rect(r, rect) => { + let r = *r; + let window_size = canvas.output_size().unwrap(); + let center = rect.center().into(); + + let tl = rect.top_left().into(); + let tr = rect.top_right().into(); + let bl = rect.bottom_left().into(); + let br = rect.bottom_right().into(); + + let tl = cam.rotate_point(center, tl, r) + center; + let tr = cam.rotate_point(center, tr, r) + center; + let bl = cam.rotate_point(center, bl, r) + center; + let br = cam.rotate_point(center, br, r) + center; + + let tl = cam.transform(tl, window_size); + let tr = cam.transform(tr, window_size); + let bl = cam.transform(bl, window_size); + let br = cam.transform(br, window_size); + + + let pos1 = Point::from(tl); // Top Left + let pos2 = Point::from(tr); // Top Right + let pos3 = Point::from(br); // Bottom Right + let pos4 = Point::from(bl); // Bottom Left + + match t { + Some(n) => { + canvas.copy_ex(n, *rect, None, r.get_deg() as f64, rect.center(), false, false) + }, + None => { + canvas.aa_polygon(&[pos1.x as i16, pos2.x as i16, pos3.x as i16, pos4.x as i16], &[pos1.y as i16, pos2.y as i16, pos3.y as i16, pos4.y as i16], color) + } + } + } + }; + + match x { + Ok(_) => (), + Err(n) => println!("Draw Error: {}", n), + } + } + + fn new_rect(p: Pos, p2: Pos) -> Object { + let w = p2.0 - p.0; + let h = p2.1 - p.1; + let center = Pos(p.0 - (w / 2.0), p.1 - (h / 2.0)); + Self::Rect(Rot::new(), Rect::new(center.0 as i32, center.1 as i32, w as u32, h as u32)) + } +} + +struct KeyState(HashMap<Keycode, bool>); +impl KeyState { + fn new() -> KeyState { + KeyState ( + HashMap::new() + ) + } + + #[allow(dead_code)] + fn get(&self, k: Keycode) -> bool { + *self.0.get(&k).unwrap_or(&false) + } + + fn set(&mut self, k: Keycode, v: bool) { + self.0.insert(k, v); + } + + fn pairs(&self) -> Vec<(Keycode, bool)> { + self.0.clone().into_iter().collect() + } +} + +fn main() { + println!("--Program start--"); + + let sdl_context = sdl2::init().unwrap(); + let video_subsystem = sdl_context.video().unwrap(); + let window = video_subsystem.window("rust-sdl2 demo", 800, 600) + .position_centered() + .build() + .unwrap(); + let mut canvas = window.into_canvas().build().unwrap(); + // let texture_creator = canvas.texture_creator(); + let mut event_pump = sdl_context.event_pump().unwrap(); + let mut cam = Camera::new(); + + let mut keymap = KeyState::new(); + // let mut character = Object::Circle(Pos(0.0, 0.0), Rot::new(), 10.0); + let mut character = Object::new_rect(Pos(0.0, 0.0), Pos(100.0, 100.0)); + + let mut degree = Rot::new(); + + 'main: loop { + degree.modify(0.8 * PI); + + // Clear the frame + canvas.set_draw_color(Color::RGB(128, 128, 128)); + canvas.clear(); + + let window_size = canvas.output_size().unwrap(); + + // Process events + for event in event_pump.poll_iter() { + match event { + Event::Quit {..} | + Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { + // Quit program without saving + break 'main + }, + Event::KeyDown { keycode: Some(n), ..} => { + keymap.set(n, true); + } + Event::KeyUp { keycode: Some(n), .. } => { + keymap.set(n, false) + } + _ => () + } + } + + // Process keymap + for x in keymap.pairs() { + match x { + (n, true) => { + use Keycode::*; + match n { + // Character translation + W => character.translate(Pos(0.0, 5.0)), + A => character.translate(Pos(-5.0, 0.0)), + S => character.translate(Pos(0.0, -5.0)), + D => character.translate(Pos(5.0, 0.0)), + // Character rotation + Q => character.modify_rotation(-2.0), + E => character.modify_rotation(2.0), + // Camera translation (local axis) + Up => cam.translate_offset(Pos(0.0, 5.0)), + Left => cam.translate_offset(Pos(-5.0, 0.0)), + Down => cam.translate_offset(Pos(0.0, -5.0)), + Right => cam.translate_offset(Pos(5.0, 0.0)), + // Camera translation (global axis) + I => cam.translate_offset(cam.rotate_point(Pos(0.0, 0.0), Pos(0.0, 5.0), cam.rotation)), + J => cam.translate_offset(cam.rotate_point(Pos(0.0, 0.0), Pos(-5.0, 0.0), cam.rotation)), + K => cam.translate_offset(cam.rotate_point(Pos(0.0, 0.0), Pos(0.0, -5.0), cam.rotation)), + L => cam.translate_offset(cam.rotate_point(Pos(0.0, 0.0), Pos(5.0, 0.0), cam.rotation)), + // Camera rotation + U => cam.modify_rotation(-2.0), + O => cam.modify_rotation(2.0), + // Camera scale + N => cam.modify_scale(0.1), + M => cam.modify_scale(-0.1), + // Reset Camera + Space => cam.reset(), + _ => (), + } + }, + _ => () + } + } + + // Center on the character + cam.center_on(&character.get_pos(), canvas.output_size().unwrap()); + + //Draw stuff + let mut wall = Object::Circle(Pos(-15.0, -100.0), Rot::new(), 5.0); + wall.draw(&mut canvas, &cam, Color::RGB(255, 255, 255), None); + + // let rect_pos = cam.transform(Pos(0.0, 0.0)); + // let rect = Rect::new(rect_pos.0 as i32, rect_pos.1 as i32, 5, 5); + // canvas.draw_rect(rect).unwrap(); + + // let mut circle = Object::Circle(Pos(50.0, 50.0), 100.0); + // circle.draw(&canvas, &cam, Color::RGB(255,255,255)); + + canvas.set_draw_color(Color::RGB(50, 255, 50)); + let start = cam.transform(Pos(0.0, -300.0), window_size); + let end = cam.transform(Pos(0.0, 300.0), window_size); + canvas.draw_line(start, end); + let start = cam.transform(Pos(-300.0, 0.0), window_size); + let end = cam.transform(Pos(300.0, 0.0), window_size); + canvas.draw_line(start, end); + + let trigon_center = Pos(30.0, -30.0); + let trigon_1 = cam.transform(cam.rotate_point(trigon_center, Pos(0.0, 0.0), degree), window_size); + let trigon_2 = cam.transform(cam.rotate_point(trigon_center, Pos(-20.0, -60.0), degree), window_size); + let trigon_3 = cam.transform(cam.rotate_point(trigon_center, Pos(20.0, -60.0), degree), window_size); + canvas.trigon(trigon_1.0 as i16, + trigon_1.1 as i16, + trigon_2.0 as i16, + trigon_2.1 as i16, + trigon_3.0 as i16, + trigon_3.1 as i16, + Color::RGB(255, 255, 255)) + .unwrap(); + + + // Draw player + character.draw(&mut canvas, &cam, Color::RGB(255, 0, 255), None); + + // Draw text + // let s_pos = cam.transform(Pos(50.0, 50.0), window_size); + // canvas.string(s_pos.0 as i16, s_pos.1 as i16, "Hello", Color::RGB(255, 255, 255)); + + // Present the screen and sleep for 1/60th a second + canvas.present(); + ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60)); + } +} |