mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 07:52:05 +03:00
first lift sim out of sim ctrl
This commit is contained in:
parent
04a25bd489
commit
147901790c
@ -933,6 +933,38 @@ alright, time to move color logic. let's see what it takes for each Renderable t
|
||||
|
||||
OK, so where was I?
|
||||
- colors are still currently missing for things that need two of them.
|
||||
- having one active plugin at a time simplifies the color problem and solves a few others, so try that now.
|
||||
** having one active plugin at a time simplifies the color problem and solves a few others, so try that now.
|
||||
- another refactor to do -- initiate plugins based on current_selection_state in UI or the plugin, but stop mixing so much
|
||||
- make car and ped also Renderable, for great consistency!
|
||||
- work on generic quadtree idea
|
||||
|
||||
### One active plugin at a time
|
||||
|
||||
I wonder if the UI will have a need to reach into plugins beyond event(). Let's find out!
|
||||
- exceptions
|
||||
- hider needs to given to finding onscreen stuff
|
||||
- search can specify colors and OSD lines
|
||||
- warp can add OSD lines
|
||||
- show_route can color
|
||||
- floodfiller can color
|
||||
- steepness can color
|
||||
- osm can color
|
||||
- signal and stop sign editor can color and indicate what icons are onscreen
|
||||
- road editor can be asked for state to serialize
|
||||
- sim ctrl can contribute OSD lines (and everything grabs sim from it directly too -- maybe sim should live in UI directly)
|
||||
- color picker can draw
|
||||
- turn cycler can draw
|
||||
|
||||
- the stuff they take in event() is different. hmm.
|
||||
- box lil closures
|
||||
|
||||
so it feels like we implicitly have a big enum of active plugin, with each of their states kinda hidden inside.
|
||||
|
||||
- the simple idea
|
||||
- UI keeps having a bunch of separate plugins with their real type
|
||||
- have a list of closures that take UI and do event(). return true if that plugin is active
|
||||
NOT if something was done with the input
|
||||
- in event(), go through the list and stop when something becomes
|
||||
active. remember it's active and just call it directly next time in
|
||||
event(), until it says its no longer active.
|
||||
- then figure out the implications for color
|
||||
|
@ -4,14 +4,12 @@ use control::ControlMap;
|
||||
use ezgui::UserInput;
|
||||
use map_model::Map;
|
||||
use piston::input::{Key, UpdateEvent};
|
||||
use sim;
|
||||
use sim::{Benchmark, Sim};
|
||||
use sim::{Benchmark, Sim, TIMESTEP};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
const ADJUST_SPEED: f64 = 0.1;
|
||||
|
||||
pub struct SimController {
|
||||
pub sim: Sim,
|
||||
desired_speed: f64, // sim seconds per real second
|
||||
// If None, then the sim is paused
|
||||
last_step: Option<Instant>,
|
||||
@ -20,9 +18,8 @@ pub struct SimController {
|
||||
}
|
||||
|
||||
impl SimController {
|
||||
pub fn new(sim: Sim) -> SimController {
|
||||
pub fn new() -> SimController {
|
||||
SimController {
|
||||
sim,
|
||||
desired_speed: 1.0,
|
||||
last_step: None,
|
||||
benchmark: None,
|
||||
@ -31,7 +28,13 @@ impl SimController {
|
||||
}
|
||||
|
||||
// true if the sim is running
|
||||
pub fn event(&mut self, input: &mut UserInput, map: &Map, control_map: &ControlMap) -> bool {
|
||||
pub fn event(
|
||||
&mut self,
|
||||
input: &mut UserInput,
|
||||
map: &Map,
|
||||
control_map: &ControlMap,
|
||||
sim: &mut Sim,
|
||||
) -> bool {
|
||||
if input.unimportant_key_pressed(Key::LeftBracket, "slow down sim") {
|
||||
self.desired_speed -= ADJUST_SPEED;
|
||||
self.desired_speed = self.desired_speed.max(0.0);
|
||||
@ -40,12 +43,12 @@ impl SimController {
|
||||
self.desired_speed += ADJUST_SPEED;
|
||||
}
|
||||
if input.unimportant_key_pressed(Key::O, "save sim state") {
|
||||
self.sim.save();
|
||||
sim.save();
|
||||
}
|
||||
if input.unimportant_key_pressed(Key::P, "load sim state") {
|
||||
match self.sim.load_most_recent() {
|
||||
Ok(sim) => {
|
||||
self.sim = sim;
|
||||
match sim.load_most_recent() {
|
||||
Ok(new_sim) => {
|
||||
*sim = new_sim;
|
||||
self.benchmark = None;
|
||||
}
|
||||
Err(e) => println!("Couldn't load savestate: {}", e),
|
||||
@ -60,9 +63,9 @@ impl SimController {
|
||||
} else {
|
||||
if input.unimportant_key_pressed(Key::Space, "run sim") {
|
||||
self.last_step = Some(Instant::now());
|
||||
self.benchmark = Some(self.sim.start_benchmark());
|
||||
self.benchmark = Some(sim.start_benchmark());
|
||||
} else if input.unimportant_key_pressed(Key::M, "run one step") {
|
||||
self.sim.step(map, control_map);
|
||||
sim.step(map, control_map);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,14 +74,14 @@ impl SimController {
|
||||
// TODO https://gafferongames.com/post/fix_your_timestep/
|
||||
let dt = tick.elapsed();
|
||||
let dt_s = dt.as_secs() as f64 + f64::from(dt.subsec_nanos()) * 1e-9;
|
||||
if dt_s >= sim::TIMESTEP.value_unsafe / self.desired_speed {
|
||||
self.sim.step(map, control_map);
|
||||
if dt_s >= TIMESTEP.value_unsafe / self.desired_speed {
|
||||
sim.step(map, control_map);
|
||||
self.last_step = Some(Instant::now());
|
||||
}
|
||||
|
||||
if let Some(ref mut b) = self.benchmark {
|
||||
if b.has_real_time_passed(Duration::from_secs(1)) {
|
||||
self.sim_speed = format!("{0:.2}x", self.sim.measure_speed(b));
|
||||
self.sim_speed = format!("{0:.2}x", sim.measure_speed(b));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -86,9 +89,9 @@ impl SimController {
|
||||
self.last_step.is_some()
|
||||
}
|
||||
|
||||
pub fn get_osd_lines(&self) -> Vec<String> {
|
||||
pub fn get_osd_lines(&self, sim: &Sim) -> Vec<String> {
|
||||
vec![
|
||||
self.sim.summary(),
|
||||
sim.summary(),
|
||||
format!(
|
||||
"Speed: {0} / desired {1:.2}x",
|
||||
self.sim_speed, self.desired_speed
|
||||
|
@ -34,7 +34,7 @@ use plugins::warp::WarpState;
|
||||
use render;
|
||||
use render::Renderable;
|
||||
use sim;
|
||||
use sim::{AgentID, CarID, CarState, PedestrianID};
|
||||
use sim::{AgentID, CarID, CarState, PedestrianID, Sim};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::process;
|
||||
|
||||
@ -48,6 +48,7 @@ pub struct UI {
|
||||
map: map_model::Map,
|
||||
draw_map: render::DrawMap,
|
||||
control_map: ControlMap,
|
||||
sim: Sim,
|
||||
|
||||
show_lanes: ToggleableLayer,
|
||||
show_buildings: ToggleableLayer,
|
||||
@ -69,7 +70,6 @@ pub struct UI {
|
||||
floodfiller: Floodfiller,
|
||||
steepness_viz: SteepnessVisualizer,
|
||||
osm_classifier: OsmClassifier,
|
||||
turn_colors: TurnColors,
|
||||
traffic_signal_editor: TrafficSignalEditor,
|
||||
stop_sign_editor: StopSignEditor,
|
||||
road_editor: RoadEditor,
|
||||
@ -78,6 +78,9 @@ pub struct UI {
|
||||
geom_validator: Validator,
|
||||
turn_cycler: TurnCyclerState,
|
||||
|
||||
// Not really a plugin; it doesn't react to anything.
|
||||
turn_colors: TurnColors,
|
||||
|
||||
canvas: Canvas,
|
||||
// TODO maybe never pass this to other places? Always resolve colors here?
|
||||
cs: ColorScheme,
|
||||
@ -113,15 +116,17 @@ impl UI {
|
||||
|
||||
let steepness_viz = SteepnessVisualizer::new(&map);
|
||||
let turn_colors = TurnColors::new(&control_map);
|
||||
let sim_ctrl = SimController::new(sim);
|
||||
|
||||
let mut ui = UI {
|
||||
// TODO organize this by section
|
||||
map,
|
||||
draw_map,
|
||||
control_map,
|
||||
sim,
|
||||
|
||||
steepness_viz,
|
||||
turn_colors,
|
||||
sim_ctrl,
|
||||
sim_ctrl: SimController::new(),
|
||||
|
||||
show_lanes: ToggleableLayer::new("lanes", Key::D3, Some(MIN_ZOOM_FOR_LANES)),
|
||||
show_buildings: ToggleableLayer::new("buildings", Key::D1, Some(0.0)),
|
||||
@ -212,12 +217,12 @@ impl UI {
|
||||
Vec::new()
|
||||
};
|
||||
for l in &lanes_onscreen {
|
||||
for c in &self.sim_ctrl.sim.get_draw_cars_on_lane(l.id, &self.map) {
|
||||
for c in &self.sim.get_draw_cars_on_lane(l.id, &self.map) {
|
||||
if c.contains_pt(pt) {
|
||||
return Some(ID::Car(c.id));
|
||||
}
|
||||
}
|
||||
for p in &self.sim_ctrl.sim.get_draw_peds_on_lane(l.id, &self.map) {
|
||||
for p in &self.sim.get_draw_peds_on_lane(l.id, &self.map) {
|
||||
if p.contains_pt(pt) {
|
||||
return Some(ID::Pedestrian(p.id));
|
||||
}
|
||||
@ -235,12 +240,12 @@ impl UI {
|
||||
return Some(ID::Turn(*t));
|
||||
}
|
||||
|
||||
for c in &self.sim_ctrl.sim.get_draw_cars_on_turn(*t, &self.map) {
|
||||
for c in &self.sim.get_draw_cars_on_turn(*t, &self.map) {
|
||||
if c.contains_pt(pt) {
|
||||
return Some(ID::Car(c.id));
|
||||
}
|
||||
}
|
||||
for p in &self.sim_ctrl.sim.get_draw_peds_on_turn(*t, &self.map) {
|
||||
for p in &self.sim.get_draw_peds_on_turn(*t, &self.map) {
|
||||
if p.contains_pt(pt) {
|
||||
return Some(ID::Pedestrian(p.id));
|
||||
}
|
||||
@ -389,7 +394,7 @@ impl UI {
|
||||
return c;
|
||||
}
|
||||
// TODO if it's a bus, color it differently -- but how? :\
|
||||
match self.sim_ctrl.sim.get_car_state(id) {
|
||||
match self.sim.get_car_state(id) {
|
||||
CarState::Debug => shift_color(self.cs.get(Colors::DebugCar), id.0),
|
||||
CarState::Moving => shift_color(self.cs.get(Colors::MovingCar), id.0),
|
||||
CarState::Stuck => shift_color(self.cs.get(Colors::StuckCar), id.0),
|
||||
@ -460,21 +465,21 @@ impl GUI for UI {
|
||||
&mut self.map,
|
||||
&mut self.draw_map,
|
||||
&self.control_map,
|
||||
&mut self.sim_ctrl.sim
|
||||
&mut self.sim
|
||||
));
|
||||
stop_if_done!(self.current_search_state.event(input));
|
||||
stop_if_done!(self.warp.event(
|
||||
input,
|
||||
&self.map,
|
||||
&self.sim_ctrl.sim,
|
||||
&self.sim,
|
||||
&mut self.canvas,
|
||||
&mut self.current_selection_state,
|
||||
));
|
||||
stop_if_done!(
|
||||
self.follow
|
||||
.event(input, &self.map, &self.sim_ctrl.sim, &mut self.canvas,)
|
||||
.event(input, &self.map, &self.sim, &mut self.canvas,)
|
||||
);
|
||||
stop_if_done!(self.show_route.event(input, &self.sim_ctrl.sim));
|
||||
stop_if_done!(self.show_route.event(input, &self.sim));
|
||||
stop_if_done!(
|
||||
self.color_picker
|
||||
.handle_event(input, &mut self.canvas, &mut self.cs)
|
||||
@ -543,7 +548,7 @@ impl GUI for UI {
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if input.unimportant_key_pressed(Key::S, "Seed the map with agents") {
|
||||
self.sim_ctrl.sim.small_spawn(&self.map);
|
||||
self.sim.small_spawn(&self.map);
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
|
||||
@ -552,11 +557,11 @@ impl GUI for UI {
|
||||
// TODO not sure if we should debug like this (pushing the bit down to all the
|
||||
// layers representing an entity) or by using some scary global mutable singleton
|
||||
if input.unimportant_key_pressed(Key::D, "debug") {
|
||||
self.sim_ctrl.sim.toggle_debug(id);
|
||||
self.sim.toggle_debug(id);
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if input.key_pressed(Key::A, "start this parked car") {
|
||||
self.sim_ctrl.sim.start_parked_car(&self.map, id);
|
||||
self.sim.start_parked_car(&self.map, id);
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
if input.key_pressed(Key::F, "follow this car") {
|
||||
@ -588,7 +593,7 @@ impl GUI for UI {
|
||||
if self.map.get_l(id).is_sidewalk()
|
||||
&& input.key_pressed(Key::A, "spawn a pedestrian here")
|
||||
{
|
||||
self.sim_ctrl.sim.spawn_pedestrian(&self.map, id);
|
||||
self.sim.spawn_pedestrian(&self.map, id);
|
||||
return EventLoopMode::InputOnly;
|
||||
}
|
||||
}
|
||||
@ -613,7 +618,7 @@ impl GUI for UI {
|
||||
stop_if_done!(self.current_selection_state.event(
|
||||
input,
|
||||
&self.map,
|
||||
&mut self.sim_ctrl.sim,
|
||||
&mut self.sim,
|
||||
&self.control_map
|
||||
));
|
||||
|
||||
@ -636,7 +641,9 @@ impl GUI for UI {
|
||||
}
|
||||
|
||||
// Sim controller plugin is kind of always active? If nothing else ran, let it use keys.
|
||||
if self.sim_ctrl.event(input, &self.map, &self.control_map) {
|
||||
if self.sim_ctrl
|
||||
.event(input, &self.map, &self.control_map, &mut self.sim)
|
||||
{
|
||||
EventLoopMode::Animation
|
||||
} else {
|
||||
EventLoopMode::InputOnly
|
||||
@ -683,10 +690,10 @@ impl GUI for UI {
|
||||
.get_t(*t)
|
||||
.draw(g, self.color_turn_icon(*t), &self.cs);
|
||||
}
|
||||
for c in &self.sim_ctrl.sim.get_draw_cars_on_turn(*t, &self.map) {
|
||||
for c in &self.sim.get_draw_cars_on_turn(*t, &self.map) {
|
||||
c.draw(g, self.color_car(c.id));
|
||||
}
|
||||
for p in &self.sim_ctrl.sim.get_draw_peds_on_turn(*t, &self.map) {
|
||||
for p in &self.sim.get_draw_peds_on_turn(*t, &self.map) {
|
||||
p.draw(g, self.color_ped(p.id));
|
||||
}
|
||||
}
|
||||
@ -716,10 +723,10 @@ impl GUI for UI {
|
||||
}
|
||||
|
||||
for l in &lanes_onscreen {
|
||||
for c in &self.sim_ctrl.sim.get_draw_cars_on_lane(l.id, &self.map) {
|
||||
for c in &self.sim.get_draw_cars_on_lane(l.id, &self.map) {
|
||||
c.draw(g, self.color_car(c.id));
|
||||
}
|
||||
for p in &self.sim_ctrl.sim.get_draw_peds_on_lane(l.id, &self.map) {
|
||||
for p in &self.sim.get_draw_peds_on_lane(l.id, &self.map) {
|
||||
p.draw(g, self.color_ped(p.id));
|
||||
}
|
||||
}
|
||||
@ -743,21 +750,16 @@ impl GUI for UI {
|
||||
&self.map,
|
||||
&self.draw_map,
|
||||
&self.control_map,
|
||||
&self.sim_ctrl.sim,
|
||||
&self.sim,
|
||||
&self.cs,
|
||||
g,
|
||||
);
|
||||
self.current_selection_state.draw(
|
||||
&self.map,
|
||||
&self.canvas,
|
||||
&self.draw_map,
|
||||
&self.sim_ctrl.sim,
|
||||
g,
|
||||
);
|
||||
self.current_selection_state
|
||||
.draw(&self.map, &self.canvas, &self.draw_map, &self.sim, g);
|
||||
|
||||
self.color_picker.draw(&self.canvas, g);
|
||||
|
||||
let mut osd_lines = self.sim_ctrl.get_osd_lines();
|
||||
let mut osd_lines = self.sim_ctrl.get_osd_lines(&self.sim);
|
||||
let action_lines = input.get_possible_actions();
|
||||
if !action_lines.is_empty() {
|
||||
osd_lines.push(String::from(""));
|
||||
|
Loading…
Reference in New Issue
Block a user