Add a basic boost mechanic

This commit is contained in:
Dustin Carlino 2020-12-03 20:36:35 -08:00
parent 12d0294692
commit 97c5c45ca4
4 changed files with 77 additions and 12 deletions

View File

@ -13,14 +13,18 @@ use widgetry::{
use crate::animation::{Animator, SnowEffect};
use crate::buildings::{BldgState, Buildings};
use crate::levels::Level;
use crate::meters::make_bar;
use crate::meters::{custom_bar, make_bar};
use crate::movement::Player;
use crate::vehicles::Vehicle;
const ACQUIRE_BOOST_RATE: f64 = 0.5;
const BOOST_SPEED_MULTIPLIER: f64 = 1.5;
pub struct Game {
title_panel: Panel,
status_panel: Panel,
time_panel: Panel,
boost_panel: Panel,
minimap: SimpleMinimap,
animator: Animator,
@ -71,6 +75,15 @@ impl Game {
.aligned(HorizontalAlignment::LeftInset, VerticalAlignment::TopInset)
.build(ctx);
let boost_panel = Panel::new(Widget::row(vec![
"Boost".draw_text(ctx),
Widget::draw_batch(ctx, GeomBatch::new())
.named("boost")
.align_right(),
]))
.aligned(HorizontalAlignment::Center, VerticalAlignment::BottomInset)
.build(ctx);
let start = app
.map
.find_i_by_osm_id(level.start)
@ -85,6 +98,7 @@ impl Game {
title_panel,
status_panel,
time_panel,
boost_panel,
minimap: SimpleMinimap::new(ctx, app, with_zorder),
animator: Animator::new(ctx),
@ -119,6 +133,18 @@ impl Game {
self.state.vehicle.max_energy,
);
self.status_panel.replace(ctx, "energy", energy_bar);
let boost_bar = custom_bar(
ctx,
Color::hex("#A32015"),
self.state.boost / self.state.vehicle.max_boost,
if self.state.boost == Duration::ZERO {
Text::from(Line("Find a bike or bus lane to get a boost"))
} else {
Text::from(Line("Press space to boost"))
},
);
self.boost_panel.replace(ctx, "boost", boost_bar);
}
}
@ -128,11 +154,21 @@ impl State<SimpleApp> for Game {
self.time += dt;
}
let speed = if self.state.has_energy() {
let base_speed = if self.state.has_energy() {
self.state.vehicle.normal_speed
} else {
self.state.vehicle.tired_speed
};
let speed = if ctx.is_key_down(Key::Space) && self.state.boost > Duration::ZERO {
if let Some(dt) = ctx.input.nonblocking_is_update_event() {
self.state.boost -= dt;
self.state.boost = self.state.boost.max(Duration::ZERO);
}
base_speed * BOOST_SPEED_MULTIPLIER
} else {
base_speed
};
for b in self.player.update_with_speed(ctx, app, speed) {
match self.state.bldgs.buildings[&b] {
BldgState::Undelivered(_) => {
@ -168,6 +204,12 @@ impl State<SimpleApp> for Game {
BldgState::Done => {}
}
}
if let Some(dt) = ctx.input.nonblocking_is_update_event() {
if self.player.on_good_road(app) {
self.state.boost += dt * ACQUIRE_BOOST_RATE;
self.state.boost = self.state.boost.min(self.state.vehicle.max_boost);
}
}
if let Some(t) = self.minimap.event(ctx, app) {
return t;
@ -222,6 +264,7 @@ impl State<SimpleApp> for Game {
self.title_panel.draw(g);
self.status_panel.draw(g);
self.time_panel.draw(g);
self.boost_panel.draw(g);
let santa_tracker = g.upload(GeomBatch::from(vec![(
Color::RED,
@ -271,6 +314,7 @@ struct GameState {
score: usize,
// Number of gifts currently being carried
energy: usize,
boost: Duration,
draw_done_houses: Drawable,
energyless_arrow: Option<EnergylessArrow>,
@ -292,6 +336,7 @@ impl GameState {
score: 0,
energy,
boost: Duration::ZERO,
draw_done_houses: Drawable::empty(ctx),
energyless_arrow: None,

View File

@ -2,11 +2,10 @@ use abstutil::prettyprint_usize;
use geom::Polygon;
use widgetry::{Color, EventCtx, GeomBatch, Line, Text, Widget};
pub fn make_bar(ctx: &mut EventCtx, filled_color: Color, value: usize, max: usize) -> Widget {
pub fn custom_bar(ctx: &mut EventCtx, filled_color: Color, pct_full: f64, txt: Text) -> Widget {
let total_width = 300.0;
let height = 32.0;
let radius = Some(4.0);
let pct_full = (value as f64) / (max as f64);
let mut batch = GeomBatch::new();
// Background
@ -19,13 +18,18 @@ pub fn make_bar(ctx: &mut EventCtx, filled_color: Color, value: usize, max: usiz
batch.push(filled_color, poly);
}
// Text
let label = Text::from(Line(format!(
"{} / {}",
prettyprint_usize(value),
prettyprint_usize(max)
)))
.render_to_batch(ctx.prerender);
let label = txt.render_to_batch(ctx.prerender);
let dims = label.get_dims();
batch.append(label.translate(10.0, height / 2.0 - dims.height / 2.0));
Widget::draw_batch(ctx, batch)
}
pub fn make_bar(ctx: &mut EventCtx, filled_color: Color, value: usize, max: usize) -> Widget {
let pct_full = (value as f64) / (max as f64);
let txt = Text::from(Line(format!(
"{} / {}",
prettyprint_usize(value),
prettyprint_usize(max)
)));
custom_bar(ctx, filled_color, pct_full, txt)
}

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use abstutil::MultiMap;
use geom::{Angle, Circle, Distance, Pt2D, Speed};
use map_gui::{SimpleApp, ID};
use map_model::{BuildingID, Direction, IntersectionID, RoadID};
use map_model::{BuildingID, Direction, IntersectionID, LaneType, RoadID};
use widgetry::EventCtx;
use crate::controls::InstantController;
@ -134,6 +134,18 @@ impl Player {
pub fn get_angle(&self) -> Angle {
self.controls.facing
}
/// Is the player currently on a road with a bus or bike lane?
pub fn on_good_road(&self, app: &SimpleApp) -> bool {
if let On::Road(r, _) = self.on {
for (_, _, lt) in app.map.get_r(r).lanes_ltr() {
if lt == LaneType::Biking || lt == LaneType::Bus {
return true;
}
}
}
false
}
}
#[derive(Clone)]

View File

@ -1,4 +1,4 @@
use geom::{Speed, Time};
use geom::{Duration, Speed, Time};
pub struct Vehicle {
pub name: &'static str,
@ -6,6 +6,7 @@ pub struct Vehicle {
pub normal_speed: Speed,
pub tired_speed: Speed,
pub max_energy: usize,
pub max_boost: Duration,
// Paths to SVGs to draw in sequence
pub draw_frames: Vec<&'static str>,
@ -20,6 +21,7 @@ impl Vehicle {
normal_speed: Speed::miles_per_hour(30.0),
tired_speed: Speed::miles_per_hour(10.0),
max_energy: 80,
max_boost: Duration::seconds(5.0),
draw_frames: vec!["sleigh.svg"],
},
@ -29,6 +31,7 @@ impl Vehicle {
normal_speed: Speed::miles_per_hour(40.0),
tired_speed: Speed::miles_per_hour(15.0),
max_energy: 50,
max_boost: Duration::seconds(8.0),
draw_frames: vec!["bike1.svg", "bike2.svg", "bike1.svg", "bike3.svg"],
},
@ -38,6 +41,7 @@ impl Vehicle {
normal_speed: Speed::miles_per_hour(40.0),
tired_speed: Speed::miles_per_hour(5.0),
max_energy: 150,
max_boost: Duration::seconds(10.0),
draw_frames: vec![
"cargo_bike1.svg",