Added basic parallax

master
Mark 2023-12-22 22:10:38 -08:00
parent 6ad23b4410
commit c0db69bd76
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
6 changed files with 46 additions and 11 deletions

View File

@ -5,6 +5,7 @@ use crate::{physics::Pfloat, Sprite, Spriteable};
pub struct Doodad { pub struct Doodad {
pub sprite: String, pub sprite: String,
pub pos: Point2<Pfloat>, pub pos: Point2<Pfloat>,
pub parallax: Pfloat,
} }
impl Spriteable for Doodad { impl Spriteable for Doodad {
@ -14,6 +15,7 @@ impl Spriteable for Doodad {
name: self.sprite.clone(), name: self.sprite.clone(),
angle: Deg { 0: 0.0 }, angle: Deg { 0: 0.0 },
scale: 1.0, scale: 1.0,
parallax: self.parallax,
}; };
} }
} }

View File

@ -1,5 +1,5 @@
use anyhow::Result; use anyhow::Result;
use cgmath::{Deg, Point2}; use cgmath::{Deg, EuclideanSpace, Point2};
use winit::{ use winit::{
event::{ event::{
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase, ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase,
@ -51,6 +51,22 @@ struct Sprite {
// This sprite's rotation // This sprite's rotation
// (relative to north, measured ccw) // (relative to north, measured ccw)
angle: Deg<Pfloat>, angle: Deg<Pfloat>,
// 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<f32> {
let v = camera.pos.to_vec() - self.pos.to_vec();
return self.pos + (v * self.parallax * Self::PARALLAX_STRENGTH);
}
} }
struct Game { struct Game {
@ -95,11 +111,11 @@ impl Game {
} }
if self.input.key_right { 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 { 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 { if self.input.v_scroll != 0.0 {
@ -119,6 +135,13 @@ impl Game {
sprites.append(&mut self.system.sprites()); sprites.append(&mut self.system.sprites());
sprites.push(self.player.sprite()); 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; return sprites;
} }
} }

View File

@ -260,13 +260,15 @@ impl GPUState {
let mut instances: Vec<SpriteInstance> = Vec::new(); let mut instances: Vec<SpriteInstance> = Vec::new();
for s in sprites { 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[..]); let texture = self.texture_array.get_texture(&s.name[..]);
// Game dimensions of this sprite post-scale // 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" // We only need height / 2 to check if we're on the screen,
// and so we can re-use this value. // 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 height = texture.height * s.scale;
let width = height * texture.aspect; let width = height * texture.aspect;
@ -277,7 +279,6 @@ impl GPUState {
|| pos.x > clip_sw.x + width || pos.x > clip_sw.x + width
|| pos.y < clip_sw.y - height || pos.y < clip_sw.y - height
{ {
println!("skip {}", s.name);
continue; continue;
} }

View File

@ -11,7 +11,7 @@ pub struct TextureArray {
texture_indices: HashMap<String, u32>, texture_indices: HashMap<String, u32>,
} }
const TEX: &[&str] = &["error", "red", "gypsum", "earth", "a0"]; const TEX: &[&str] = &["error", "small", "gypsum", "earth", "a0"];
pub struct Texture { pub struct Texture {
pub index: u32, // Index in texture array pub index: u32, // Index in texture array

View File

@ -35,6 +35,7 @@ impl Spriteable for Ship {
name: self.kind.sprite().to_owned(), name: self.kind.sprite().to_owned(),
angle: self.body.angle, angle: self.body.angle,
scale: 1.0, scale: 1.0,
parallax: 0.0,
}; };
} }
} }

View File

@ -12,6 +12,7 @@ impl System {
s.bodies.push(Doodad { s.bodies.push(Doodad {
pos: (0.0, 0.0).into(), pos: (0.0, 0.0).into(),
sprite: "a0".to_owned(), sprite: "a0".to_owned(),
parallax: 3.0,
}); });
s.bodies.push(Doodad { s.bodies.push(Doodad {
@ -22,11 +23,18 @@ impl System {
} }
.to_cartesian(), .to_cartesian(),
sprite: "earth".to_owned(), sprite: "earth".to_owned(),
parallax: 1.0,
}); });
s.bodies.push(Doodad { 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(), sprite: "small".to_owned(),
parallax: -1.0,
}); });
return s; return s;