Added radar frame

master
Mark 2024-01-01 22:25:16 -08:00
parent aa2a1943b2
commit a85a0f8188
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
9 changed files with 158 additions and 25 deletions

10
TODO.md
View File

@ -1,3 +1,13 @@
## Specific Jobs
- UI: health, shield, fuel, heat, energy bars
- UI: text arranger
- Sound system
- Particles, impact effects
- Debris on ship death
- Radar: dynamic colors, size, planets and suns
----------------------------------
## Game & Story ## Game & Story
- Landmarks to determine speed? - Landmarks to determine speed?
- How to keep player in system bounds, what to do if they fly far away - How to keep player in system bounds, what to do if they fly far away

2
assets

@ -1 +1 @@
Subproject commit 8205d79e8aa9d7e4976fe8a7794e83819ec19688 Subproject commit 91377416617d049acec68bb5a17647dcac7acd0e

View File

@ -24,3 +24,6 @@ path = "ui/radar.png"
[texture."ui::blip"] [texture."ui::blip"]
path = "ui/blip.png" path = "ui/blip.png"
[texture."ui::radarframe"]
path = "ui/radarframe.png"

View File

@ -356,28 +356,46 @@ impl GPUState {
let width = s.dimensions.x; let width = s.dimensions.x;
let height = s.dimensions.y; let height = s.dimensions.y;
// Compute square scale, since we must apply screen aspect ratio
// AFTER rotation.
let scale = Matrix4::from_nonuniform_scale( let scale = Matrix4::from_nonuniform_scale(
width / logical_size.width, width / logical_size.height,
height / logical_size.height, height / logical_size.height,
1.0, 1.0,
); );
let rotate = Matrix4::from_angle_z(s.angle); let rotate = Matrix4::from_angle_z(s.angle);
let translate = Matrix4::from_translation(match s.pos { let translate = Matrix4::from_translation(match s.pos {
super::AnchoredUiPosition::NorthWest(p) => Vector3 { super::AnchoredUiPosition::NwC(p) => Vector3 {
// Note the signs. Positive y points north! // Note the signs. Positive y points north!
x: -1.0 + p.x / (logical_size.width / 2.0),
y: 1.0 + p.y / (logical_size.height / 2.0),
z: 0.0,
},
super::AnchoredUiPosition::NwNw(p) => Vector3 {
x: -1.0 + (width / 2.0 + p.x) / (logical_size.width / 2.0), x: -1.0 + (width / 2.0 + p.x) / (logical_size.width / 2.0),
y: 1.0 - (height / 2.0 - p.y) / (logical_size.height / 2.0), y: 1.0 - (height / 2.0 - p.y) / (logical_size.height / 2.0),
z: 0.0, z: 0.0,
}, },
_ => Vector3 { super::AnchoredUiPosition::NwNe(p) => Vector3 {
x: 0.0, x: -1.0 - (width / 2.0 - p.x) / (logical_size.width / 2.0),
y: 0.0, y: 1.0 - (height / 2.0 - p.y) / (logical_size.height / 2.0),
z: 0.0,
},
super::AnchoredUiPosition::NwSw(p) => Vector3 {
x: -1.0 + (width / 2.0 + p.x) / (logical_size.width / 2.0),
y: 1.0 + (height / 2.0 + p.y) / (logical_size.height / 2.0),
z: 0.0,
},
super::AnchoredUiPosition::NwSe(p) => Vector3 {
x: -1.0 - (width / 2.0 - p.x) / (logical_size.width / 2.0),
y: 1.0 + (height / 2.0 + p.y) / (logical_size.height / 2.0),
z: 0.0, z: 0.0,
}, },
}); });
let screen_aspect = Matrix4::from_nonuniform_scale(1.0 / self.window_aspect, 1.0, 1.0);
instances.push(SpriteInstance { instances.push(SpriteInstance {
transform: (OPENGL_TO_WGPU_MATRIX * translate * rotate * scale).into(), transform: (OPENGL_TO_WGPU_MATRIX * translate * screen_aspect * rotate * scale).into(),
texture_index: texture.index, texture_index: texture.index,
}); });
} }

View File

@ -8,13 +8,25 @@ use cgmath::{Deg, Point2, Point3};
/// positive X always points right. /// positive X always points right.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum AnchoredUiPosition { pub enum AnchoredUiPosition {
/// Position of this sprite's center,
/// relative to the nw corner of the window.
NwC(Point2<f32>),
/// Position of this sprite's nw corner, /// Position of this sprite's nw corner,
/// relative to the nw corner of the window. /// relative to the nw corner of the window.
NorthWest(Point2<f32>), NwNw(Point2<f32>),
/// Position of this sprite's ne corner,
/// relative to the nw corner of the window.
NwNe(Point2<f32>),
/// Position of this sprite's sw corner, /// Position of this sprite's sw corner,
/// relative to the sw corner of the window. /// relative to the nw corner of the window.
SouthWest(Point2<f32>), NwSw(Point2<f32>),
/// Position of this sprite's se corner,
/// relative to the nw corner of the window.
NwSe(Point2<f32>),
} }
/// A sprite that represents a ui element /// A sprite that represents a ui element

View File

@ -1,12 +1,15 @@
use cgmath::{Deg, InnerSpace, Point2}; use cgmath::{Deg, InnerSpace, Point2, Vector2};
use galactica_content as content; use galactica_content as content;
use galactica_render::{AnchoredUiPosition, UiSprite}; use galactica_render::{AnchoredUiPosition, UiSprite};
use galactica_world::{util, ShipPhysicsHandle, World}; use galactica_world::{util, ShipPhysicsHandle, World};
// TODO: camera as one unit
pub fn build_radar( pub fn build_radar(
ct: &content::Content,
player: &ShipPhysicsHandle, player: &ShipPhysicsHandle,
physics: &World, physics: &World,
ct: &content::Content, camera_zoom: f32,
camera_aspect: f32,
) -> Vec<UiSprite> { ) -> Vec<UiSprite> {
let mut out = Vec::new(); let mut out = Vec::new();
@ -15,7 +18,7 @@ pub fn build_radar(
out.push(UiSprite { out.push(UiSprite {
texture: ct.get_texture_handle("ui::radar"), texture: ct.get_texture_handle("ui::radar"),
pos: AnchoredUiPosition::NorthWest(Point2 { x: 10.0, y: -10.0 }), pos: AnchoredUiPosition::NwNw(Point2 { x: 10.0, y: -10.0 }),
dimensions: Point2 { dimensions: Point2 {
x: radar_size, x: radar_size,
y: radar_size, y: radar_size,
@ -23,26 +26,98 @@ pub fn build_radar(
angle: Deg(0.0), angle: Deg(0.0),
}); });
// Draw viewport frame
let d = Vector2 {
x: (camera_zoom / 2.0) * camera_aspect,
y: camera_zoom / 2.0,
};
let m = d.magnitude() / radar_range;
let d = d / radar_range * (radar_size / 2.0);
println!("{:?}", d);
if m < 0.8 {
let texture = ct.get_texture_handle("ui::radarframe");
let dimensions = Point2 {
x: texture.aspect,
y: 1.0,
} * 7.0f32.min((0.8 - m) * 70.0);
out.push(UiSprite {
texture,
pos: AnchoredUiPosition::NwNw(Point2 {
x: (radar_size / 2.0 + 10.0) - d.x,
y: (radar_size / -2.0 - 10.0) + d.y,
}),
dimensions,
angle: Deg(0.0),
});
out.push(UiSprite {
texture,
pos: AnchoredUiPosition::NwSw(Point2 {
x: (radar_size / 2.0 + 10.0) - d.x,
y: (radar_size / -2.0 - 10.0) - d.y,
}),
dimensions,
angle: Deg(90.0),
});
out.push(UiSprite {
texture,
pos: AnchoredUiPosition::NwSe(Point2 {
x: (radar_size / 2.0 + 10.0) + d.x,
y: (radar_size / -2.0 - 10.0) - d.y,
}),
dimensions,
angle: Deg(180.0),
});
out.push(UiSprite {
texture,
pos: AnchoredUiPosition::NwNe(Point2 {
x: (radar_size / 2.0 + 10.0) + d.x,
y: (radar_size / -2.0 - 10.0) + d.y,
}),
dimensions,
angle: Deg(270.0),
});
}
let (_, pr) = physics.get_ship_body(player).unwrap(); let (_, pr) = physics.get_ship_body(player).unwrap();
let pr = util::rigidbody_position(pr); let pr = util::rigidbody_position(pr);
let texture = ct.get_texture_handle("ui::blip");
for (s, r) in physics.iter_ship_body() { for (s, r) in physics.iter_ship_body() {
if s.physics_handle == *player { let p = util::rigidbody_position(r);
continue; let d = p - pr;
}
let r = util::rigidbody_position(r);
let d = r - pr;
let m = d.magnitude() / radar_range; let m = d.magnitude() / radar_range;
if m < 0.8 { let angle: Deg<f32> = util::rigidbody_rotation(r)
.angle(Vector2 { x: 0.0, y: 1.0 })
.into();
if s.physics_handle == *player {
out.push(UiSprite { out.push(UiSprite {
texture: ct.get_texture_handle("ui::blip"), texture,
pos: AnchoredUiPosition::NorthWest( pos: AnchoredUiPosition::NwC(Point2 {
x: radar_size / 2.0 + 10.0,
y: radar_size / -2.0 - 10.0,
}),
dimensions: Point2 {
x: texture.aspect,
y: 1.0,
} * 5.0f32.min((0.8 - m) * 50.0),
angle: -angle,
});
} else if m < 0.8 {
out.push(UiSprite {
texture,
pos: AnchoredUiPosition::NwC(
Point2 { Point2 {
x: radar_size / 2.0 + 10.0, x: radar_size / 2.0 + 10.0,
y: radar_size / -2.0 - 10.0, y: radar_size / -2.0 - 10.0,
} + (d / radar_range * 150.0), } + (d / radar_range * (radar_size / 2.0)),
), ),
dimensions: Point2 { x: 1.0, y: 1.0 } * 5.0f32.min((0.8 - m) * 50.0), dimensions: Point2 {
angle: Deg(0.0), x: texture.aspect,
y: 1.0,
} * 5.0f32.min((0.8 - m) * 50.0),
angle: -angle,
}); });
} }
} }

View File

@ -8,4 +8,7 @@ pub struct Camera {
/// Camera zoom /// Camera zoom
/// (How many game units tall is the viewport?) /// (How many game units tall is the viewport?)
pub zoom: f32, pub zoom: f32,
/// Aspect ratio of viewport (width / height)
pub aspect: f32,
} }

View File

@ -86,6 +86,7 @@ impl Game {
camera: Camera { camera: Camera {
pos: (0.0, 0.0).into(), pos: (0.0, 0.0).into(),
zoom: 500.0, zoom: 500.0,
aspect: 1.0,
}, },
system: object::System::new(&ct, SystemHandle { index: 0 }), system: object::System::new(&ct, SystemHandle { index: 0 }),
@ -179,6 +180,12 @@ impl Game {
} }
pub fn get_ui_sprites(&self) -> Vec<UiSprite> { pub fn get_ui_sprites(&self) -> Vec<UiSprite> {
return ui::build_radar(&self.player, &self.physics, &self.content); return ui::build_radar(
&self.content,
&self.player,
&self.physics,
self.camera.zoom,
self.camera.aspect,
);
} }
} }

View File

@ -27,6 +27,7 @@ fn main() -> Result<()> {
let mut game = game::Game::new(content); let mut game = game::Game::new(content);
gpu.update_starfield_buffer(); gpu.update_starfield_buffer();
game.camera.aspect = gpu.window_size.width as f32 / gpu.window_size.height as f32;
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
match event { match event {
@ -75,9 +76,13 @@ fn main() -> Result<()> {
} }
WindowEvent::Resized(_) => { WindowEvent::Resized(_) => {
gpu.resize(); gpu.resize();
game.camera.aspect =
gpu.window_size.width as f32 / gpu.window_size.height as f32;
} }
WindowEvent::ScaleFactorChanged { .. } => { WindowEvent::ScaleFactorChanged { .. } => {
gpu.resize(); gpu.resize();
game.camera.aspect =
gpu.window_size.width as f32 / gpu.window_size.height as f32;
} }
_ => {} _ => {}
}, },