def get_player_input(self) -> PlayerInput: player_input = PlayerInput() player_input.throttle = self.controls.throttle player_input.steer = self.controls.steer player_input.pitch = self.controls.pitch player_input.yaw = self.controls.yaw player_input.roll = self.controls.roll player_input.jump = self.controls.jump player_input.boost = self.controls.boost player_input.handbrake = self.controls.handbrake return player_input
def convert_player_input(ctrl: SimpleControllerState) -> PlayerInput: """ Converts a SimpleControllerState to a PlayerInput object. """ player_input = PlayerInput() player_input.throttle = ctrl.throttle player_input.steer = ctrl.steer player_input.pitch = ctrl.pitch player_input.yaw = ctrl.yaw player_input.roll = ctrl.roll player_input.jump = ctrl.jump player_input.boost = ctrl.boost player_input.handbrake = ctrl.handbrake # player_input.use_item = ctrl.use_item return player_input
def __init__(self, index: int, packet: GameTickPacket = None): self.location: Vector3 = Vector3(0, 0, 0) self.orientation: Matrix3 = Matrix3(0, 0, 0) self.velocity: Vector3 = Vector3(0, 0, 0) self.angular_velocity: [] = [0, 0, 0] self.demolished: bool = False self.airborne: bool = False self.supersonic: bool = False self.jumped: bool = False self.doublejumped: bool = False self.team: int = 0 self.boost: float = 0 self.index: int = index self.controller: PlayerInput = PlayerInput() # A list that acts as the routines stack self.stack: [] = [] self.action: Action = Action.Shadowing self.on_side: bool = False self.closest: bool = False self.second_closest: bool = False self.time = 0 self.delta_time = 1 / 120 self.boost_accel = 991 + (2 / 3) self.gravity = Vector3(0, 0, -650) self.goals = 0 self.ball_prediction_struct = None if packet is not None: car = packet.game_cars[self.index] self.team = car.team self.hitbox = Hitbox(car.hitbox.length, car.hitbox.width, car.hitbox.height, Vector3(car.hitbox_offset)) self.update(packet)
def update(self, packet: GameTickPacket): car = packet.game_cars[self.index] self.location.data = [ car.physics.location.x, car.physics.location.y, car.physics.location.z ] self.velocity.data = [ car.physics.velocity.x, car.physics.velocity.y, car.physics.velocity.z ] self.orientation = Matrix3(car.physics.rotation.pitch, car.physics.rotation.yaw, car.physics.rotation.roll) self.angular_velocity = self.orientation.dot([ car.physics.angular_velocity.x, car.physics.angular_velocity.y, car.physics.angular_velocity.z ]).data self.demolished = car.is_demolished self.airborne = not car.has_wheel_contact self.supersonic = car.is_super_sonic self.jumped = car.jumped self.doublejumped = car.double_jumped self.boost = car.boost # Reset controller self.controller = PlayerInput() self.closest = False
def update_controls(self, controls: PlayerInput): air_roll = self.button_data[2] or self.button_data[9] controls.throttle = self.axis_data[5] - self.axis_data[4] controls.steer = self.axis_data[0] controls.pitch = self.axis_data[1] controls.yaw = 0 if air_roll else self.axis_data[0] controls.roll = self.axis_data[0] if air_roll else 0 controls.jump = self.button_data[0] controls.boost = self.button_data[1] controls.handbrake = air_roll
def get_outputs(self, state: GameTickPacket) -> Dict[int, Action]: """Returns a dictionary where the keys are indices of your drones and the values are PlayerInput objects (the controller inputs)""" # check if round is active if state.game_info.is_round_active: # round is active, update state and make bot decisions self.stopped = False current_state = State.from_packet(state, self.drone_actions, self.enemy_actions) current_state.dt = C.DT self.drone_actions, self.enemy_actions = self.choose_action( current_state) # finalize stored packets for i in self.drone_actions: current_state.drones[i].current_action = self.drone_actions[i] for i in self.enemy_actions: current_state.enemies[i].current_action = self.enemy_actions[i] last_state = self.initial_states[-1] if last_state is not None: last_state.dt = state.game_info.seconds_elapsed - self.time self.final_states.append(current_state) self.initial_states.append(current_state) else: self.initial_states[-1] = current_state self.time = state.game_info.seconds_elapsed # transform into RLBot compatible inputs self.controls = { i: PlayerInput(*self.drone_actions[i]) for i in self.drone_indices } elif not self.stopped: # first interrupted frame, restart data capture self.stopped = True self.initial_states[-1] = None # train predictor if possible if self.final_states: self.predictor.train(self.initial_states[:-1], self.final_states) # set controls to nothing self.controls = { i: PlayerInput(*C.NOTHING) for i in self.drone_indices } return self.controls
def get_outputs(self, packet: GameTickPacket) -> Dict[int, PlayerInput]: # Your logic goes here! # Return a dictionary where the keys are indices of your drones and # the values are PlayerInput objects (the controller inputs). return { index: PlayerInput(throttle=1.0) for index in self.drone_indices }
def prepare_for_run(self): # Set up shared memory map (offset makes it so bot only writes to its own input!) and map to buffer self.bot_input = PlayerInput() # Set up shared memory for game data # We want to do a deep copy for game inputs so people don't mess with em self.game_tick_packet = gd.GameTickPacket() # Set up shared memory for Ball prediction self.ball_prediction = bp.BallPrediction() # Set up shared memory for rigid body tick self.rigid_body_tick = RigidBodyTick()
def __init__(self, index: int, team: int): self.index: int = index self.team: int = team self.pos: np.ndarray = np.zeros(3) self.rot: np.ndarray = np.zeros(3) self.vel: np.ndarray = np.zeros(3) self.boost: float = 0.0 self.orient_m: np.ndarray = np.identity(3) self.ctrl: PlayerInput = PlayerInput() self.forward: bool = True self.going: bool = False
def game_loop(self): """The main game loop. This is where your hivemind code goes.""" # Setting up rate limiter. rate_limit = rate_limiter.RateLimiter(120) # Setting up data. field_info = FieldInfoPacket() self.game_interface.update_field_info_packet(field_info) packet = GameTickPacket() self.game_interface.update_live_data_packet(packet) data.setup(self, packet, field_info, self.running_indices) self.ball.predict = BallPrediction() # https://github.com/RLBot/RLBotPythonExample/wiki/Ball-Path-Prediction # MAIN LOOP: while True: # Updating the game packet from the game. self.game_interface.update_live_data_packet(packet) # Processing packet. data.process(self, packet) # Ball prediction. self.game_interface.update_ball_prediction(self.ball.predict) # Planning. brain.plan(self) # Rendering. self.render_debug(self.game_interface.renderer) # For each drone under the hivemind's control, do something. for drone in self.drones: # The controls are reset each frame. drone.ctrl = PlayerInput( ) # Basically the same as SimpleControllerState(). # Role execution. if drone.role is not None: drone.role.execute(self, drone) self.render_role(self.game_interface.renderer, drone) # Send the controls to the bots. self.game_interface.update_player_input( drone.ctrl, drone.index) # Rate limit sleep. rate_limit.acquire()
def get_outputs(self, packet: GameTickPacket) -> Dict[int, PlayerInput]: """Where all the logic of your hivemind gets its input and returns its outputs for each drone. Use self.drone_indices to access the set of bot indices your hivemind controls. Arguments: packet {GameTickPacket} -- see https://github.com/RLBot/RLBot/wiki/Input-and-Output-Data-(current) Returns: Dict[int, PlayerInput] -- A dictionary with drone indices as keys and corresponding PlayerInputs as values. """ return {index: PlayerInput() for index in self.drone_indices}
def get_player_input(self) -> PlayerInput: """"Get the current controls from the drone. :return: Current controls for this car. :rtype: PlayerInput """ # Throw error if no controls were set. if self.controller is None: RuntimeError(f"Did not set the controls for drone {self.index}") # PlayerInput mapping player_input = PlayerInput() player_input.throttle = self.controller.throttle # -1 for full reverse, 1 for full forward player_input.steer = self.controller.steer # -1 for full left, 1 for full right player_input.pitch = self.controller.pitch # -1 for nose down, 1 for nose up player_input.yaw = self.controller.yaw # -1 for full left, 1 for full right player_input.roll = self.controller.roll # -1 for roll left, 1 for roll right player_input.jump = self.controller.jump # true if you want to press the jump button player_input.boost = self.controller.boost # true if you want to press the boost button player_input.handbrake = self.controller.handbrake # true if you want to press the handbrake button return player_input
def initialize_hive(self, state: GameTickPacket) -> None: """Initializes the collection of bots (drones).""" self.enemy_indices = set(i for i in range(state.num_cars) if state.game_cars[i].team != self.team) self.drone_actions = {i: C.NOTHING for i in self.drone_indices} self.enemy_actions = {i: C.NOTHING for i in self.enemy_indices} self.controls = { i: PlayerInput(*self.drone_actions[i]) for i in self.drone_indices } self.scorer = Scorer() self.predictor = Predictor() self.stopped = False self.initial_states = [None] self.final_states = [] self.time = 0
def get_outputs(self, packet: GameTickPacket) -> Dict[int, PlayerInput]: # Calculate delta time and add to timer. game_time = packet.game_info.seconds_elapsed dt = game_time - self.last_time self.last_time = game_time self.timer += dt # Proclaim aliveness every three seconds. if self.timer > 3.0: self.logger.info(f'I am alive! Team: {self.team}') self.timer = 0.0 return { index: PlayerInput(throttle=1.0) for index in self.drone_indices }
def retire_agent(self, agent): # Shut down the bot by calling cleanup functions. if hasattr(agent, 'retire'): try: agent.retire() except Exception as e: self.logger.error("Retiring the agent failed:\n" + traceback.format_exc()) if hasattr(agent, 'renderer') and isinstance(agent.renderer, RenderingManager): agent.renderer.clear_all_touched_render_groups() # Zero out the inputs, so it's more obvious that the bot has stopped. self.game_interface.update_player_input(PlayerInput(), self.index) # Don't trust the agent to shut down its own client in retire(). if agent._matchcomms is not None: agent._matchcomms.close()
def start(self): self.game_interface.load_interface() controls = PlayerInput() last_time = time() while not self.quit_event.is_set(): current_time = time() if limit_hz and current_time - last_time < 1 / limit_hz: continue last_time = current_time # Get controls. for event in pygame.event.get(): if event.type == pygame.JOYAXISMOTION: self.axis_data[event.axis] = deadzone( event.value, transform=event.axis > 3 ) elif event.type == pygame.JOYBUTTONDOWN: self.button_data[event.button] = True if event.button == 4: self.recording = not self.recording elif event.type == pygame.JOYBUTTONUP: self.button_data[event.button] = False # Update controls. self.update_controls(controls) self.game_interface.update_player_input(controls, self.index) if not self.recording: # Dump. if len(self.recorded) > 0: self.dump() del self.recorded[:] # Clear. else: if len(self.recorded) == 0: self.recording_time = current_time print(current_time - self.recording_time) self.recorded.append( (current_time - self.recording_time, copy(controls)) )
def game_loop(self): """The main game loop. This is where your hivemind code goes.""" # Setting up rate limiter. rate_limit = rate_limiter.RateLimiter(120) # Setting up data. field_info = FieldInfoPacket() self.game_interface.update_field_info_packet(field_info) packet = GameTickPacket() self.game_interface.update_live_data_packet(packet) data.setup(self, packet, field_info, self.running_indices) self.ball.predict = BallPrediction() # MAIN LOOP: while True: # Updating the game packet from the game. self.game_interface.update_live_data_packet(packet) # Processing packet. data.process(self, packet) # Ball prediction. self.game_interface.update_ball_prediction(self.ball.predict) brain.think(self) for drone in self.drones: drone.ctrl = PlayerInput() if drone.role is not None: drone.role.execute(self, drone) self.game_interface.update_player_input( drone.ctrl, drone.index) self.draw_debug() # Rate limit sleep. rate_limit.acquire()
def __init__(self, index: int, packet: GameTickPacket = None): self.location: Vector3 = Vector3(0, 0, 0) self.orientation: Matrix3 = Matrix3(0, 0, 0) self.velocity: Vector3 = Vector3(0, 0, 0) self.angular_velocity: [] = [0, 0, 0] self.demolished: bool = False self.airborne: bool = False self.supersonic: bool = False self.jumped: bool = False self.doublejumped: bool = False self.team: int = 0 self.boost: float = 0 self.index: int = index self.controller: PlayerInput = PlayerInput() # A list that acts as the routines stack self.stack: [] = [] self.action: Action = Action.Shadowing self.on_side: bool = False self.closest: bool = False if packet is not None: self.team = packet.game_cars[self.index].team self.update(packet)
def prepare_for_run(self): # Set up shared memory map (offset makes it so bot only writes to its own input!) and map to buffer self.bot_input = PlayerInput() # Set up shared memory for game data self.game_tick_packet = gd.GameTickPacket( ) # We want to do a deep copy for game inputs so people don't mess with em
def run(self): """ Loads interface for RLBot, prepares environment and agent, and calls the update for the agent. """ self.logger.debug('initializing agent') self.game_interface.load_interface() self.prepare_for_run() # Create Ratelimiter rate_limit = rate_limiter.RateLimiter( GAME_TICK_PACKET_POLLS_PER_SECOND) last_tick_game_time = None # What the tick time of the last observed tick was last_call_real_time = datetime.now() # When we last called the Agent # Get bot module agent, agent_class_file = self.load_agent() last_module_modification_time = os.stat(agent_class_file).st_mtime # Run until main process tells to stop, or we detect Ctrl+C try: while not self.terminate_request_event.is_set(): self.pull_data_from_game() # game_tick_packet = self.game_interface.get # Read from game data shared memory # Run the Agent only if the game_info has updated. tick_game_time = self.get_game_time() should_call_while_paused = datetime.now( ) - last_call_real_time >= MAX_AGENT_CALL_PERIOD if tick_game_time != last_tick_game_time or should_call_while_paused: last_tick_game_time = tick_game_time last_call_real_time = datetime.now() # Reload the Agent if it has been modified or if reload is requested from outside. try: new_module_modification_time = os.stat( agent_class_file).st_mtime if new_module_modification_time != last_module_modification_time or self.reload_request_event.is_set( ): self.reload_request_event.clear() last_module_modification_time = new_module_modification_time agent, agent_class_file = self.reload_agent( agent, agent_class_file) except FileNotFoundError: self.logger.error( f"Agent file {agent_class_file} was not found. Will try again." ) time.sleep(0.5) except Exception: self.logger.error("Reloading the agent failed:\n" + traceback.format_exc()) time.sleep( 0.5 ) # Avoid burning CPU / logs if this starts happening constantly # Call agent try: self.call_agent( agent, self.agent_class_wrapper.get_loaded_class()) except Exception as e: self.logger.error("Call to agent failed:\n" + traceback.format_exc()) # Ratelimit here rate_limit.acquire() except KeyboardInterrupt: self.terminate_request_event.set() # Shut down the bot by calling cleanup functions. if hasattr(agent, 'retire'): try: agent.retire() except Exception as e: self.logger.error("Retiring the agent failed:\n" + traceback.format_exc()) if hasattr(agent, 'renderer') and isinstance(agent.renderer, RenderingManager): agent.renderer.clear_all_touched_render_groups() # Zero out the inputs, so it's more obvious that the bot has stopped. self.game_interface.update_player_input(PlayerInput(), self.index) # If terminated, send callback self.termination_complete_event.set()
def spawn_car_in_showroom(loadout_config: LoadoutConfig, team: int, showcase_type: str, map_name: str, launcher_prefs: RocketLeagueLauncherPreference): match_config = MatchConfig() match_config.game_mode = 'Soccer' match_config.game_map = map_name match_config.instant_start = True match_config.existing_match_behavior = 'Continue And Spawn' match_config.networking_role = NetworkingRole.none match_config.enable_state_setting = True match_config.skip_replays = True bot_config = PlayerConfig() bot_config.bot = True bot_config.rlbot_controlled = True bot_config.team = team bot_config.name = "Showroom" bot_config.loadout_config = loadout_config match_config.player_configs = [bot_config] match_config.mutators = MutatorConfig() match_config.mutators.boost_amount = 'Unlimited' match_config.mutators.match_length = 'Unlimited' global sm if sm is None: sm = SetupManager() sm.connect_to_game(launcher_preference=launcher_prefs) sm.load_match_config(match_config) sm.start_match() game_state = GameState( cars={0: CarState(physics=Physics( location=Vector3(0, 0, 20), velocity=Vector3(0, 0, 0), angular_velocity=Vector3(0, 0, 0), rotation=Rotator(0, 0, 0) ))}, ball=BallState(physics=Physics( location=Vector3(0, 0, -100), velocity=Vector3(0, 0, 0), angular_velocity=Vector3(0, 0, 0) )) ) player_input = PlayerInput() team_sign = -1 if team == 0 else 1 if showcase_type == "boost": player_input.boost = True player_input.steer = 1 game_state.cars[0].physics.location.y = -1140 game_state.cars[0].physics.velocity.x = 2300 game_state.cars[0].physics.angular_velocity.z = 3.5 elif showcase_type == "throttle": player_input.throttle = 1 player_input.steer = 0.56 game_state.cars[0].physics.location.y = -1140 game_state.cars[0].physics.velocity.x = 1410 game_state.cars[0].physics.angular_velocity.z = 1.5 elif showcase_type == "back-center-kickoff": game_state.cars[0].physics.location.y = 4608 * team_sign game_state.cars[0].physics.rotation.yaw = -0.5 * pi * team_sign elif showcase_type == "goal-explosion": game_state.cars[0].physics.location.y = -2000 * team_sign game_state.cars[0].physics.rotation.yaw = -0.5 * pi * team_sign game_state.cars[0].physics.velocity.y = -2300 * team_sign game_state.ball.physics.location = Vector3(0, -3500 * team_sign, 93) sm.game_interface.update_player_input(player_input, 0) sm.game_interface.set_game_state(game_state)
def game_loop(self): """The main game loop. This is where your hivemind code goes.""" # Creating packet and ball prediction objects which will be updated every tick. packet = GameTickPacket() ball_prediction = BallPrediction() # Nicknames the renderer to shorten code. draw = self.game_interface.renderer # MAIN LOOP: while True: previous_packet = packet # Updating the game tick packet. self.game_interface.update_live_data_packet(packet) # Checking if packet is new, otherwise sleep. if previous_packet.game_info.seconds_elapsed == packet.game_info.seconds_elapsed: time.sleep(0.001) else: # Begins rendering at the start of the loop; makes life easier. # https://discordapp.com/channels/348658686962696195/446761380654219264/610879527089864737 draw.begin_rendering(f'Hivemind{self.drones[0].team}') # PRE-PROCESSING: # Updates the ball prediction. self.game_interface.update_ball_prediction(ball_prediction) # Processing ball data. self.ball.pos = a3v(packet.game_ball.physics.location) # Processing drone data. for drone in self.drones: drone.pos = a3v(packet.game_cars[drone.index].physics.location) drone.rot = a3r(packet.game_cars[drone.index].physics.rotation) drone.vel = a3v(packet.game_cars[drone.index].physics.velocity) drone.boost = packet.game_cars[drone.index].boost drone.orient_m = orient_matrix(drone.rot) # Reset ctrl every tick. # PlayerInput is practically identical to SimpleControllerState. drone.ctrl = PlayerInput() # Game time. game_time = packet.game_info.seconds_elapsed # Example Team Pinches (2 bots only) # There's nothing stopping you from doing it with more ;) Give it a shot! if len(self.drones) == 2: # Sorts the drones left to right. (More understandble code below) #right_to_left_drones = sorted(self.drones, key=lambda drone: drone.pos[0]*team_sign(drone.team)) # Finds the right and left drones. sign = team_sign(self.drones[0].team) if self.drones[0].pos[0]*sign <= self.drones[1].pos[0]*sign: right = self.drones[0] left = self.drones[1] else: right = self.drones[1] left = self.drones[0] # Bots get boost and go to wait positions. if self.state == State.SETUP: # Some guide positions. right_boost = a3l([-3072.0, -4096.0, 71.1])*sign right_wait = a3l([-1792.0, -4184.0, 71.1])*sign # Making use of symmetry left_boost = right_boost * a3l([-1, 1, 1]) left_wait = right_wait * a3l([-1, 1, 1]) # First get boost and then go to wait position. if right.boost < 100: slow_to_pos(right, right_boost) else: slow_to_pos(right, right_wait) if left.boost < 100: slow_to_pos(left, left_boost) else: slow_to_pos(left, left_wait) # If both bots are in wait position, switch to WAIT state. if np.linalg.norm(right.pos-right_wait) + np.linalg.norm(left.pos-left_wait) < 200: self.state = State.WAIT # Bots try to face the ball, waiting for perfect moment to team pinch. elif self.state == State.WAIT: # Each drone should try to face the ball. for drone in self.drones: turn_to_pos(drone, self.ball.pos, game_time) # Filters out all the predictions where the ball is too far off the ground. # Result is a list of tuples of positions and time. filtered_prediction = [(a3v(step.physics.location), step.game_seconds) for step in ball_prediction.slices if step.physics.location.z < 100] if len(filtered_prediction) > 0: # Turns the predition into a numpy array for fast vectorized calculations. filtered_prediction = np.array(filtered_prediction) # Gets the vectors from the drones to the ball prediction. positions = np.vstack(filtered_prediction[:, 0]) right_to_prediction = positions - right.pos left_to_prediction = positions - left.pos # Calculates the distances. # Cool blog post about einsum: http://ajcr.net/Basic-guide-to-einsum/ right_distances = np.sqrt( np.einsum('ij,ij->i', right_to_prediction, right_to_prediction)) left_distances = np.sqrt( np.einsum('ij,ij->i', left_to_prediction, left_to_prediction)) # Filters out the predictions which are too close or too far. good_distances = (CLOSEST <= right_distances) & (FARTHEST >= right_distances) & ( CLOSEST <= left_distances) & (FARTHEST >= left_distances) valid_targets = filtered_prediction[good_distances] if len(valid_targets) > 0: # Getting the remaining distances after filter. right_distances = right_distances[good_distances] left_distances = left_distances[good_distances] # Getting time estimates to go that distance. (Assuming boosting, and going in a straight line.) # https://www.geogebra.org/m/nnsat4pj right_times = right_distances**0.55 / 41.53 right_times[right_distances > 2177.25] = 1/2300 * \ right_distances[right_distances > 2177.25] + 0.70337 right_times += game_time + TIME_BUFFER left_times = left_distances**0.55 / 41.53 left_times[left_distances > 2177.25] = 1/2300 * \ left_distances[left_distances > 2177.25] + 0.70337 left_times += game_time + TIME_BUFFER # Filters out the predictions which we can't get to. good_times = (valid_targets[:, 1] > right_times) & ( valid_targets[:, 1] > left_times) valid_targets = valid_targets[good_times] # To avoid flukes or anomalies, check that the ball is valid for at least 10 steps. # Not exact because there could be more bounce spots but good enough to avoid flukes. if len(valid_targets) > 10: # Select first valid target. self.pinch_target = valid_targets[0] # Reset drone's going attribute. right.going = False left.going = False # Set the state to PINCH. self.state = State.PINCH # Rendering number of positions viable after each condition. draw.draw_string_2d( 10, 70, 2, 2, f'Good height: {len(filtered_prediction)}', draw.white()) draw.draw_string_2d( 10, 100, 2, 2, f'Good distance: {len(valid_targets)}', draw.white()) # Render circles to show distances. draw.draw_polyline_3d(make_circle( CLOSEST, right.pos, 20), draw.cyan()) draw.draw_polyline_3d(make_circle( CLOSEST, left.pos, 20), draw.cyan()) draw.draw_polyline_3d(make_circle( FARTHEST, right.pos, 30), draw.pink()) draw.draw_polyline_3d(make_circle( FARTHEST, left.pos, 30), draw.pink()) elif self.state == State.PINCH: # Checks if the ball has been hit recently. if packet.game_ball.latest_touch.time_seconds + 0.1 > game_time: self.pinch_target = None self.state = State.SETUP elif self.pinch_target is not None: if not right.going: # Get the distance to the target. right_distance = np.linalg.norm( self.pinch_target[0] - right.pos) # Get a time estimate right_time = right_distance**0.55 / \ 41.53 if right_distance <= 2177.25 else 1/2300 * right_distance + 0.70337 # Waits until time is right to go. Otherwise turns to face the target position. if game_time + right_time + TIME_ERROR >= self.pinch_target[1]: right.going = True else: turn_to_pos( right, self.pinch_target[0], game_time) else: fast_to_pos(right, self.pinch_target[0]) # Same for left. if not left.going: left_distance = np.linalg.norm( self.pinch_target[0] - left.pos) left_time = left_distance**0.55 / \ 41.53 if left_distance <= 2177.25 else 1/2300 * left_distance + 0.70337 if game_time + left_time + TIME_ERROR >= self.pinch_target[1]: left.going = True else: turn_to_pos( left, self.pinch_target[0], game_time) else: fast_to_pos(left, self.pinch_target[0]) # Some rendering. draw.draw_string_2d( 10, 70, 2, 2, f'Right going: {right.going}', draw.white()) draw.draw_string_2d( 10, 100, 2, 2, f'Left going: {left.going}', draw.white()) else: draw.draw_string_2d( 10, 10, 2, 2, 'This example version has only been coded for 2 HiveBots.', draw.red()) # Use this to send the drone inputs to the drones. for drone in self.drones: self.game_interface.update_player_input( drone.ctrl, drone.index) # Some example rendering: draw.draw_string_2d(10, 10, 3, 3, f'{self.state}', draw.pink()) # Renders ball prediction path = [step.physics.location for step in ball_prediction.slices[::10]] draw.draw_polyline_3d(path, draw.pink()) # Renders drone indices. for drone in self.drones: draw.draw_string_3d(drone.pos, 1, 1, str( drone.index), draw.white()) # Team pinch info. if self.pinch_target is not None: draw.draw_rect_3d( self.pinch_target[0], 10, 10, True, draw.red()) # Ending rendering. draw.end_rendering()
def __init__(self): self.player_input = PlayerInput()