1"""
2This package implements tools to allow the user to interact with the simulation.
3This includes cameras, keyboard inputs, and the HUD.
4
5Most features are only available from the :py:mod:`pygame` when using :py:attr:`.LaunchConfig.pygame`.
6"""
7
8# Solutions see: https://stackoverflow.com/questions/69107143/how-to-end-a-while-loop-in-another-thread
9from threading import Event
10import carla
11from agents.tools import logger
12from launch_tools import CarlaDataProvider
13
14__all__ = ["spectator_follow_actor"]
15
16_follow_car_event = Event()
17"""Use the :py:meth:`treading.Event.set` method to stop the thread."""
18
19
[docs]
20def spectator_follow_actor(actor: carla.Actor):
21 """
22 Continuously follow the ego vehicle with the spectator view.
23
24 Attention:
25 - Needs to be run in a separate thread.
26 - Does not allow for thread.join() to stop the thread, before calling :py:meth:`stop`.
27
28 Methods:
29 stop: Stop following the actor.
30
31 See Also:
32 - :py:meth:`.CameraManager.follow_actor`
33 """
34 try:
35 while not _follow_car_event.is_set():
36 spectator_to_actor(actor)
37 except Exception as e:
38 logger.error(f"Error in spectator_follow_actor: {e}")
39
40
41spectator_follow_actor.stop = lambda: _follow_car_event.set() # type: ignore[attr-defined]
42
43
44def spectator_to_actor(actor: carla.Actor) -> None:
45 """
46 Set the spectator's view to follow the ego vehicle.
47
48 Parameters:
49 ego_vehicle (Vehicle): The ego vehicle that the spectator will follow.
50 world (World): The game world where the spectator view is set.
51
52 Description:
53 This function calculates the desired spectator transform by positioning the spectator
54 10 meters behind the ego vehicle and 5 meters above it. The spectator's view will follow
55 the ego vehicle from this transformed position.
56
57 Note:
58 To face the vehicle from behind, uncomment the line 'spectator_transform.rotation.yaw += 180'.
59
60 Returns:
61 None: The function does not return any value.
62 """
63 # Calculate the desired spectator transform
64 vehicle_transform = actor.get_transform()
65 spectator_transform = vehicle_transform
66 spectator_transform.location -= vehicle_transform.get_forward_vector() * 10 # Move 10 meters behind the vehicle
67 spectator_transform.location += vehicle_transform.get_up_vector() * 5 # Move 5 meters above the vehicle
68 # spectator_transform.rotation.yaw += 180 # Face the vehicle from behind
69
70 # Set the spectator's transform in the world
71 CarlaDataProvider.get_world().get_spectator().set_transform(spectator_transform)