mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
Add a warning when low on time or blood sugar
This commit is contained in:
parent
57ea1b898d
commit
631b164cf8
@ -2,17 +2,19 @@ use rand::{Rng, SeedableRng};
|
|||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
|
|
||||||
use geom::{Distance, Duration, PolyLine, Pt2D, Time};
|
use geom::{Distance, Duration, PolyLine, Pt2D, Time};
|
||||||
use widgetry::{Color, Drawable, EventCtx, GeomBatch, GfxCtx};
|
use widgetry::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, RewriteColor};
|
||||||
|
|
||||||
pub struct Animator {
|
pub struct Animator {
|
||||||
active: Vec<Animation>,
|
active: Vec<Animation>,
|
||||||
draw_current: Drawable,
|
draw_mapspace: Drawable,
|
||||||
|
draw_screenspace: Option<Drawable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Animation {
|
struct Animation {
|
||||||
start: Time,
|
start: Time,
|
||||||
end: Time,
|
end: Time,
|
||||||
effect: Effect,
|
effect: Effect,
|
||||||
|
screenspace: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Effect {
|
pub enum Effect {
|
||||||
@ -26,13 +28,19 @@ pub enum Effect {
|
|||||||
width: Distance,
|
width: Distance,
|
||||||
pl: PolyLine,
|
pl: PolyLine,
|
||||||
},
|
},
|
||||||
|
Flash {
|
||||||
|
orig: GeomBatch,
|
||||||
|
alpha_scale: (f32, f32),
|
||||||
|
cycles: usize,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Animator {
|
impl Animator {
|
||||||
pub fn new(ctx: &EventCtx) -> Animator {
|
pub fn new(ctx: &EventCtx) -> Animator {
|
||||||
Animator {
|
Animator {
|
||||||
active: Vec::new(),
|
active: Vec::new(),
|
||||||
draw_current: Drawable::empty(ctx),
|
draw_mapspace: Drawable::empty(ctx),
|
||||||
|
draw_screenspace: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +50,16 @@ impl Animator {
|
|||||||
start: now,
|
start: now,
|
||||||
end: now + duration,
|
end: now + duration,
|
||||||
effect,
|
effect,
|
||||||
|
screenspace: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_screenspace(&mut self, now: Time, duration: Duration, effect: Effect) {
|
||||||
|
self.active.push(Animation {
|
||||||
|
start: now,
|
||||||
|
end: now + duration,
|
||||||
|
effect,
|
||||||
|
screenspace: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +67,8 @@ impl Animator {
|
|||||||
if self.active.is_empty() {
|
if self.active.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut batch = GeomBatch::new();
|
let mut mapspace = GeomBatch::new();
|
||||||
|
let mut screenspace = GeomBatch::new();
|
||||||
self.active.retain(|anim| {
|
self.active.retain(|anim| {
|
||||||
let pct = (now - anim.start) / (anim.end - anim.start);
|
let pct = (now - anim.start) / (anim.end - anim.start);
|
||||||
if pct < 0.0 {
|
if pct < 0.0 {
|
||||||
@ -58,15 +77,29 @@ impl Animator {
|
|||||||
} else if pct > 1.0 {
|
} else if pct > 1.0 {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
anim.effect.render(pct, &mut batch);
|
if anim.screenspace {
|
||||||
|
anim.effect.render(pct, &mut screenspace);
|
||||||
|
} else {
|
||||||
|
anim.effect.render(pct, &mut mapspace);
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.draw_current = ctx.upload(batch);
|
self.draw_mapspace = ctx.upload(mapspace);
|
||||||
|
if screenspace.is_empty() {
|
||||||
|
self.draw_screenspace = None;
|
||||||
|
} else {
|
||||||
|
self.draw_screenspace = Some(ctx.upload(screenspace));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, g: &mut GfxCtx) {
|
pub fn draw(&self, g: &mut GfxCtx) {
|
||||||
g.redraw(&self.draw_current);
|
g.redraw(&self.draw_mapspace);
|
||||||
|
if let Some(ref d) = self.draw_screenspace {
|
||||||
|
g.fork_screenspace();
|
||||||
|
g.redraw(d);
|
||||||
|
g.unfork();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_done(&self) -> bool {
|
pub fn is_done(&self) -> bool {
|
||||||
@ -94,6 +127,19 @@ impl Effect {
|
|||||||
batch.push(*color, pl.make_polygons(*width));
|
batch.push(*color, pl.make_polygons(*width));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Effect::Flash {
|
||||||
|
ref orig,
|
||||||
|
alpha_scale,
|
||||||
|
cycles,
|
||||||
|
} => {
|
||||||
|
// -1 to 1
|
||||||
|
let shift = (pct * (*cycles as f64) * (2.0 * std::f64::consts::PI)).sin() as f32;
|
||||||
|
let midpt = (alpha_scale.0 + alpha_scale.1) / 2.0;
|
||||||
|
let half_range = (alpha_scale.1 - alpha_scale.0) / 2.0;
|
||||||
|
let alpha = midpt + shift * half_range;
|
||||||
|
|
||||||
|
batch.append(orig.clone().color(RewriteColor::ChangeAlpha(alpha)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,6 +255,7 @@ impl Game {
|
|||||||
let refill = self.state.vehicle.max_energy - self.state.energy;
|
let refill = self.state.vehicle.max_energy - self.state.energy;
|
||||||
if refill > 0 {
|
if refill > 0 {
|
||||||
self.state.energy += refill;
|
self.state.energy += refill;
|
||||||
|
self.state.warned_low_energy = false;
|
||||||
let path_speed = Duration::seconds(0.2);
|
let path_speed = Duration::seconds(0.2);
|
||||||
self.animator.add(
|
self.animator.add(
|
||||||
app.time,
|
app.time,
|
||||||
@ -387,6 +388,69 @@ impl State<App> for Game {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.state.warned_low_time
|
||||||
|
&& self.state.level.time_limit - (app.time - Time::START_OF_DAY)
|
||||||
|
<= Duration::seconds(20.0)
|
||||||
|
{
|
||||||
|
self.state.warned_low_time = true;
|
||||||
|
self.animator.add(
|
||||||
|
app.time,
|
||||||
|
Duration::seconds(2.0),
|
||||||
|
Effect::Flash {
|
||||||
|
alpha_scale: (0.1, 0.5),
|
||||||
|
cycles: 2,
|
||||||
|
orig: GeomBatch::from(vec![(
|
||||||
|
Color::RED,
|
||||||
|
app.map.get_boundary_polygon().clone(),
|
||||||
|
)]),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.animator.add_screenspace(
|
||||||
|
app.time,
|
||||||
|
Duration::seconds(2.0),
|
||||||
|
Effect::Scale {
|
||||||
|
lerp_scale: (1.0, 4.0),
|
||||||
|
center: {
|
||||||
|
let pt = ctx.canvas.center_to_screen_pt();
|
||||||
|
Pt2D::new(pt.x, pt.y / 2.0)
|
||||||
|
},
|
||||||
|
orig: Text::from(Line("Almost out of time!"))
|
||||||
|
.bg(Color::RED)
|
||||||
|
.render_autocropped(ctx),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.state.warned_low_energy && self.state.energy < 30 {
|
||||||
|
self.state.warned_low_energy = true;
|
||||||
|
self.animator.add(
|
||||||
|
app.time,
|
||||||
|
Duration::seconds(2.0),
|
||||||
|
Effect::Flash {
|
||||||
|
alpha_scale: (0.1, 0.5),
|
||||||
|
cycles: 2,
|
||||||
|
orig: GeomBatch::from(vec![(
|
||||||
|
Color::RED,
|
||||||
|
app.map.get_boundary_polygon().clone(),
|
||||||
|
)]),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.animator.add_screenspace(
|
||||||
|
app.time,
|
||||||
|
Duration::seconds(2.0),
|
||||||
|
Effect::Scale {
|
||||||
|
lerp_scale: (1.0, 4.0),
|
||||||
|
center: {
|
||||||
|
let pt = ctx.canvas.center_to_screen_pt();
|
||||||
|
Pt2D::new(pt.x, pt.y / 2.0)
|
||||||
|
},
|
||||||
|
orig: Text::from(Line("Low on blood sugar, refill soon!"))
|
||||||
|
.bg(Color::RED)
|
||||||
|
.render_autocropped(ctx),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ctx.request_update(UpdateType::Game);
|
ctx.request_update(UpdateType::Game);
|
||||||
return Transition::Keep;
|
return Transition::Keep;
|
||||||
}
|
}
|
||||||
@ -504,6 +568,8 @@ struct GameState {
|
|||||||
idle_time: Duration,
|
idle_time: Duration,
|
||||||
|
|
||||||
game_over: bool,
|
game_over: bool,
|
||||||
|
warned_low_time: bool,
|
||||||
|
warned_low_energy: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameState {
|
impl GameState {
|
||||||
@ -524,6 +590,8 @@ impl GameState {
|
|||||||
idle_time: Duration::ZERO,
|
idle_time: Duration::ZERO,
|
||||||
|
|
||||||
game_over: false,
|
game_over: false,
|
||||||
|
warned_low_time: false,
|
||||||
|
warned_low_energy: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ impl Vehicle {
|
|||||||
name: "bike".to_string(),
|
name: "bike".to_string(),
|
||||||
|
|
||||||
speed: Speed::miles_per_hour(30.0),
|
speed: Speed::miles_per_hour(30.0),
|
||||||
max_energy: 100,
|
max_energy: 50,
|
||||||
|
|
||||||
draw_frames: vec!["bike1.svg", "bike2.svg", "bike1.svg", "bike3.svg"],
|
draw_frames: vec!["bike1.svg", "bike2.svg", "bike1.svg", "bike3.svg"],
|
||||||
scale: 0.05,
|
scale: 0.05,
|
||||||
|
@ -123,7 +123,7 @@ impl GeomBatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// True when the batch is empty.
|
/// True when the batch is empty.
|
||||||
pub(crate) fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.list.is_empty()
|
self.list.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user