195 lines
4.8 KiB
Rust
195 lines
4.8 KiB
Rust
use cgmath::{Deg, InnerSpace, Point2, Vector2};
|
|
use galactica_content as content;
|
|
use galactica_gameobject as object;
|
|
use galactica_render::{AnchoredUiPosition, UiSprite};
|
|
use galactica_world::{util, ShipPhysicsHandle, World};
|
|
|
|
// TODO: args as one unit
|
|
pub fn build_radar(
|
|
ct: &content::Content,
|
|
player: ShipPhysicsHandle,
|
|
physics: &World,
|
|
system: &object::System,
|
|
camera_zoom: f32,
|
|
camera_aspect: f32,
|
|
) -> Vec<UiSprite> {
|
|
let mut out = Vec::new();
|
|
|
|
let radar_range = 4000.0;
|
|
let radar_size = 300.0;
|
|
let hide_range = 0.85;
|
|
let shrink_distance = 20.0;
|
|
let system_object_scale = 1.0 / 600.0;
|
|
let ship_scale = 1.0 / 15.0;
|
|
|
|
let (_, player_body) = physics.get_ship_body(player).unwrap();
|
|
let player_position = util::rigidbody_position(player_body);
|
|
let planet_sprite = ct.get_sprite_handle("ui::planetblip");
|
|
let ship_sprite = ct.get_sprite_handle("ui::shipblip");
|
|
let arrow_sprite = ct.get_sprite_handle("ui::centerarrow");
|
|
|
|
out.push(UiSprite {
|
|
sprite: ct.get_sprite_handle("ui::radar"),
|
|
pos: AnchoredUiPosition::NwNw(Point2 { x: 10.0, y: -10.0 }),
|
|
dimensions: Point2 {
|
|
x: radar_size,
|
|
y: radar_size,
|
|
},
|
|
angle: Deg(0.0),
|
|
color: None,
|
|
});
|
|
|
|
// Draw system objects
|
|
for o in &system.bodies {
|
|
let size = (o.size / o.pos.z) / (radar_range * system_object_scale);
|
|
let p = Point2 {
|
|
x: o.pos.x,
|
|
y: o.pos.y,
|
|
};
|
|
let d = (p - player_position) / radar_range;
|
|
// Add half the blip sprite's height to distance
|
|
let m = d.magnitude() + (size / (2.0 * radar_size));
|
|
if m < hide_range {
|
|
// Shrink blips as they get closeto the edge
|
|
let size = size.min((hide_range - m) * size * shrink_distance);
|
|
if size <= 2.0 {
|
|
// Don't draw super tiny sprites, they flicker
|
|
continue;
|
|
}
|
|
out.push(UiSprite {
|
|
sprite: planet_sprite,
|
|
pos: AnchoredUiPosition::NwC(
|
|
Point2 {
|
|
x: radar_size / 2.0 + 10.0,
|
|
y: radar_size / -2.0 - 10.0,
|
|
} + (d * (radar_size / 2.0)),
|
|
),
|
|
dimensions: Point2 {
|
|
x: planet_sprite.aspect,
|
|
y: 1.0,
|
|
} * size,
|
|
angle: o.angle,
|
|
color: Some([0.5, 0.5, 0.5, 1.0]),
|
|
});
|
|
}
|
|
}
|
|
|
|
// Draw ships
|
|
for (s, r) in physics.iter_ship_body() {
|
|
let ship = ct.get_ship(s.ship.handle);
|
|
let size = (ship.size * ship.sprite.aspect) * ship_scale;
|
|
let p = util::rigidbody_position(r);
|
|
let d = (p - player_position) / radar_range;
|
|
let m = d.magnitude() + (size / (2.0 * radar_size));
|
|
if m < hide_range {
|
|
let size = size.min((hide_range - m) * size * shrink_distance);
|
|
if size < 2.0 {
|
|
continue;
|
|
}
|
|
let angle: Deg<f32> = util::rigidbody_rotation(r)
|
|
.angle(Vector2 { x: 0.0, y: 1.0 })
|
|
.into();
|
|
let f = ct.get_faction(s.ship.faction).color;
|
|
let f = [f[0], f[1], f[2], 1.0];
|
|
out.push(UiSprite {
|
|
sprite: ship_sprite,
|
|
pos: AnchoredUiPosition::NwC(
|
|
Point2 {
|
|
x: radar_size / 2.0 + 10.0,
|
|
y: radar_size / -2.0 - 10.0,
|
|
} + (d * (radar_size / 2.0)),
|
|
),
|
|
dimensions: Point2 {
|
|
x: ship_sprite.aspect,
|
|
y: 1.0,
|
|
} * size,
|
|
angle: -angle,
|
|
color: Some(f),
|
|
});
|
|
}
|
|
}
|
|
|
|
// Draw viewport frame
|
|
let d = Vector2 {
|
|
x: (camera_zoom / 2.0) * camera_aspect,
|
|
y: camera_zoom / 2.0,
|
|
} / radar_range;
|
|
let m = d.magnitude();
|
|
let d = d * (radar_size / 2.0);
|
|
let color = Some([0.3, 0.3, 0.3, 1.0]);
|
|
if m < 0.8 {
|
|
let sprite = ct.get_sprite_handle("ui::radarframe");
|
|
let dimensions = Point2 {
|
|
x: sprite.aspect,
|
|
y: 1.0,
|
|
} * 7.0f32.min((0.8 - m) * 70.0);
|
|
out.push(UiSprite {
|
|
sprite,
|
|
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),
|
|
color,
|
|
});
|
|
|
|
out.push(UiSprite {
|
|
sprite,
|
|
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),
|
|
color,
|
|
});
|
|
|
|
out.push(UiSprite {
|
|
sprite,
|
|
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),
|
|
color,
|
|
});
|
|
|
|
out.push(UiSprite {
|
|
sprite,
|
|
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),
|
|
color,
|
|
});
|
|
}
|
|
|
|
// Arrow to center of system
|
|
let q = Point2 { x: 0.0, y: 0.0 } - player_position;
|
|
let m = q.magnitude();
|
|
if m > 200.0 {
|
|
let player_angle: Deg<f32> = q.angle(Vector2 { x: 0.0, y: 1.0 }).into();
|
|
out.push(UiSprite {
|
|
sprite: arrow_sprite,
|
|
pos: AnchoredUiPosition::NwC(
|
|
Point2 {
|
|
x: radar_size / 2.0 + 10.0,
|
|
y: radar_size / -2.0 - 10.0,
|
|
} + ((q.normalize() * 0.865) * (radar_size / 2.0)),
|
|
),
|
|
dimensions: Point2 {
|
|
x: arrow_sprite.aspect,
|
|
y: 1.0,
|
|
} * 10.0,
|
|
angle: -player_angle,
|
|
color: Some([1.0, 1.0, 1.0, 1f32.min((m - 200.0) / 400.0)]),
|
|
});
|
|
}
|
|
|
|
return out;
|
|
}
|