From c0db69bd7600d21970b07fb063d83e7ba206e59f Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 22 Dec 2023 22:10:38 -0800 Subject: [PATCH] Added basic parallax --- src/doodad.rs | 2 ++ src/main.rs | 29 ++++++++++++++++++++++++++--- src/render/gpustate.rs | 13 +++++++------ src/render/texturearray.rs | 2 +- src/ship.rs | 1 + src/system.rs | 10 +++++++++- 6 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/doodad.rs b/src/doodad.rs index f123aa2..f949c66 100644 --- a/src/doodad.rs +++ b/src/doodad.rs @@ -5,6 +5,7 @@ use crate::{physics::Pfloat, Sprite, Spriteable}; pub struct Doodad { pub sprite: String, pub pos: Point2, + pub parallax: Pfloat, } impl Spriteable for Doodad { @@ -14,6 +15,7 @@ impl Spriteable for Doodad { name: self.sprite.clone(), angle: Deg { 0: 0.0 }, scale: 1.0, + parallax: self.parallax, }; } } diff --git a/src/main.rs b/src/main.rs index 82cdc2f..7b8e5e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use cgmath::{Deg, Point2}; +use cgmath::{Deg, EuclideanSpace, Point2}; use winit::{ event::{ ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, @@ -51,6 +51,22 @@ struct Sprite { // This sprite's rotation // (relative to north, measured ccw) angle: Deg, + + // Parallax factor. + // More positive => farther away + // More negative => closer + // Zero: no parallax. + parallax: Pfloat, +} + +impl Sprite { + const PARALLAX_STRENGTH: Pfloat = 0.1; + + // Returns post-parallax position in game coordinates. + pub fn post_parallax_position(&self, camera: Camera) -> Point2 { + let v = camera.pos.to_vec() - self.pos.to_vec(); + return self.pos + (v * self.parallax * Self::PARALLAX_STRENGTH); + } } struct Game { @@ -95,11 +111,11 @@ impl Game { } if self.input.key_right { - self.player.body.rot(Deg { 0: 15.0 } * t); + self.player.body.rot(Deg { 0: 35.0 } * t); } if self.input.key_left { - self.player.body.rot(Deg { 0: -15.0 } * t); + self.player.body.rot(Deg { 0: -35.0 } * t); } if self.input.v_scroll != 0.0 { @@ -119,6 +135,13 @@ impl Game { sprites.append(&mut self.system.sprites()); sprites.push(self.player.sprite()); + // Make sure sprites are drawn in the correct order + // (note the reversed a, b in the comparator) + // + // TODO: use a gpu depth buffer with parallax as z-coordinate? + // Might be overkill. + sprites.sort_by(|a, b| b.parallax.total_cmp(&a.parallax)); + return sprites; } } diff --git a/src/render/gpustate.rs b/src/render/gpustate.rs index 7bd12ac..c5e3b1a 100644 --- a/src/render/gpustate.rs +++ b/src/render/gpustate.rs @@ -260,13 +260,15 @@ impl GPUState { let mut instances: Vec = Vec::new(); for s in sprites { - let pos = s.pos - camera.pos.to_vec(); + let pos = s.post_parallax_position(camera) - camera.pos.to_vec(); let texture = self.texture_array.get_texture(&s.name[..]); - // Game dimensions of this sprite post-scale - // We really need height / 2 to check if we're on the screen, - // but we omit the division so we get a small "margin" - // and so we can re-use this value. + // Game dimensions of this sprite post-scale. + // + // We only need height / 2 to check if we're on the screen, + // but we omit the division. + // This gives us a small margin, and lets us re-use the value + // without an extra multiply. let height = texture.height * s.scale; let width = height * texture.aspect; @@ -277,7 +279,6 @@ impl GPUState { || pos.x > clip_sw.x + width || pos.y < clip_sw.y - height { - println!("skip {}", s.name); continue; } diff --git a/src/render/texturearray.rs b/src/render/texturearray.rs index 280aa69..a1a935f 100644 --- a/src/render/texturearray.rs +++ b/src/render/texturearray.rs @@ -11,7 +11,7 @@ pub struct TextureArray { texture_indices: HashMap, } -const TEX: &[&str] = &["error", "red", "gypsum", "earth", "a0"]; +const TEX: &[&str] = &["error", "small", "gypsum", "earth", "a0"]; pub struct Texture { pub index: u32, // Index in texture array diff --git a/src/ship.rs b/src/ship.rs index f811eac..3a1bf78 100644 --- a/src/ship.rs +++ b/src/ship.rs @@ -35,6 +35,7 @@ impl Spriteable for Ship { name: self.kind.sprite().to_owned(), angle: self.body.angle, scale: 1.0, + parallax: 0.0, }; } } diff --git a/src/system.rs b/src/system.rs index 477c519..5344a53 100644 --- a/src/system.rs +++ b/src/system.rs @@ -12,6 +12,7 @@ impl System { s.bodies.push(Doodad { pos: (0.0, 0.0).into(), sprite: "a0".to_owned(), + parallax: 3.0, }); s.bodies.push(Doodad { @@ -22,11 +23,18 @@ impl System { } .to_cartesian(), sprite: "earth".to_owned(), + parallax: 1.0, }); s.bodies.push(Doodad { - pos: (1000.0, 1000.0).into(), + pos: Polar { + center: (0.0, 0.0).into(), + radius: 200.0, + angle: Deg { 0: 270.0 }, + } + .to_cartesian(), sprite: "small".to_owned(), + parallax: -1.0, }); return s;