Пример #1
0
 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
Пример #2
0
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
Пример #3
0
 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)
Пример #4
0
 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
Пример #5
0
 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
Пример #6
0
 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
Пример #7
0
    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
        }
Пример #8
0
 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()
Пример #9
0
 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
Пример #10
0
    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()
Пример #11
0
    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}
Пример #12
0
    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
Пример #13
0
 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
Пример #14
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
        }
Пример #15
0
    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()
Пример #16
0
    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))
                )
Пример #17
0
    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()
Пример #18
0
 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)
Пример #19
0
 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
Пример #20
0
    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()
Пример #21
0
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)
Пример #22
0
    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()
Пример #23
0
 def __init__(self):
     self.player_input = PlayerInput()