mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 03:35:51 +03:00
Experiment with animation
This commit is contained in:
parent
4b28cfe806
commit
fad0358553
72
experiment/src/animation.rs
Normal file
72
experiment/src/animation.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use geom::{Duration, Pt2D, Time};
|
||||
use widgetry::{Drawable, EventCtx, GeomBatch, GfxCtx};
|
||||
|
||||
pub struct Animator {
|
||||
time: Time,
|
||||
active: Vec<Effect>,
|
||||
draw_current: Drawable,
|
||||
}
|
||||
|
||||
struct Effect {
|
||||
start: Time,
|
||||
end: Time,
|
||||
orig: GeomBatch,
|
||||
center: Pt2D,
|
||||
// Scaling is the only transformation for now
|
||||
lerp_scale: (f64, f64),
|
||||
}
|
||||
|
||||
impl Animator {
|
||||
pub fn new(ctx: &EventCtx) -> Animator {
|
||||
Animator {
|
||||
time: Time::START_OF_DAY,
|
||||
active: Vec::new(),
|
||||
draw_current: Drawable::empty(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(
|
||||
&mut self,
|
||||
duration: Duration,
|
||||
lerp_scale: (f64, f64),
|
||||
center: Pt2D,
|
||||
orig: GeomBatch,
|
||||
) {
|
||||
self.active.push(Effect {
|
||||
start: self.time,
|
||||
end: self.time + duration,
|
||||
orig,
|
||||
lerp_scale,
|
||||
center,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn event(&mut self, ctx: &mut EventCtx) {
|
||||
if let Some(dt) = ctx.input.nonblocking_is_update_event() {
|
||||
self.time += dt;
|
||||
if self.active.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut batch = GeomBatch::new();
|
||||
let time = self.time;
|
||||
self.active.retain(|effect| effect.update(time, &mut batch));
|
||||
self.draw_current = ctx.upload(batch);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
g.redraw(&self.draw_current);
|
||||
}
|
||||
}
|
||||
|
||||
impl Effect {
|
||||
fn update(&self, time: Time, batch: &mut GeomBatch) -> bool {
|
||||
let pct = (time - self.start) / (self.end - self.start);
|
||||
if pct > 1.0 {
|
||||
return false;
|
||||
}
|
||||
let scale = self.lerp_scale.0 + pct * (self.lerp_scale.1 - self.lerp_scale.0);
|
||||
batch.append(self.orig.clone().scale(scale).centered_on(self.center));
|
||||
true
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ use widgetry::{
|
||||
Line, Outcome, Panel, State, Text, TextExt, Transition, UpdateType, VerticalAlignment, Widget,
|
||||
};
|
||||
|
||||
use crate::animation::Animator;
|
||||
use crate::controls::{Controller, InstantController, RotateController};
|
||||
|
||||
const ZOOM: f64 = 10.0;
|
||||
@ -18,6 +19,7 @@ pub struct Game {
|
||||
panel: Panel,
|
||||
controls: Box<dyn Controller>,
|
||||
minimap: SimpleMinimap,
|
||||
animator: Animator,
|
||||
|
||||
sleigh: Pt2D,
|
||||
state: SleighState,
|
||||
@ -71,6 +73,7 @@ impl Game {
|
||||
panel,
|
||||
controls: Box::new(InstantController::new()),
|
||||
minimap: SimpleMinimap::new(ctx, app, with_zorder),
|
||||
animator: Animator::new(ctx),
|
||||
|
||||
sleigh,
|
||||
state,
|
||||
@ -166,15 +169,27 @@ impl State<SimpleApp> for Game {
|
||||
}
|
||||
|
||||
if let Some(b) = self.over_bldg.key() {
|
||||
if self.state.has_energy() && self.state.present_dropped(ctx, app, b) {
|
||||
if self.state.has_energy() {
|
||||
if let Some(increase) = self.state.present_dropped(ctx, app, b) {
|
||||
self.over_bldg.clear();
|
||||
self.update_panel(ctx);
|
||||
self.animator.add(
|
||||
Duration::seconds(0.5),
|
||||
(1.0, 4.0),
|
||||
app.map.get_b(b).label_center,
|
||||
Text::from(Line(format!("+{}", prettyprint_usize(increase))))
|
||||
.bg(Color::RED)
|
||||
.render_to_batch(ctx.prerender)
|
||||
.scale(0.1),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(t) = self.minimap.event(ctx, app) {
|
||||
return t;
|
||||
}
|
||||
self.animator.event(ctx);
|
||||
|
||||
match self.panel.event(ctx) {
|
||||
Outcome::Clicked(x) => match x.as_ref() {
|
||||
@ -242,6 +257,7 @@ impl State<SimpleApp> for Game {
|
||||
Color::RED,
|
||||
Circle::new(self.sleigh, Distance::meters(5.0)).to_polygon(),
|
||||
);
|
||||
self.animator.draw(g);
|
||||
}
|
||||
}
|
||||
|
||||
@ -367,16 +383,21 @@ impl SleighState {
|
||||
self.draw_all_depots = ctx.upload(batch);
|
||||
}
|
||||
|
||||
// True if state change
|
||||
fn present_dropped(&mut self, ctx: &mut EventCtx, app: &SimpleApp, id: BuildingID) -> bool {
|
||||
// If something changed, return the update to the score
|
||||
fn present_dropped(
|
||||
&mut self,
|
||||
ctx: &mut EventCtx,
|
||||
app: &SimpleApp,
|
||||
id: BuildingID,
|
||||
) -> Option<usize> {
|
||||
if let Some(BldgState::Undelivered { score, cost }) = self.houses.get(&id).cloned() {
|
||||
self.score += score;
|
||||
self.houses.insert(id, BldgState::Done);
|
||||
self.energy -= cost;
|
||||
self.redraw(ctx, app);
|
||||
return true;
|
||||
return Some(score);
|
||||
}
|
||||
false
|
||||
None
|
||||
}
|
||||
|
||||
// True if state change
|
||||
|
@ -1,3 +1,4 @@
|
||||
mod animation;
|
||||
mod controls;
|
||||
mod game;
|
||||
mod upzone;
|
||||
|
Loading…
Reference in New Issue
Block a user