diff --git a/src/scenic/core/simulators.py b/src/scenic/core/simulators.py index 832b03632..1fa3d1c56 100644 --- a/src/scenic/core/simulators.py +++ b/src/scenic/core/simulators.py @@ -331,6 +331,7 @@ def __init__( continueAfterDivergence=False, verbosity=0, ): + self.screen = None self.result = None self.scene = scene self.objects = [] @@ -432,6 +433,13 @@ def _run(self, dynamicScenario, maxSteps): terminationReason = newReason terminationType = TerminationType.terminatedByMonitor + # Check if users manually closed out display for simulator + if "Dead" in str(self.screen): + return ( + TerminationType.terminatedByUser, + "user manually terminated simulation", + ) + # "Always" and scenario-level requirements have been checked; # now safe to terminate if the top-level scenario has finished, # a monitor requested termination, or we've hit the timeout @@ -886,6 +894,9 @@ class TerminationType(enum.Enum): #: A :term:`dynamic behavior` used :keyword:`terminate simulation` to end the simulation. terminatedByBehavior = "a behavior terminated the simulation" + #: A user manually intervenes and closes display window + terminatedByUser = "manually terminated by user" + class SimulationResult: """Result of running a simulation. diff --git a/src/scenic/simulators/newtonian/simulator.py b/src/scenic/simulators/newtonian/simulator.py index 193103ab7..6ff603509 100644 --- a/src/scenic/simulators/newtonian/simulator.py +++ b/src/scenic/simulators/newtonian/simulator.py @@ -84,6 +84,7 @@ def __init__( self.export_gif = export_gif self.render = render self.network = network + self.screen = None self.frames = [] self.debug_render = debug_render @@ -226,6 +227,11 @@ def step(self): obj.heading += obj.angularSpeed * self.timestep if self.render: + # Handle closing out pygame screen + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.destroy() + return self.draw_objects() pygame.event.pump()