mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-24 23:15:24 +03:00
Improve the out-of-energy arrow:
- point to the driveway, not the building center - scale arrow length so it doesn't overshoot where we're supposed to go - explicitly say to go refill from a store
This commit is contained in:
parent
2abf87c1a8
commit
4d057cb74f
@ -97,6 +97,8 @@ impl Strategize {
|
||||
ColorLegend::row(ctx, app.session.colors.house, "house"),
|
||||
ColorLegend::row(ctx, app.session.colors.apartment, "apartment"),
|
||||
ColorLegend::row(ctx, app.session.colors.store, "store"),
|
||||
]),
|
||||
Widget::row(vec![
|
||||
ColorLegend::row(ctx, Color::PINK, "upzoned store"),
|
||||
ColorLegend::row(ctx, Color::RED, "delivered!"),
|
||||
])
|
||||
|
@ -14,7 +14,7 @@ use crate::animation::{Animator, Effect, SnowEffect};
|
||||
use crate::buildings::{BldgState, Buildings};
|
||||
use crate::levels::Level;
|
||||
use crate::meters::{custom_bar, make_bar};
|
||||
use crate::movement::Player;
|
||||
use crate::player::Player;
|
||||
use crate::vehicles::Vehicle;
|
||||
use crate::{App, Transition};
|
||||
|
||||
@ -63,7 +63,7 @@ impl Game {
|
||||
let status_panel = Panel::new(Widget::col(vec![
|
||||
"Complete Deliveries".draw_text(ctx).named("score label"),
|
||||
Widget::draw_batch(ctx, GeomBatch::new()).named("score"),
|
||||
"Remaining Gifts".draw_text(ctx),
|
||||
"Remaining Gifts".draw_text(ctx).named("energy label"),
|
||||
Widget::draw_batch(ctx, GeomBatch::new()).named("energy"),
|
||||
]))
|
||||
.aligned(HorizontalAlignment::RightInset, VerticalAlignment::TopInset)
|
||||
@ -296,18 +296,27 @@ impl Game {
|
||||
self.animator.event(ctx, app.time);
|
||||
self.snow.event(ctx, app.time);
|
||||
if self.state.has_energy() {
|
||||
self.state.energyless_arrow = None;
|
||||
if self.state.energyless_arrow.is_some() {
|
||||
self.state.energyless_arrow = None;
|
||||
let label = "Remaining Gifts".draw_text(ctx);
|
||||
self.status_panel.replace(ctx, "energy label", label);
|
||||
}
|
||||
} else {
|
||||
if self.state.energyless_arrow.is_none() {
|
||||
self.state.energyless_arrow = Some(EnergylessArrow::new(ctx, app.time));
|
||||
self.state.energyless_arrow = Some(EnergylessArrow::new(
|
||||
ctx,
|
||||
app.time,
|
||||
self.state.bldgs.all_stores(),
|
||||
));
|
||||
let label = Text::from(Line("Out of gifts - refill from a store!").fg(Color::RED))
|
||||
.draw(ctx);
|
||||
self.status_panel.replace(ctx, "energy label", label);
|
||||
}
|
||||
let stores = self.state.bldgs.all_stores();
|
||||
self.state.energyless_arrow.as_mut().unwrap().update(
|
||||
ctx,
|
||||
app,
|
||||
self.player.get_pos(),
|
||||
stores,
|
||||
);
|
||||
self.state
|
||||
.energyless_arrow
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.update(ctx, app, self.player.get_pos());
|
||||
}
|
||||
|
||||
if self.state.boost != orig_boost {
|
||||
@ -534,28 +543,33 @@ struct EnergylessArrow {
|
||||
draw: Drawable,
|
||||
started: Time,
|
||||
last_update: Time,
|
||||
all_stores: Vec<BuildingID>,
|
||||
}
|
||||
|
||||
impl EnergylessArrow {
|
||||
fn new(ctx: &EventCtx, started: Time) -> EnergylessArrow {
|
||||
fn new(ctx: &EventCtx, started: Time, all_stores: Vec<BuildingID>) -> EnergylessArrow {
|
||||
EnergylessArrow {
|
||||
draw: Drawable::empty(ctx),
|
||||
started,
|
||||
last_update: Time::START_OF_DAY,
|
||||
all_stores,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &mut EventCtx, app: &App, sleigh: Pt2D, all_stores: Vec<BuildingID>) {
|
||||
fn update(&mut self, ctx: &mut EventCtx, app: &App, sleigh: Pt2D) {
|
||||
if self.last_update == app.time {
|
||||
return;
|
||||
}
|
||||
self.last_update = app.time;
|
||||
// Find the closest store as the crow -- or Santa -- flies
|
||||
// Find the closest store as the crow -- or Santa -- flies. Point to the end of the
|
||||
// driveway, since sometimes it's hard to quickly spot which road a building is connected
|
||||
// to.
|
||||
// TODO Or pathfind and show them that?
|
||||
let store = app.map.get_b(
|
||||
all_stores
|
||||
.into_iter()
|
||||
.min_by_key(|b| app.map.get_b(*b).label_center.fast_dist(sleigh))
|
||||
*self
|
||||
.all_stores
|
||||
.iter()
|
||||
.min_by_key(|b| app.map.get_b(**b).driveway_geom.last_pt().fast_dist(sleigh))
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
@ -566,13 +580,22 @@ impl EnergylessArrow {
|
||||
let shift = (pct * std::f64::consts::PI).sin();
|
||||
let thickness = Distance::meters(5.0 + shift);
|
||||
|
||||
let angle = sleigh.angle_to(store.label_center);
|
||||
let arrow = PolyLine::must_new(vec![
|
||||
let goto = store.driveway_geom.last_pt();
|
||||
let angle = sleigh.angle_to(goto);
|
||||
// TODO When we're too close, we get an awkward arrowcap; the intention was for it to
|
||||
// disappear...
|
||||
if let Some(arrow) = PolyLine::new(vec![
|
||||
sleigh.project_away(Distance::meters(20.0), angle),
|
||||
sleigh.project_away(Distance::meters(40.0), angle),
|
||||
goto,
|
||||
])
|
||||
.make_arrow(thickness, ArrowCap::Triangle);
|
||||
self.draw = ctx.upload(GeomBatch::from(vec![(Color::RED.alpha(0.8), arrow)]));
|
||||
.and_then(|pl| {
|
||||
pl.maybe_exact_slice(Distance::ZERO, Distance::meters(20.0).min(pl.length()))
|
||||
})
|
||||
.ok()
|
||||
.and_then(|slice| slice.maybe_make_arrow(thickness, ArrowCap::Triangle))
|
||||
{
|
||||
self.draw = ctx.upload(GeomBatch::from(vec![(Color::RED.alpha(0.8), arrow)]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ impl Level {
|
||||
map: MapName::seattle("montlake"),
|
||||
start: osm::NodeID(53084814),
|
||||
minimap_zoom: 1,
|
||||
time_limit: Duration::seconds(5.0),
|
||||
time_limit: Duration::seconds(50.0),
|
||||
goal: 20,
|
||||
|
||||
unlock_upzones: 2,
|
||||
|
@ -9,8 +9,8 @@ mod controls;
|
||||
mod game;
|
||||
mod levels;
|
||||
mod meters;
|
||||
mod movement;
|
||||
mod music;
|
||||
mod player;
|
||||
mod session;
|
||||
mod title;
|
||||
mod vehicles;
|
||||
|
@ -22,7 +22,7 @@ impl Vehicle {
|
||||
|
||||
normal_speed: Speed::miles_per_hour(30.0),
|
||||
tired_speed: Speed::miles_per_hour(10.0),
|
||||
max_energy: 80,
|
||||
max_energy: 20,
|
||||
max_boost: Duration::seconds(5.0),
|
||||
|
||||
draw_frames: vec!["sleigh.svg"],
|
||||
|
@ -519,13 +519,13 @@ impl PolyLine {
|
||||
.exact_dashed_polygons(width, dash_len, dash_separation)
|
||||
}
|
||||
|
||||
pub fn make_arrow(&self, thickness: Distance, cap: ArrowCap) -> Polygon {
|
||||
/// Fail if the length is too short.
|
||||
pub fn maybe_make_arrow(&self, thickness: Distance, cap: ArrowCap) -> Option<Polygon> {
|
||||
let head_size = thickness * 2.0;
|
||||
let triangle_height = head_size / 2.0_f64.sqrt();
|
||||
|
||||
if self.length() < triangle_height + EPSILON_DIST {
|
||||
// Just give up and make the thick line.
|
||||
return self.make_polygons(thickness);
|
||||
return None;
|
||||
}
|
||||
let slice = self.exact_slice(Distance::ZERO, self.length() - triangle_height);
|
||||
|
||||
@ -550,7 +550,17 @@ impl PolyLine {
|
||||
pts.extend(side2);
|
||||
pts.push(pts[0]);
|
||||
pts.dedup();
|
||||
Ring::must_new(pts).to_polygon()
|
||||
Some(Ring::must_new(pts).to_polygon())
|
||||
}
|
||||
|
||||
/// If the length is too short, just give up and make the thick line
|
||||
pub fn make_arrow(&self, thickness: Distance, cap: ArrowCap) -> Polygon {
|
||||
if let Some(p) = self.maybe_make_arrow(thickness, cap) {
|
||||
p
|
||||
} else {
|
||||
// Just give up and make the thick line.
|
||||
self.make_polygons(thickness)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_double_arrow(&self, thickness: Distance, cap: ArrowCap) -> Polygon {
|
||||
|
Loading…
Reference in New Issue
Block a user