converting the spawner over, one of the most complex

This commit is contained in:
Dustin Carlino 2020-03-28 17:48:50 -07:00
parent 56544d6b14
commit 12c0809b23
7 changed files with 184 additions and 194 deletions

View File

@ -116,10 +116,8 @@ impl State for ABTestMode {
.and_then(|id| id.agent_id())
{
if let Some(trip) = app.primary.sim.agent_to_trip(agent) {
if app
.per_obj
.action(ctx, Key::B, format!("Show {}'s parallel world", agent))
{
// TODO Contextual action, Key::B, show parallel world
if false {
self.diff_trip = Some(DiffOneTrip::new(
trip,
&app.primary,
@ -368,10 +366,10 @@ pub struct ABTestSavestate {
struct Actions;
impl ContextualActions for Actions {
fn actions(&self, app: &App, id: ID) -> Vec<(Key, String)> {
Vec::new()
fn actions(&self, _: &App, _: ID) -> Vec<(Key, String)> {
unreachable!()
}
fn execute(&mut self, ctx: &mut EventCtx, app: &mut App, id: ID, action: String) -> Transition {
Transition::Keep
fn execute(&mut self, _: &mut EventCtx, _: &mut App, _: ID, _: String) -> Transition {
unreachable!()
}
}

View File

@ -253,7 +253,7 @@ impl State for DebugMode {
self.highlighted_agents = None;
}
self.objects.event(ctx, app);
self.objects.event(ctx);
if let Some(t) = self.common.event(ctx, app, None, &mut Actions {}) {
return t;

View File

@ -16,7 +16,7 @@ impl ObjectDebugger {
}
}
pub fn event(&mut self, ctx: &mut EventCtx, app: &App) {
pub fn event(&mut self, ctx: &mut EventCtx) {
if self.debug_tooltip_key_held {
self.debug_tooltip_key_held = !ctx.input.key_released(Key::RightControl);
} else {

View File

@ -561,7 +561,7 @@ struct Actions<'a> {
trips_to_border: &'a MultiMap<IntersectionID, (usize, usize)>,
}
impl<'a> ContextualActions for Actions<'a> {
fn actions(&self, app: &App, id: ID) -> Vec<(Key, String)> {
fn actions(&self, _: &App, id: ID) -> Vec<(Key, String)> {
let mut actions = Vec::new();
if let ID::Building(b) = id {

View File

@ -4,7 +4,7 @@ use crate::edit::EditMode;
use crate::game::{State, Transition, WizardState};
use crate::helpers::{nice_map_name, ID};
use crate::managed::{WrappedComposite, WrappedOutcome};
use crate::sandbox::gameplay::{spawner, GameplayMode, GameplayState};
use crate::sandbox::gameplay::{GameplayMode, GameplayState};
use crate::sandbox::SandboxControls;
use crate::sandbox::SandboxMode;
use ezgui::{
@ -44,16 +44,8 @@ impl GameplayState for Freeform {
return (Some(t), false);
}
Some(WrappedOutcome::Clicked(_)) => unreachable!(),
None => {}
None => (None, false),
}
if let Some(new_state) = spawner::AgentSpawner::new(ctx, app) {
return (Some(Transition::Push(new_state)), false);
}
if let Some(new_state) = spawner::SpawnManyAgents::new(ctx, app) {
return (Some(Transition::Push(new_state)), false);
}
(None, false)
}
fn draw(&self, g: &mut GfxCtx, app: &App) {

View File

@ -1,6 +1,6 @@
use crate::app::App;
use crate::colors;
use crate::common::{Colorer, CommonState};
use crate::common::{Colorer, CommonState, ContextualActions};
use crate::game::{msg, State, Transition, WizardState};
use crate::helpers::ID;
use crate::sandbox::gameplay::freeform::Freeform;
@ -29,7 +29,7 @@ const SMALL_DT: Duration = Duration::const_seconds(0.1);
// because we need to keep amending it and re-instantiating it, and because picking specific
// starting positions for vehicles depends on randomized vehicle lengths...
pub struct AgentSpawner {
struct AgentSpawner {
composite: Composite,
from: Source,
maybe_goal: Option<(Goal, Option<PolyLine>)>,
@ -51,142 +51,6 @@ enum Goal {
Border(IntersectionID),
}
impl AgentSpawner {
pub fn new(ctx: &mut EventCtx, app: &mut App) -> Option<Box<dyn State>> {
let map = &app.primary.map;
let color = app.cs.get("selected");
let mut c = Colorer::new(Text::from(Line("spawning agent")), vec![("start", color)]);
match app.primary.current_selection {
Some(ID::Building(id)) => {
c.add_b(id, color);
let spots = app.primary.sim.get_free_offstreet_spots(id);
if !spots.is_empty() && app.per_obj.action(ctx, Key::F6, "seed a parked car here") {
let mut rng = app.primary.current_flags.sim_flags.make_rng();
app.primary.sim.seed_parked_car(
Scenario::rand_car(&mut rng),
spots[0],
Some(id),
);
return None;
}
if app.per_obj.action(ctx, Key::F3, "spawn a walking trip") {
return Some(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a pedestrian",
"Pick a building or border as a destination",
),
from: Source::WalkFromBldg(id),
maybe_goal: None,
colorer: c.build(ctx, app),
}));
}
let parked = app.primary.sim.get_parked_cars_by_owner(id);
// TODO Check if it's claimed... Haha if it is, MaybeUsingParkedCar still snags it!
if !parked.is_empty()
&& app.per_obj.action(
ctx,
Key::F5,
"spawn a pedestrian here using an owned parked car",
)
{
return Some(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a walking trip using a parked car",
"Pick a building or border as a destination",
),
from: Source::WalkFromBldgThenMaybeUseCar(id),
maybe_goal: None,
colorer: c.build(ctx, app),
}));
}
if let Some(pos) = Position::bldg_via_driving(id, map) {
if app
.per_obj
.action(ctx, Key::F4, "spawn a car starting here")
{
return Some(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a car",
"Pick a building or border as a destination",
),
from: Source::Drive(pos),
maybe_goal: None,
colorer: c.build(ctx, app),
}));
}
}
if let Some(pos) = Position::bldg_via_biking(id, map) {
if app
.per_obj
.action(ctx, Key::F7, "spawn a bike starting here")
{
return Some(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a bike",
"Pick a building or border as a destination",
),
from: Source::BikeFromBldg(id, pos),
maybe_goal: None,
colorer: c.build(ctx, app),
}));
}
}
}
Some(ID::Lane(id)) => {
c.add_l(id, color, map);
if map.get_l(id).is_driving()
&& app
.per_obj
.action(ctx, Key::F3, "spawn a car starting here")
{
return Some(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a car",
"Pick a building or border as a destination",
),
from: Source::Drive(Position::new(id, map.get_l(id).length() / 2.0)),
maybe_goal: None,
colorer: c.build(ctx, app),
}));
} else if map.get_l(id).is_sidewalk()
&& app
.per_obj
.action(ctx, Key::F3, "spawn a pedestrian starting here")
{
return Some(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a pedestrian",
"Pick a building or border as a destination",
),
from: Source::WalkFromSidewalk(Position::new(
id,
map.get_l(id).length() / 2.0,
)),
maybe_goal: None,
colorer: c.build(ctx, app),
}));
}
}
Some(ID::Intersection(i)) => {
if app.per_obj.action(ctx, Key::Z, "spawn agents here") {
spawn_agents_around(i, app);
}
}
_ => {}
}
None
}
}
impl State for AgentSpawner {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
match self.composite.event(ctx) {
@ -531,7 +395,7 @@ fn schedule_trip(
}
// New experiment, stop squeezing in all these options into one thing, specialize.
pub struct SpawnManyAgents {
struct SpawnManyAgents {
composite: Composite,
from: LaneID,
maybe_goal: Option<(LaneID, Option<PolyLine>)>,
@ -539,38 +403,6 @@ pub struct SpawnManyAgents {
colorer: Colorer,
}
impl SpawnManyAgents {
pub fn new(ctx: &mut EventCtx, app: &mut App) -> Option<Box<dyn State>> {
if let Some(ID::Lane(l)) = app.primary.current_selection {
if app.primary.map.get_l(l).is_driving()
&& app
.per_obj
.action(ctx, Key::F2, "spawn many cars starting here")
{
let color = app.cs.get("selected");
let mut c = Colorer::new(
Text::from(Line("spawning many agents")),
vec![("start", color)],
);
c.add_l(l, color, &app.primary.map);
return Some(Box::new(SpawnManyAgents {
composite: make_top_bar(
ctx,
"Spawning many agents",
"Pick a driving lane as a destination",
),
from: l,
maybe_goal: None,
schedule: None,
colorer: c.build(ctx, app),
}));
}
}
None
}
}
impl State for SpawnManyAgents {
fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
// TODO Weird pattern for handling "return value" from the wizard we launched? Maybe
@ -719,3 +551,168 @@ fn make_top_bar(ctx: &mut EventCtx, title: &str, howto: &str) -> Composite {
.aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
.build(ctx)
}
pub struct Actions;
impl ContextualActions for Actions {
fn actions(&self, app: &App, id: ID) -> Vec<(Key, String)> {
let mut actions = Vec::new();
let map = &app.primary.map;
match id {
ID::Building(id) => {
if !app.primary.sim.get_free_offstreet_spots(id).is_empty() {
actions.push((Key::F6, "seed a parked car here".to_string()));
}
actions.push((Key::F3, "spawn a walking trip".to_string()));
// TODO Check if it's claimed... Haha if it is, MaybeUsingParkedCar still snags it!
if !app.primary.sim.get_parked_cars_by_owner(id).is_empty() {
actions.push((
Key::F5,
"spawn a pedestrian here using an owned parked car".to_string(),
));
}
if Position::bldg_via_driving(id, map).is_some() {
actions.push((Key::F4, "spawn a car starting here".to_string()));
}
if Position::bldg_via_biking(id, map).is_some() {
actions.push((Key::F7, "spawn a bike starting here".to_string()));
}
}
ID::Lane(id) => {
if map.get_l(id).is_driving() {
actions.push((Key::F3, "spawn a car starting here".to_string()));
actions.push((Key::F2, "spawn many cars starting here".to_string()));
} else if map.get_l(id).is_sidewalk() {
actions.push((Key::F3, "spawn a pedestrian starting here".to_string()));
}
}
ID::Intersection(_) => {
actions.push((Key::Z, "spawn agents here".to_string()));
}
_ => {}
}
actions
}
fn execute(&mut self, ctx: &mut EventCtx, app: &mut App, id: ID, action: String) -> Transition {
let map = &app.primary.map;
let color = app.cs.get("selected");
let mut c = Colorer::new(Text::from(Line("spawning agent")), vec![("start", color)]);
match (id, action.as_ref()) {
(ID::Building(id), "seed a parked car here") => {
let spots = app.primary.sim.get_free_offstreet_spots(id);
let mut rng = app.primary.current_flags.sim_flags.make_rng();
app.primary
.sim
.seed_parked_car(Scenario::rand_car(&mut rng), spots[0], Some(id));
Transition::Keep
}
(ID::Building(id), "spawn a walking trip") => {
c.add_b(id, color);
Transition::Push(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a pedestrian",
"Pick a building or border as a destination",
),
from: Source::WalkFromBldg(id),
maybe_goal: None,
colorer: c.build(ctx, app),
}))
}
(ID::Building(id), "spawn a pedestrian here using an owned parked car") => {
c.add_b(id, color);
Transition::Push(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a walking trip using a parked car",
"Pick a building or border as a destination",
),
from: Source::WalkFromBldgThenMaybeUseCar(id),
maybe_goal: None,
colorer: c.build(ctx, app),
}))
}
(ID::Building(id), "spawn a car starting here") => {
c.add_b(id, color);
let pos = Position::bldg_via_driving(id, map).unwrap();
Transition::Push(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a car",
"Pick a building or border as a destination",
),
from: Source::Drive(pos),
maybe_goal: None,
colorer: c.build(ctx, app),
}))
}
(ID::Building(id), "spawn a bike starting here") => {
c.add_b(id, color);
let pos = Position::bldg_via_biking(id, map).unwrap();
Transition::Push(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a bike",
"Pick a building or border as a destination",
),
from: Source::BikeFromBldg(id, pos),
maybe_goal: None,
colorer: c.build(ctx, app),
}))
}
(ID::Lane(id), "spawn a car starting here") => {
c.add_l(id, color, map);
Transition::Push(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a car",
"Pick a building or border as a destination",
),
from: Source::Drive(Position::new(id, map.get_l(id).length() / 2.0)),
maybe_goal: None,
colorer: c.build(ctx, app),
}))
}
(ID::Lane(id), "spawn a pedestrian starting here") => {
c.add_l(id, color, map);
Transition::Push(Box::new(AgentSpawner {
composite: make_top_bar(
ctx,
"Spawning a pedestrian",
"Pick a building or border as a destination",
),
from: Source::WalkFromSidewalk(Position::new(id, map.get_l(id).length() / 2.0)),
maybe_goal: None,
colorer: c.build(ctx, app),
}))
}
(ID::Lane(l), "spawn many cars starting here") => {
let color = app.cs.get("selected");
let mut c = Colorer::new(
Text::from(Line("spawning many agents")),
vec![("start", color)],
);
c.add_l(l, color, &app.primary.map);
Transition::Push(Box::new(SpawnManyAgents {
composite: make_top_bar(
ctx,
"Spawning many agents",
"Pick a driving lane as a destination",
),
from: l,
maybe_goal: None,
schedule: None,
colorer: c.build(ctx, app),
}))
}
(ID::Intersection(id), "spawn agents here") => {
spawn_agents_around(id, app);
Transition::Keep
}
_ => unreachable!(),
}
}
}

View File

@ -436,7 +436,7 @@ impl ContextualActions for Actions {
if !self.can_interact {
return actions;
}
match id {
match id.clone() {
ID::Intersection(i) => {
if app.primary.map.get_i(i).is_traffic_signal() {
actions.push((Key::F, "explore traffic signal details".to_string()));
@ -465,6 +465,9 @@ impl ContextualActions for Actions {
}
_ => {}
}
if let GameplayMode::Freeform(_) = self.gameplay {
actions.extend(gameplay::spawner::Actions.actions(app, id));
}
actions
}
@ -515,7 +518,7 @@ impl ContextualActions for Actions {
true,
))
}
_ => unreachable!(),
(id, action) => gameplay::spawner::Actions.execute(ctx, app, id, action.to_string()),
}
}
}