mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 12:12:00 +03:00
converting the spawner over, one of the most complex
This commit is contained in:
parent
56544d6b14
commit
12c0809b23
@ -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!()
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user