Exemple #1
0
 def __init__(self, name, team, index):
     super().__init__(name, team, index)
     self.boost_pad_tracker = BoostPadTracker()
     self.previous_Goals = 0
     self.previous_my_Goals = 0
     self.previous_enemy_Goals = 0
     self.DDPG = None
Exemple #2
0
 def __init__(self, name, team, index):
     super().__init__(name, team, index)
     self.active_sequence: Sequence = None
     self.boost_pad_tracker = BoostPadTracker()
     self.airborne = False
     self.kickoff_active = True
     self.kickoff_position = None
Exemple #3
0
 def __init__(self, name, team, index):
     super().__init__(name, team, index) 
     self.action: Action = kickoff
     self.info : GameInfo = None
     self.car : Car = None
     self.boost_pad_tracker = BoostPadTracker()
     self.stat : Strategy = None
     self.action : Action = None
Exemple #4
0
    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()

        self.last_state = None
        self.agent = None
        self.env = None
        self.ac = None
        self.internals = None
Exemple #5
0
    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()

        self.controller_state = SimpleControllerState()
        self.me = Car()
        self.ball = Ball()
        self.kickoff_flag = False

        self.state = st.State()
        self.state_message = "State"
Exemple #6
0
    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()
        self.controls = SimpleControllerState()
        self.bot_car = None
        self.ball = None
        self.allies=[]
        self.foes=[]
        self.ball_prediction = None
        self.posts=((Vec3(893,-5120,0),Vec3(-893,-5120,0)),(Vec3(893,5120,0),Vec3(-893,5120,0)))
        self.back_corners=((Vec3(3672,-4096,0),Vec3(-3672,-4096,0)),(Vec3(3672,4096,0),Vec3(-3672,4096,0)))
        self.collision_posts=((Vec3(843,-5070,0),Vec3(-843,-5070,0)),(Vec3(843,5070,0),Vec3(-843,5070,0)))
        self.goal_corners=((Vec3(-893,-6000,0),Vec3(893,-5120,642.775)),(Vec3(-893,5120,0),Vec3(893,6000,642.775)))
        self.boxes=((Vec3(-1600,-6000,0),Vec3(1600,-4120,2044)),(Vec3(-1600,4120,0),Vec3(1600,6000,2044))) 

        self.defending = False
        self.rotating = False
        self.supporting = 0
        self.clearing = False
        self.shooting = False
        self.air_recovery = False
        self.current_strike = None
Exemple #7
0
class MyBot(BaseAgent):
    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()
        self.travel_distance = 0
        self.pos = Vec3(0, 0, 0)

    def initialize_agent(self):
        # Set up information about the boost pads now that the game is active and the info is available
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:

        self.boost_pad_tracker.update_boost_status(packet)

        if self.active_sequence is not None and not self.active_sequence.done:
            controls = self.active_sequence.tick(packet)
            if controls is not None:
                return controls

        def predict_ball(t):
            ball_in_future = find_slice_at_time(
                ball_prediction, packet.game_info.seconds_elapsed + t)
            if ball_in_future is not None:
                return ball_in_future
            else:
                return packet.game_ball

        def intersect_time(speed):
            best_spd = math.inf
            for i in range(1, 301):
                time_location = Vec3(predict_ball(i / 60).physics.location)
                if (time_location - car_location).length() * 60 / i <= speed:
                    return i / 60
            return 5

        my_car = packet.game_cars[self.index]
        car_location = Vec3(my_car.physics.location)
        car_velocity = Vec3(my_car.physics.velocity)
        ball_location = Vec3(packet.game_ball.physics.location)
        ball_location_gs = Vector3(packet.game_ball.physics.location)
        ball_velocity = Vec3(packet.game_ball.physics.velocity)
        ball_prediction = self.get_ball_prediction_struct()
        target_location = ball_location
        send_location = Vec3(0, 10240 * (0.5 - self.team), 300)
        if car_location.z == 0:
            self.pos = car_location

        self.renderer.draw_line_3d(self.pos, (target_location - self.pos) /
                                   (target_location - self.pos).length() *
                                   self.travel_distance, self.renderer.white())
        self.renderer.draw_string_3d(self.pos, 1, 1,
                                     f'Speed: {car_velocity.length():.1f}',
                                     self.renderer.white())
        self.renderer.draw_rect_3d(target_location,
                                   8,
                                   8,
                                   True,
                                   self.renderer.cyan(),
                                   centered=True)

        controls = SimpleControllerState()
        controls.steer = steer_toward_target(my_car, target_location)
        controls.throttle = 0
        if packet.game_info.is_round_active == True:
            self.travel_distance += 2300 / 60
        else:
            self.travel_distance = 0
        if (self.pos - ball_location).length(
        ) <= self.travel_distance and ball_location.y / send_location.y <= 1:
            ball_velout = -ball_velocity
            v = -(ball_location - send_location) / (
                ball_location - send_location).length() * 2300
            tp = (ball_velout + v) / (ball_velout + v).length() * 2300
            p = ball_location - tp / tp.length() * 100
            self.travel_distance = 0
            # Intentional weakness
            if random.random() <= 0.125:
                side = random.choice([1, -1])
                p = ball_location + Vec3(-v.x * side, 0,
                                         v.z * side) / 2300 * 150
                self.travel_distance = -11500
            car_state = CarState(
                physics=Physics(location=Vector3(p.x, p.y, p.z),
                                velocity=Vector3(v.x, v.y, v.z)))
            gs = GameState(cars={self.index: car_state})
            self.set_game_state(gs)
            self.pos = Vec3(packet.game_cars[self.index].physics.location)
        elif packet.game_info.is_round_active == True and self.travel_distance >= 0:
            p = self.pos + (ball_location - self.pos) / (
                ball_location - self.pos).length() * (self.travel_distance -
                                                      200)
            car_state = CarState(physics=Physics(
                location=Vector3(p.x, p.y, p.z), velocity=Vector3(0, 0, 0)))
            gs = GameState(cars={self.index: car_state})
            self.set_game_state(gs)
        else:
            self.pos = Vec3(packet.game_cars[self.index].physics.location)
        if packet.game_info.is_round_active == False:
            self.send_quick_chat(
                team_only=False,
                quick_chat=QuickChatSelection.Compliments_WhatASave)
        return controls
Exemple #8
0
class MyBot(BaseAgent):

    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()
        self.bot_state = 0


    def initialize_agent(self):
        # Set up information about the boost pads now that the game is active and the info is available
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        """
        This function will be called by the framework many times per second. This is where you can
        see the motion of the ball, etc. and return controls to drive your car.
        """

        # Keep our boost pad info updated with which pads are currently active
        self.boost_pad_tracker.update_boost_status(packet)

        # This is good to keep at the beginning of get_output. It will allow you to continue
        # any sequences that you may have started during a previous call to get_output.
        if self.active_sequence is not None and not self.active_sequence.done:
            controls = self.active_sequence.tick(packet)
            if controls is not None:
                return controls

        # Gather some information about our car and the ball
        my_car = packet.game_cars[self.index]
        car_location = Vec3(my_car.physics.location)
        car_velocity = Vec3(my_car.physics.velocity)
        ball_location = Vec3(packet.game_ball.physics.location)
        ball_velocity = Vec3(packet.game_ball.physics.velocity)

        # By default we will chase the ball, but target_location can be changed later
        target_location = ball_location
        ball_on_floor = target_location

        ball_prediction = self.get_ball_prediction_struct()  # This can predict bounces, etc
        # dynamic time to the ball depending on the car's speed
        time_in_future = self.time_to_ball(car_location, car_velocity.length(), ball_location)
        seconds_in_future = packet.game_info.seconds_elapsed + time_in_future
        ball_in_future = find_slice_at_time(ball_prediction, seconds_in_future)
        ball_on_floor = find_matching_slice(ball_prediction, 0, lambda s: s.physics.location.z < 150 and s.game_seconds >= packet.game_info.seconds_elapsed + time_in_future, search_increment=1)
        time_to_floor = 0

        # ball_in_future might be None if we don't have an adequate ball prediction right now, like during
        # replays, so check it to avoid errors.
        if ball_in_future is not None:
            target_location = Vec3(ball_in_future.physics.location)
            time_in_future = self.time_to_ball(car_location, car_velocity.length(), target_location)
            self.renderer.draw_line_3d(ball_location, target_location, self.renderer.cyan())

        # gets the next time when the ball is on the floor
        if ball_on_floor is not None:
            floor_location = Vec3(ball_on_floor.physics.location)
            time_to_floor = ball_on_floor.game_seconds - packet.game_info.seconds_elapsed
            self.renderer.draw_line_3d(ball_location, floor_location, self.renderer.orange())
            self.renderer.draw_rect_3d(floor_location, 8, 8, True, self.renderer.orange(), centered=True)

        # Draw some things to help understand what the bot is thinking
        self.renderer.draw_line_3d(car_location, target_location, self.renderer.white())
        self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)

        orientation = Orientation(my_car.physics.rotation)
        relative = relative_location(car_location, orientation, ball_location)

        controls = SimpleControllerState()

        self.renderer.draw_string_2d(10, 10 + self.team * 100, 5, 5, f"{controls.throttle}", self.renderer.team_color())

        # makes the car rotate to be more straight
        if not my_car.has_wheel_contact:
            # roll to land on all four wheels
            if orientation.roll < -0.1:
                controls.roll = 1
            elif orientation.roll > 0.1:
                controls.roll = -1

            # pitch to land on all four wheels
            if orientation.pitch < -0.1:
                controls.pitch = 1
            elif orientation.pitch > 0.1:
                controls.pitch = -1

            deg = math.degrees(car_location.ang_to(ball_location))

            # yaw to correct angle towards ball
            if deg < 85:
                controls.yaw = 1
            elif deg > 95:
                controls.yaw = -1

        # jump if another car is close to not get stuck
        if self.location_to_nearest_car(car_location, my_car.team, packet).dist(car_location) < 200 and car_velocity.length() < 50:
            controls.jump = True

        self.set_kickoff_state(car_velocity, ball_location, ball_velocity)

        self.decide_state(controls, packet, my_car, car_location, car_velocity, ball_location, ball_velocity, target_location, ball_prediction, orientation, relative, time_in_future, time_to_floor)

        return controls

    def decide_state(self, controls, packet, my_car, car_location, car_velocity, ball_location, ball_velocity, target_location, ball_prediction, orientation, relative, time_to_target, time_to_floor):
        if self.bot_state == 0:
            self.ball_chase(controls, packet, my_car, car_velocity, car_location, target_location, ball_location, relative, time_to_target, time_to_floor, orientation)
        elif self.bot_state == 1:
            self.retreat_to_goal(controls, packet, my_car, car_location, car_velocity)
        elif self.bot_state == 2:
            self.go_towards_own_goal(controls, my_car, car_location, ball_location)
        elif self.bot_state == 3:
            self.kickoff()

    def set_kickoff_state(self, car_velocity, ball_location, ball_velocity):
        if car_velocity.length() == 0 and ball_location.x == 0 and ball_location.y == 0 and ball_velocity.length() == 0:
            self.bot_state = 3

    def kickoff(self):
        self.bot_state = 0

    def ball_chase(self, controls, packet, my_car, car_velocity, car_location, target_location, ball_location, relative, time_to_target, time_to_floor, orientation):
        """
        Makes the bot chase the ball unless some conditions are valid
        """

        # retreat to own goal if the ball is a lot closer to our goal than we are
        info = self.get_field_info()
        own_goal_vec = info.goals[self.team].location
        own_goal_location = Vec3(own_goal_vec)

        if ball_location.dist(own_goal_location) + 1000 < car_location.dist(own_goal_location) and car_location.dist(own_goal_location) > 4000:
            self.bot_state = 1
        elif own_goal_vec.y > 5000 and car_location.y + 100 < target_location.y:  # BLUE
            self.bot_state = 2
        elif own_goal_vec.y < -5000 and car_location.y > target_location.y + 100:  # ORANGE
            self.bot_state = 2

        self.renderer.draw_string_3d(car_location, 1, 1, "\nBall chasing", self.renderer.red())

        # makes the bots shoot towards the goal
        target_location = self.ball_towards_goal_location(target_location, own_goal_location, car_location, ball_location)
        self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.red(), centered=True)
        self.renderer.draw_line_3d(car_location, target_location, self.renderer.red())

        controls.steer = steer_toward_target(my_car, target_location)
        controls.throttle = 1.0
        # You can set more controls if you want, like controls.boost.

        # angle to ball
        car_to_ball = Vec3(ball_location.x - car_location.x, ball_location.y - car_location.y, ball_location.z - car_location.z)
        angle = math.degrees(orientation.forward.ang_to(car_to_ball))

        # boost
        if angle < 20 and not my_car.is_super_sonic:
            controls.boost = True

        # try to turn around quickly
        if angle > 160 and relative.x < -2000:
            self.begin_half_flip(packet)
        elif angle > 40:
            controls.handbrake = True
        elif 1000 < car_velocity.length() and angle < 90 and car_to_ball.length() < 400 and relative.z < 200:
            # We'll do a front flip if the car is moving at a certain speed.
            return self.begin_front_flip(packet, angle, orientation.right.length())

    def drive_to_ball_bounce(self, my_car, car_location, floor_location):
        """
        Slowly drives to where the ball will bounce
        """
        pass

    def retreat_to_goal(self, controls, packet, my_car, car_location, car_velocity):
        """
        Makes the bot retreat back to the goal and only change back to another state when it's close to the goal
        """
        self.renderer.draw_string_3d(car_location, 1, 1, "\nRetreating to goal", self.renderer.red())
        info = self.get_field_info()
        own_goal_vec = info.goals[self.team].location
        own_goal_location = Vec3(own_goal_vec)
        controls.steer = steer_toward_target(my_car, own_goal_location)
        controls.throttle = 1.0

        if not my_car.is_super_sonic and car_velocity.length() > 200 and car_location.dist(own_goal_location) > 4500:
            controls.boost = True

        # change back to ball chasing if distance to goal is small
        self.renderer.draw_string_3d(car_location, 1, 1, f"\n\nDist to goal {car_location.dist(own_goal_location)}", self.renderer.white())
        if car_location.dist(own_goal_location) < 4000:
            self.bot_state = 0

    def go_towards_own_goal(self, controls, my_car, car_location, ball_location):
        """
        Goes towards own goal and changes back to ball chasing when a bit away from the ball
        """
        self.renderer.draw_string_3d(car_location, 1, 1, "\nGoing towards own goal", self.renderer.red())
        info = self.get_field_info()
        own_goal_vec = info.goals[self.team].location
        own_goal_location = Vec3(own_goal_vec)
        controls.steer = steer_toward_target(my_car, own_goal_location)
        controls.throttle = 1.0

        # goes back to ball chase state if far enough away from the ball
        if car_location.dist(ball_location) > 1000 or car_location.dist(own_goal_location) < 4000:
            self.bot_state = 0

    def jump_shot(self, controls, car_location, ball_location):
        pass

    def ball_towards_goal_location(self, target_location, goal_location, car_location, ball_location):
        """
        Modifies the target location so that the ball is hit a bit more towards the enemy goal
        """
        enemy_goal_location = Vec3(0, -goal_location.y, goal_location.z)

        if target_location.x - enemy_goal_location.x == 0:
            target_location.x = 1
            if goal_location.y < 0:  # usually for blue side
                target_location.x = -1
        slope = (target_location.y - enemy_goal_location.y) / (target_location.x - enemy_goal_location.x)

        dist = car_location.dist(target_location)
        if dist > 3000:
            correction = 1000
        elif 500 < dist <= 3000:
            correction = 0.36 * dist - 80
        else:
            correction = 100

        x_value = 1
        if target_location.x < 0:
            x_value = -1

        new_target_location = Vec3(1, slope, 0).normalized()
        return target_location + x_value * correction * new_target_location

    def location_to_nearest_car(self, car_location, team, packet, enemy=False):
        """
        Gets the closest enemy car to a target location
        """

        # If enemy is true, only view nearest enemy cars
        nearest_distance = 999999
        nearest_car = None
        for car in packet.game_cars:
            if car.team == team:
                continue
            other_car = Vec3(car.physics.location)
            distance_to = car_location.dist(other_car)
            if distance_to < nearest_distance:
                nearest_distance = distance_to
                nearest_car = other_car
        return nearest_car

    def time_to_ball(self, car_location, car_speed, ball_location):
        # estimates a time it takes for the bot to reach the ball for it to better predict where to go to hit the ball
        distance = car_location.dist(ball_location)
        return distance/(car_speed+100)

    def begin_half_flip(self, packet):
        self.active_sequence = Sequence([
            ControlStep(duration=1.0, controls=SimpleControllerState(throttle=-1, boost=False)),
            ControlStep(duration=0.1, controls=SimpleControllerState(jump=True)),
            ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)),
            ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, pitch=1)),
            ControlStep(duration=0.15, controls=SimpleControllerState(pitch=-1, boost=False)),
            ControlStep(duration=0.5, controls=SimpleControllerState(pitch=-1, boost=True, roll=1, throttle=1)),
            ControlStep(duration=0.5, controls=SimpleControllerState()),
        ])

        return self.active_sequence.tick(packet)

    def begin_front_flip(self, packet, angle=0.0, right=1):
        # Do a flip. We will be committed to this for a few seconds and the bot will ignore other
        # logic during that time because we are setting the active_sequence.
        mult = 1
        if right < 0:
            mult = -1
        rad = math.radians(0)  # set to 0 for now
        self.active_sequence = Sequence([
            ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)),
            ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)),
            ControlStep(duration=0.1, controls=SimpleControllerState(jump=True, pitch=-math.cos(rad), yaw=mult * math.sin(rad))),
            ControlStep(duration=0.8, controls=SimpleControllerState()),
        ])

        # Return the controls associated with the beginning of the sequence so we can start right away.
        return self.active_sequence.tick(packet)
Exemple #9
0
class MyBot(BaseAgent):


    def __init__(self, name, team, index):
        super().__init__(name, team, index) 
        self.action: Action = kickoff
        self.info : GameInfo = None
        self.car : Car = None
        self.boost_pad_tracker = BoostPadTracker()
        self.stat : Strategy = None
        self.action : Action = None

    def initialize_agent(self):
        # Set up information about the boost pads now that the game is active and the info is available
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())
        self.info = MyInfo(self.team, self.index)
        self.strat = Strategy(self.info)
        self.car = Car()

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        """
        This function will be called by the framework many times per second. This is where you can
        see the motion of the ball, etc. and return controls to drive your car.
        """

        # Keep our boost pad info updated with which pads are currently active
        self.boost_pad_tracker.update_boost_status(packet)
        #self.info = self.info.read_packet(packet)  
        self.car.updateCar(packet, self.index)
        self.info.read_packet(packet, self.get_ball_prediction_struct().slices)
        #print("in main target: {}".format(self.get_ball_prediction_struct().slices[0].physics.location))
        #self.renderer.draw_line_3d(self.car.loc, target_location, self.renderer.white())
        #self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
       
        #cg = ChallengeGame(self.car, bp_struct)
        
        #print(cg.get_time_to_loc(cg.challenge_loc))
        # This is good to keep at the beginning of get_output. It will allow you to continue
        # any sequences that you may have started during a previous call to get_output.
        if self.action is None:
            self.action = self.strat.chooseAction(self.info)
            
            controls = self.action.tick(self.info)
            print(controls.steer)
            return controls
        

        self.renderer.draw_string_3d(self.car.loc, 1, 1, f'Speed: {self.car.vel.length():.1f}', self.renderer.white())
        if self.action.name:
            self.renderer.draw_string_3d(self.car.loc + Vec3(0, 0, 20), 1, 1, self.action.name, self.renderer.white())
        

        if packet.game_info.is_kickoff_pause and not isinstance(self.action, kickoff):
            #self.logger.info(self.action)
            self.action = kickoff(self.car.loc)
            #print("Sequence is: {}".format(self.action))
            #print("Sequence finished: {}".format(self.action.done))
            controls = self.action.tick(self.info)
            return controls
        
        if self.action and not self.action.done:
            controls = self.action.tick(self.info)
            #print("action is: {}".format(self.action.name))
            if controls is not None:
                return controls
        
        elif self.action.done:
            print("choosing new action")
            
            self.action = self.strat.chooseAction(self.info)
            controls = self.action.tick(self.info)
            return controls

        # Gather some information about our car and the ball
        ball_location = Vec3(packet.game_ball.physics.location)

        if self.car.loc.dist(ball_location) > 1500:
            # We're far away from the ball, let's try to lead it a little bit
            ball_prediction = self.get_ball_prediction_struct()  # This can predict bounces, etc
            ball_in_future = find_slice_at_time(ball_prediction, packet.game_info.seconds_elapsed + 2)
            target_location = Vec3(ball_in_future.physics.location)
            self.renderer.draw_line_3d(ball_location, target_location, self.renderer.cyan())
        else:
            target_location = ball_location

        # Draw some things to help understand what the bot is thinking
         #self.renderer.draw_string_2d(100, 100, 1, 1, f'Ball at: {ball_location}', self.renderer.white())

        '''
        if 750 < self.car.vel.length()  < 800:
            # We'll do a front flip if the car is moving at a certain speed.
            return self.begin_front_flip(packet)
        
        #controls = self.action.controls
        controls = SimpleControllerState()
        controls.steer = steer_toward_target(self.car, target_location)
        controls.throttle = 1.0
        # You can set more controls if you want, like controls.boost.
        '''
        print("the f**k we doin here?!?!?!?")
        return controls

    def begin_front_flip(self, packet):
        # Send some quickchat just for fun
        self.send_quick_chat(team_only=False, quick_chat=QuickChatSelection.Information_IGotIt)

        # Do a front flip. We will be committed to this for a few seconds and the bot will ignore other
        # logic during that time because we are setting the action.
        self.action = Sequence([
            ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)),
            ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)),
            ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, pitch=-1)),
            ControlStep(duration=0.8, controls=SimpleControllerState()),
        ])

        # Return the controls associated with the beginning of the sequence so we can start right away.
        return self.action.tick(packet)

    def is_kickoff(self, ball_location, ball_velocity):
        #self.logger.info(ball_location.flat() == kickoff_location)
        #self.logger.info(ball_velocity.length() == 0)
        return ball_location.flat() == kickoff_location and ball_velocity.length() == 0
Exemple #10
0
class MyBot(BaseAgent):
    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()
        self.airborne = False
        self.kickoff_active = True
        self.kickoff_position = None

    def initialize_agent(self):
        # Set up information about the boost pads now that the game is active and the info is available
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        """
        This function will be called by the framework many times per second. This is where you can
        see the motion of the ball, etc. and return controls to drive your car.
        """

        # Keep our boost pad info updated with which pads are currently active
        self.boost_pad_tracker.update_boost_status(packet)

        # This is good to keep at the beginning of get_output. It will allow you to continue
        # any sequences that you may have started during a previous call to get_output.
        if self.active_sequence and not self.active_sequence.done:
            controls = self.active_sequence.tick(packet)
            if controls is not None:
                return controls

        # Gather some information about our car and the ball
        my_car = packet.game_cars[self.index]
        car_location = Vec3(my_car.physics.location)
        car_velocity = Vec3(my_car.physics.velocity)
        ball_location = Vec3(packet.game_ball.physics.location)

        if my_car.team == 1:  # Orange Team
            self.my_goal_right_post = Vec3(850, 5100, 320)
            self.my_goal_center = Vec3(0, 5100, 320)
            self.my_goal_left_post = Vec3(-850, 5100, 320)
            self.enemy_goal_right_post = Vec3(850, -5100, 320)
            self.enemy_goal_center = Vec3(0.0, -5100, 320)
            self.enemy_goal_left_post = Vec3(-850, -5100, 320)
        else:  # Blue Team
            self.my_goal_right_post = Vec3(-850, -5100, 320)
            self.my_goal_center = Vec3(0.0, -5100, 320)
            self.my_goal_left_post = Vec3(850, -5100, 320)
            self.enemy_goal_right_post = Vec3(-850, 5100, 320)
            self.enemy_goal_center = Vec3(0, 5100, 320)
            self.enemy_goal_left_post = Vec3(850, 5100, 320)

        controls = SimpleControllerState()

        # Draw some things to help understand what the bot is thinking
        # self.renderer.draw_line_3d(car_location, target_location, self.renderer.white())
        # self.renderer.draw_string_3d(car_location, 1, 1, f'Speed: {car_velocity.length():.1f}', self.renderer.white())
        # self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)

        # Important flags to check / set
        if my_car.has_wheel_contact == True:
            self.airborne = False
        else:
            # try to recover here
            if self.airborne == False:
                self.send_quick_chat(
                    team_only=False,
                    quick_chat=QuickChatSelection.Custom_Useful_Faking)

            self.airborne = True

        if self.ball_in_kickoff_position(ball_location, packet):
            self.kickoff_active = True
        else:
            self.kickoff_active = False
            self.kickoff_position = None

        if self.kickoff_active and self.kickoff_position is None:
            self.kickoff_position = self.get_kickoff_position(car_location)

        # Main state checking area
        if self.kickoff_active and self.kickoff_position is not None:
            self.do_kickoff(my_car, car_location, car_velocity, ball_location,
                            controls, packet)
        else:
            self.ball_chase(controls, my_car, car_location, car_velocity,
                            ball_location, packet)

        # Other things that have been written:
        # self.boost_steal(controls, car_location, my_car, ball_location)
        # self.half_flip_sequence(packet)
        # self.manage_speed(packet, controls, my_car, car_velocity)

        return controls

    def get_kickoff_position(self, car_location):
        if car_location.flat().dist(Vec3(
                2048.00, -2560.00)) < 50 or car_location.flat().dist(
                    Vec3(-2048.00, 2560.00)) < 50:
            return 1
        elif car_location.flat().dist(Vec3(
                -2048.00, -2560.00)) < 50 or car_location.flat().dist(
                    Vec3(2048.00, 2560.00)) < 50:
            return 2
        elif car_location.flat().dist(Vec3(
                256.00, -3840.00)) < 50 or car_location.flat().dist(
                    Vec3(-256.00, 3840.00)) < 50:
            return 3
        elif car_location.flat().dist(Vec3(
                -256.00, -3840.00)) < 50 or car_location.flat().dist(
                    Vec3(256.00, 3840.00)) < 50:
            return 4
        else:
            return 5

    def ball_in_kickoff_position(self, ball_location, packet):
        if ball_location.x == 0 \
            and ball_location.y == 0 \
            and packet.game_ball.physics.velocity.x == 0 \
            and packet.game_ball.physics.velocity.y == 0 \
            and packet.game_ball.physics.velocity.z == 0:
            return True
        else:
            return False

    def do_kickoff(self, my_car, car_location, car_velocity, ball_location,
                   controls, packet):
        self.send_quick_chat(
            team_only=False,
            quick_chat=QuickChatSelection.Information_Incoming)

        print(f"kickoff position {self.kickoff_position}")

        # if self.kickoff_position == 1:
        #     self.left_speed_flip_kickoff(packet)
        # elif self.kickoff_position == 2:
        #     self.right_speed_flip_kickoff(packet)
        # elif self.kickoff_position == 3:
        #     self.left_diagonal_flip_kickoff(packet, ball_location)
        # else:
        self.send_quick_chat(team_only=False,
                             quick_chat=QuickChatSelection.Reactions_HolyCow)
        self.front_flip_kickoff(my_car, car_location, car_velocity,
                                ball_location, controls, packet)

    def ball_chase(self, controls, my_car, car_location, car_velocity,
                   ball_location, packet):
        if car_location.dist(ball_location) > 1500:
            # We're far away from the ball, let's try to lead it a little bit
            ball_prediction = self.get_ball_prediction_struct(
            )  # This can predict bounces, etc
            ball_in_future = find_slice_at_time(
                ball_prediction, packet.game_info.seconds_elapsed + 2)
            target_location = Vec3(ball_in_future.physics.location)
            self.renderer.draw_line_3d(ball_location, target_location,
                                       self.renderer.cyan())
        else:
            target_location = ball_location

        controls.steer = steer_toward_target(my_car, ball_location)
        controls.throttle = 1.0
        self.manage_speed(packet, controls, my_car, car_velocity)

    def half_flip_sequence(self, packet):
        self.active_sequence = Sequence([
            ControlStep(duration=0.3,
                        controls=SimpleControllerState(throttle=-1)),
            ControlStep(duration=0.1,
                        controls=SimpleControllerState(throttle=-1,
                                                       jump=True,
                                                       pitch=1)),
            ControlStep(duration=0.2,
                        controls=SimpleControllerState(throttle=-1,
                                                       jump=False,
                                                       pitch=1)),
            ControlStep(duration=0.1,
                        controls=SimpleControllerState(jump=True, pitch=1)),
            ControlStep(duration=0.1,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=True,
                                                       pitch=-1)),
            ControlStep(duration=0.5,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=True,
                                                       pitch=-1,
                                                       roll=1)),
            ControlStep(duration=0.2, controls=SimpleControllerState(roll=0)),
            ControlStep(duration=0.5,
                        controls=SimpleControllerState(throttle=1)),
        ])

        return self.active_sequence.tick(packet)

    def left_speed_flip_kickoff(self, packet):
        print("left speed flip")

        self.active_sequence = Sequence([
            ControlStep(duration=.4,
                        controls=SimpleControllerState(throttle=1, boost=1)),
            ControlStep(duration=.1,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=1,
                                                       steer=.75)),
            ControlStep(duration=.05,
                        controls=SimpleControllerState(jump=True,
                                                       yaw=1,
                                                       boost=1)),
            ControlStep(duration=.05,
                        controls=SimpleControllerState(yaw=-1,
                                                       pitch=-1,
                                                       boost=1)),
            ControlStep(duration=.05,
                        controls=SimpleControllerState(jump=True,
                                                       yaw=-1,
                                                       pitch=-1)),
            ControlStep(duration=.5,
                        controls=SimpleControllerState(yaw=1, pitch=1,
                                                       roll=-1)),
            ControlStep(duration=.25,
                        controls=SimpleControllerState(roll=-1, boost=1,
                                                       yaw=1)),
            ControlStep(duration=.5,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=1,
                                                       handbrake=True)),
            ControlStep(duration=.5,
                        controls=SimpleControllerState(throttle=1, boost=1)),
            ControlStep(duration=3,
                        controls=SimpleControllerState(throttle=1)),
        ])

        return self.active_sequence.tick(packet)

    def right_speed_flip_kickoff(self, packet):
        print("right speed flip")

        self.active_sequence = Sequence([
            ControlStep(duration=.4,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=True)),
            ControlStep(duration=.2,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=True,
                                                       steer=.75)),
            ControlStep(duration=.05,
                        controls=SimpleControllerState(jump=True,
                                                       yaw=1,
                                                       boost=True)),
            ControlStep(duration=.05,
                        controls=SimpleControllerState(yaw=-1,
                                                       pitch=-1,
                                                       boost=True)),
            ControlStep(duration=.05,
                        controls=SimpleControllerState(jump=True,
                                                       yaw=-1,
                                                       pitch=-1)),
            ControlStep(duration=.5,
                        controls=SimpleControllerState(yaw=1, pitch=1,
                                                       roll=-1)),
            ControlStep(duration=.25,
                        controls=SimpleControllerState(roll=-1,
                                                       boost=True,
                                                       yaw=1)),
            ControlStep(duration=.25,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=True,
                                                       handbrake=True)),
            ControlStep(duration=3,
                        controls=SimpleControllerState(throttle=1)),
        ])

        return self.active_sequence.tick(packet)

    def left_diagonal_flip_kickoff(self, packet, ball_location):
        print("left diagonal kickoff")

        self.active_sequence = Sequence([
            ControlStep(duration=.2,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=True)),
            ControlStep(duration=.3,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=1,
                                                       steer=1)),
            ControlStep(duration=.15,
                        controls=SimpleControllerState(throttle=1,
                                                       boost=1,
                                                       steer=-1)),
            ControlStep(duration=.05,
                        controls=SimpleControllerState(jump=True,
                                                       yaw=-1,
                                                       boost=True)),
            ControlStep(duration=.05,
                        controls=SimpleControllerState(yaw=-1, boost=True)),
            ControlStep(duration=.05,
                        controls=SimpleControllerState(jump=True,
                                                       yaw=-1,
                                                       boost=True)),
        ])

        return self.active_sequence.tick(packet)

    def front_flip_kickoff(self, my_car, car_location, car_velocity,
                           ball_location, controls, packet):
        self.send_quick_chat(
            team_only=False,
            quick_chat=QuickChatSelection.Information_Incoming)
        controls.steer = steer_toward_target(my_car, ball_location)
        controls.throttle = 1.0
        controls.boost = True

        distance_from_ball = car_location.dist(ball_location)

        # tweak these settings so the first and second flips go off at the right time
        if 750 < car_velocity.length() < 900:
            self.begin_front_flip(packet)

        if distance_from_ball <= 1000:
            self.begin_front_flip(packet)

    def boost_steal(self, controls, car_location, my_car, ball_location):
        active_boosts = [
            boost for boost in self.boost_pad_tracker.get_full_boosts()
            if boost.is_active == True
        ]
        car_x = int(car_location.x)
        car_y = int(car_location.y)

        boost_distances = []

        for boost in active_boosts:
            boost_x = int(boost.location.x)
            boost_y = int(boost.location.y)

            distance_from_boost = abs(boost_x - car_x) + abs(boost_y - car_y)
            boost_distances.append(distance_from_boost)

        if len(active_boosts) == 0:
            controls.steer = steer_toward_target(my_car, ball_location)
            controls.throttle = 1.0
        else:
            boost_index = boost_distances.index(min(boost_distances))
            boost_location = active_boosts[boost_index].location

            controls.steer = steer_toward_target(my_car, boost_location)
            controls.throttle = 1.0

    def begin_front_flip(self, packet):
        # Send some quickchat just for fun
        self.send_quick_chat(team_only=False,
                             quick_chat=QuickChatSelection.Information_IGotIt)

        # Do a front flip. We will be committed to this for a few seconds and the bot will ignore other
        # logic during that time because we are setting the active_sequence.
        self.active_sequence = Sequence([
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=True)),
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=False)),
            ControlStep(duration=0.2,
                        controls=SimpleControllerState(jump=True, pitch=-1)),
            ControlStep(duration=0.8, controls=SimpleControllerState()),
        ])

        # Return the controls associated with the beginning of the sequence so we can start right away.
        return self.active_sequence.tick(packet)

    def manage_speed(self, packet, controls, my_car, car_velocity):
        if 750 < car_velocity.length() < 800:
            # We'll do a front flip if the car is moving at a certain speed.
            # Note: maybe do a diagonal / sideflip again? We should also only conditionally flip
            #  since getting caught mid flip is bad, this would also be cool as a wavedash
            return self.begin_front_flip(packet)

        if my_car.is_super_sonic == False:
            controls.boost = True

        if my_car.boost == 100:
            controls.boost = True
Exemple #11
0
class MyBot(BaseAgent):

    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()

    def initialize_agent(self):
        # Set up information about the boost pads now that the game is active and the info is available
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        """
        This function will be called by the framework many times per second. This is where you can
        see the motion of the ball, etc. and return controls to drive your car.
        """

        # Keep our boost pad info updated with which pads are currently active
        self.boost_pad_tracker.update_boost_status(packet)

        # This is good to keep at the beginning of get_output. It will allow you to continue
        # any sequences that you may have started during a previous call to get_output.
        if self.active_sequence is not None and not self.active_sequence.done:
            controls = self.active_sequence.tick(packet)
            if controls is not None:
                return controls

        # Gather some information about our car and the ball
        my_car = packet.game_cars[self.index]
        car_location = Vec3(my_car.physics.location)
        car_velocity = Vec3(my_car.physics.velocity)
        ball_location = Vec3(packet.game_ball.physics.location)

        # By default we will chase the ball, but target_location can be changed later
        target_location = ball_location

        if car_location.dist(ball_location) > 1500:
            # We're far away from the ball, let's try to lead it a little bit
            ball_prediction = self.get_ball_prediction_struct()  # This can predict bounces, etc
            ball_in_future = find_slice_at_time(ball_prediction, packet.game_info.seconds_elapsed + 2)

            # ball_in_future might be None if we don't have an adequate ball prediction right now, like during
            # replays, so check it to avoid errors.
            if ball_in_future is not None:
                target_location = Vec3(ball_in_future.physics.location)
                self.renderer.draw_line_3d(ball_location, target_location, self.renderer.cyan())

        # Draw some things to help understand what the bot is thinking
        self.renderer.draw_line_3d(car_location, target_location, self.renderer.white())
        self.renderer.draw_string_3d(car_location, 1, 1, f'Speed: {car_velocity.length():.1f}', self.renderer.white())
        self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)

        if 750 < car_velocity.length() < 800:
            # We'll do a front flip if the car is moving at a certain speed.
            return self.begin_front_flip(packet)

        controls = SimpleControllerState()
        controls.steer = steer_toward_target(my_car, target_location)
        controls.throttle = 1.0
        # You can set more controls if you want, like controls.boost.

        return controls

    def begin_front_flip(self, packet):
        # Send some quickchat just for fun
        self.send_quick_chat(team_only=False, quick_chat=QuickChatSelection.Information_IGotIt)

        # Do a front flip. We will be committed to this for a few seconds and the bot will ignore other
        # logic during that time because we are setting the active_sequence.
        self.active_sequence = Sequence([
            ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)),
            ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)),
            ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, pitch=-1)),
            ControlStep(duration=0.8, controls=SimpleControllerState()),
        ])

        # Return the controls associated with the beginning of the sequence so we can start right away.
        return self.active_sequence.tick(packet)
Exemple #12
0
class MyBot(BaseAgent):
    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()

        self.last_state = None
        self.agent = None
        self.env = None
        self.ac = None
        self.internals = None

    def initialize_agent(self):
        # Set up information about the boost pads now that the game is active and the info is available
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())
        if MODEL is not None:
            max_time = 10
            frames_per_sec = 20
            max_timesteps = RLEnvironment.get_max_timesteps(max_time, frames_per_sec)
            self.env = Environment.create(
                environment=KickoffEnvironment,
                max_episode_timesteps=max_timesteps,
                max_time=max_time,
                message_throttle=20,
                frames_per_sec=frames_per_sec,
                input_exclude=[
                    InputOptions.BALL_POSITION_REL,
                    InputOptions.BALL_DIRECTION,
                    InputOptions.CAR_POSITION_REL,
                    InputOptions.CAR_VELOCITY_MAG,
                ],
                output_exclude=[
                    OutputOptions.BOOST,
                    OutputOptions.STEER,
                    OutputOptions.E_BRAKE,
                    OutputOptions.THROTTLE,
                    OutputOptions.ROLL,
                ]
            )

            directory='../learning/training/{0}'.format(MODEL)
            filename='agent'
            agent = os.path.join(directory, os.path.splitext(filename)[0] + '.json') 

            if not os.path.isfile(agent):
                logging_utils.log_warn(os.getcwd(), {})
                raise Exception('Model file doesn\'t exist')
            
            self.agent = Agent.load(
                directory=os.path.abspath(directory),
                environment=self.env,
                format='checkpoint',
            )
            self.env.reset()

    def render(self, packet):
        # Gather some information about our car and the ball
        my_car = packet.game_cars[self.index]
        car_location = Vec3(my_car.physics.location)
        car_velocity = Vec3(my_car.physics.velocity)
        ball_location = Vec3(packet.game_ball.physics.location)

        # By default we will chase the ball, but target_location can be changed later
        target_location = ball_location

        if car_location.dist(ball_location) > 1500:
            # We're far away from the ball, let's try to lead it a little bit
            ball_prediction = self.get_ball_prediction_struct()  # This can predict bounces, etc
            ball_in_future = find_slice_at_time(ball_prediction, packet.game_info.seconds_elapsed + 2)

            # ball_in_future might be None if we don't have an adequate ball prediction right now, like during
            # replays, so check it to avoid errors.
            if ball_in_future is not None:
                target_location = Vec3(ball_in_future.physics.location)
                self.renderer.draw_line_3d(ball_location, target_location, self.renderer.cyan())

        # Draw some things to help understand what the bot is thinking
        self.renderer.draw_line_3d(car_location, target_location, self.renderer.white())
        self.renderer.draw_string_3d(car_location, 1, 1, f'Speed: {car_velocity.length():.1f}', self.renderer.white())
        self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)


    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        """
        This function will be called by the framework many times per second. This is where you can
        see the motion of the ball, etc. and return controls to drive your car.
        """

        # Keep our boost pad info updated with which pads are currently active
        self.boost_pad_tracker.update_boost_status(packet)

        # This is good to keep at the beginning of get_output. It will allow you to continue
        # any sequences that you may have started during a previous call to get_output.
        if self.active_sequence is not None and not self.active_sequence.done:
            controls = self.active_sequence.tick(packet)
            if controls is not None:
                return controls

        self.render(packet)

        my_car = packet.game_cars[self.index]
        my_car = packet.game_cars[self.index]
        car_location = Vec3(my_car.physics.location)
        car_velocity = Vec3(my_car.physics.velocity)
        ball_location = Vec3(packet.game_ball.physics.location)
        target_location = ball_location

        if car_location.dist(ball_location) > 1500:
            ball_prediction = self.get_ball_prediction_struct()
            ball_in_future = find_slice_at_time(ball_prediction, packet.game_info.seconds_elapsed + 2)

            if ball_in_future is not None:
                target_location = Vec3(ball_in_future.physics.location)

        # Drive at ball
        controls = self.last_state or SimpleControllerState(throttle=1)
        # controls.steer = steer_toward_target(my_car, target_location)

        self.set_controls_from_model(packet, controls)

        self.last_state = controls

        return controls

    def set_controls_from_model(self, tick, controls):
        actions = self.get_actions(tick)

        if (len(actions) > 1):
            controls.throttle = actions[OutputOptions.THROTTLE][0] - 1 if OutputOptions.THROTTLE in actions else controls.throttle
            controls.pitch = actions[OutputOptions.PITCH][0] - 1 if OutputOptions.PITCH in actions else controls.pitch
            controls.roll = actions[OutputOptions.ROLL][0] - 1 if OutputOptions.ROLL in actions else controls.roll
            controls.yaw = actions[OutputOptions.STEER][0] - 1 if OutputOptions.STEER in actions else controls.yaw
            controls.steer = actions[OutputOptions.STEER][0] - 1 if OutputOptions.STEER in actions else controls.steer
            controls.boost = actions[OutputOptions.BOOST][0] if OutputOptions.BOOST in actions else controls.boost
            controls.jump = actions[OutputOptions.JUMP][0] if OutputOptions.JUMP in actions else controls.jump
            controls.handbrake = actions[OutputOptions.E_BRAKE][0] if OutputOptions.E_BRAKE in actions else controls.handbrake

        return controls

    def get_actions(self, tick):
        actions = {}
        if self.env is not None and self.env.update_throttle(tick):
            states = self.env.setRLState(tick)
            actions = self.agent.act(states)
            states, terminal, reward = self.env.execute(actions=actions)
            self.agent.observe(terminal=terminal, reward=reward)
            if terminal: self.env.reset()
        else:
            try:
                actions = self.matchcomms.incoming_broadcast.get(block=False)
            except Empty:
                pass
        return actions
Exemple #13
0
class MyBot(BaseAgent):

    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.boost_pad_tracker = BoostPadTracker()
        self.previous_Goals = 0
        self.previous_my_Goals = 0
        self.previous_enemy_Goals = 0
        self.DDPG = None
    def initialize_agent(self):
        # Set up information about the boost pads now that the game is active and the info is available
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())


    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        """
        This function will be called by the framework many times per second. This is where you can
        see the motion of the ball, etc. and return controls to drive your car.
        """

        # Keep our boost pad info updated with which pads are currently active
        self.boost_pad_tracker.update_boost_status(packet)

        # Gather some information about our car and the ball
        my_car = packet.game_cars[self.index]

        if self.team == 0:
            goal_location = np.array((0, 5213, 321.3875))
        else:
            goal_location = np.array((0, -5213, 321.3875))
        def dictToArr(d):
            return np.array((d.x,d.y,d.z))
        field_length = 10426
        max_velocity = 1000
        ball_velocity = dictToArr(packet.game_ball.physics.velocity)
        car_location = dictToArr(my_car.physics.location)
        car_velocity = dictToArr(my_car.physics.velocity)
        ball_location = dictToArr(packet.game_ball.physics.location)
        car_ball = ball_location - car_location
        ball_goal = goal_location - ball_location
        
        my_Goals = packet.teams[self.team].score
        enemy_goals = packet.teams[1-self.team].score
        current_Goals =  my_Goals+enemy_goals
        print("velocity: ", car_velocity, end = " ")
        state = np.concatenate((car_ball[:2]/field_length,ball_goal[:2]/field_length,car_velocity[:2]/max_velocity,ball_velocity[:2]/max_velocity))

        if self.DDPG is None:
            self.DDPG = DDPG(state)
        reward = 0.0

        #denom = np.linalg.norm(ball_goal) * np.linalg.norm(ball_velocity) 
        #if denom != 0:
        reward += np.dot(ball_goal, ball_velocity)
            #np.arccos(np.dot(ball_goal, ball_velocity)/denom)

        #denom = np.linalg.norm(car_ball) * np.linalg.norm(car_velocity)

        #if denom != 0:
        reward += np.dot(car_ball, car_velocity)

            #100*np.arccos(np.dot(car_ball, car_velocity)/denom)
        
        #if denom != 0:
        #reward += 2000/np.linalg.norm(car_ball)


        if my_Goals != self.previous_my_Goals:
            reward = 1000
        if enemy_goals != self.previous_enemy_Goals:
            reward = -1000

        print("Time: ", round(packet.game_info.seconds_elapsed,2), end = " ")
        action = self.DDPG.step(state, reward)


        if current_Goals != self.previous_Goals:
            self.DDPG.newEpisode()


        self.previous_Goals = current_Goals
        self.previous_enemy_Goals = enemy_goals
        self.previous_my_Goals = my_Goals

        #target_location = ball_location

        # if car_location.dist(ball_location) > 500:
        #     # We're far away from the ball, let's try to lead it a little bit
        #     ball_prediction = self.get_ball_prediction_struct()  # This can predict bounces, etc
        #     ball_in_future = find_slice_at_time(ball_prediction, packet.game_info.seconds_elapsed + 1)

        #     # ball_in_future might be None if we don't have an adequate ball prediction right now, like during
        #     # replays, so check it to avoid errors.
        #     if ball_in_future is not None:
        #         target_location = Vec3(ball_in_future.physics.location)
        #         self.renderer.draw_line_3d(ball_location, target_location, self.renderer.cyan())

        # Draw some things to help understand what the bot is thinking
        # self.renderer.draw_line_3d(car_location, target_location, self.renderer.white())
        # self.renderer.draw_string_3d(car_location, 1, 1, f'Speed: {car_velocity.length():.1f}', self.renderer.white())
        # self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)



        controls = SimpleControllerState()
        
        
        controls.steer = action[0]
        controls.throttle = action[1]
        controls.boost = action[2]>0
        # You can set more controls if you want, like controls.boost.

        return controls
Exemple #14
0
 def __init__(self, name, team, index):
     super().__init__(name, team, index)
     self.active_sequence: Sequence = None
     self.boost_pad_tracker = BoostPadTracker()
     self.travel_distance = 0
     self.pos = Vec3(0, 0, 0)
Exemple #15
0
class MyBot(BaseAgent):
    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()

    def initialize_agent(self):
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())
        settings = self.get_match_settings()
        self.map = settings.GameMap()
        if self.map == 35:
            self.map_size = [3581, 2966.7]
        elif self.map == 31:
            self.map_size = [5139.7, 4184.5]
        elif self.map == 37:
            self.map_size = [6912, 4096]
        else:
            self.map_size = [5120, 4096]

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:

        self.boost_pad_tracker.update_boost_status(packet)

        if self.active_sequence is not None and not self.active_sequence.done:
            controls = self.active_sequence.tick(packet)
            if controls is not None:
                return controls
        # Get the distance from the nearest surface (walls, floor, roof, etc.)
        def distance_from_surface(pos):
            min_dist = math.inf
            nearest_surface = pos
            if min_dist > pos.z:
                min_dist = pos.z
                nearest_surface = Vec3(pos.x, pos.y, 0)
            if min_dist > self.map_size[1] - abs(pos.x):
                min_dist = self.map_size[1] - abs(pos.x)
                nearest_surface = Vec3(
                    sign(pos.x) * self.map_size[1], pos.y, pos.z)
            if min_dist > self.map_size[0] - abs(pos.y):
                min_dist = self.map_size[0] - abs(pos.y)
                nearest_surface = Vec3(pos.x,
                                       sign(pos.y) * self.map_size[0], pos.z)
            if min_dist > 99999 + (8064 - abs(pos.x) -
                                   abs(pos.y)) / math.sqrt(2):
                min_dist = (8064 - abs(pos.x) - abs(pos.y)) / math.sqrt(2)
                nearest_surface = Vec3(pos.x,
                                       sign(pos.y) * self.map_size[0], pos.z)
            return nearest_surface

        # Get the rate in which the object is moving away from the nearest surface
        def velocity_from_surface(pos, vel):
            val = pos - distance_from_surface(pos)
            if val.x != 0:
                return vel.x * sign(val.x)
            elif val.y != 0:
                return vel.y * sign(val.y)
            elif val.z != 0:
                return vel.z * sign(val.z)

        # Get the order within the team
        def distance_order(teams):
            nearest = 1
            overall_nearest = 1
            last = 0
            ref = (car_location - ball_location).length(
            ) / (car_velocity.length() + 2300) + math.asin(
                (car_velocity * safe_div(car_velocity.length()) -
                 ball_location * safe_div(ball_location.length())).length() /
                2) * 3 / math.pi * 0
            for i in range(len(packet.game_cars)):
                if (packet.game_cars[i].team !=
                    (-teams * packet.game_cars[self.index].team +
                     (1 + teams) / 2) or teams == False
                    ) and packet.game_cars[i].physics.location.z > 0:
                    time_taken = (
                        Vec3(packet.game_cars[i].physics.location) -
                        ball_location).length() / (Vec3(packet.game_cars[
                            i].physics.velocity).length() + 2300) + math.asin(
                                (Vec3(packet.game_cars[i].physics.velocity) *
                                 safe_div(
                                     Vec3(packet.game_cars[i].physics.velocity
                                          ).length()) - ball_location *
                                 safe_div(ball_location.length())).length() /
                                2) * 3 / math.pi * 0
                    # When the car is further front than the POV
                    if ref > time_taken:
                        if ((Vec3(packet.game_cars[i].physics.location) +
                             send_location).length() <=
                            (ball_location + send_location).length()
                                or (car_location + send_location).length() >
                            (ball_location + send_location).length()):
                            nearest += 1
                        overall_nearest += 1
                    last += 1
            # Keep the full-time goal keeper
            if overall_nearest == last:
                nearest = overall_nearest
            # Prevent the division by 0 error
            return last, nearest

        # Find the best boost pads to use to refuel as fast as possible
        def find_best_boost_pads():
            best_pad = None
            best_score = math.inf
            for i in range(len(self.get_field_info().boost_pads)):
                pad = self.get_field_info().boost_pads[i]
                if packet.game_boosts[
                        i].is_active == True or packet.game_boosts[i].timer <= (
                            Vec3(pad.location) - car_location).length() / 2300:
                    score = (Vec3(pad.location) - car_location).length(
                    ) * safe_div(car_velocity.length()) + math.sin(
                        ((Vec3(pad.location) - car_location) /
                         (Vec3(pad.location) - car_location).length() -
                         car_velocity * safe_div(car_velocity.length())
                         ).length() / 2) * 3 / math.pi
                    if pad.is_full_boost:
                        score *= safe_div((50 - my_car.boost / 2) / 6)
                    if score < best_score:
                        best_score = score
                        best_pad = pad
            return Vec3(best_pad.location)

        # Get the yaw based on position
        def get_yaw(x, y):
            a = math.acos(x / Vec3(x, y, 0).length())
            if abs(a) < math.pi:
                return a * sign(y)
            else:
                return math.pi

        # Get the angle between two places
        def get_angle(p1, p2):
            d = (p1 * safe_div(p1.length()) -
                 p2 * safe_div(p2.length())).length()
            angle = 2 * math.asin(d / 2)
            return angle

        # Determine when the car would intersect the ball assuming a speed
        def intersect_time(surface):
            t1 = 5
            t2 = 5
            best_spd = math.inf
            slowest = math.inf
            if surface == False:
                for i in range(1, 101):
                    time_location = Vec3(predict_ball(i / 20).physics.location)
                    if (time_location - car_location).length(
                    ) * 20 / i <= car_velocity.length() and t1 == 5:
                        t1 = i / 20
                    if (time_location -
                            car_location).length() * 20 / i <= slowest:
                        slowest = (time_location -
                                   car_location).length() * 20 / i
                        t2 = i / 20
            else:
                for i in range(1, 101):
                    time_location = Vec3(predict_ball(i / 20).physics.location)
                    if (distance_from_surface(time_location) -
                            distance_from_surface(car_location)).length(
                            ) * 20 / i <= car_velocity.length() and t1 == 5:
                        t1 = i / 20
                    if (distance_from_surface(time_location) -
                            distance_from_surface(car_location)
                        ).length() * 20 / i <= slowest:
                        slowest = (distance_from_surface(time_location) -
                                   distance_from_surface(car_location)
                                   ).length() * 20 / i
                        t2 = i / 20

            return t1, t2

        # Determine when the car should jump
        def jump_ready(val):
            if val <= 300 and val > 92.75:
                delay = (2 * (val - 92.75) / 650)**0.5
                return delay
            else:
                return 0

        # Get the nearest player to the ball
        def nearest_player(teams, speed_offset):
            nearest = None
            best_time = math.inf
            last = True
            for i in range(len(packet.game_cars)):
                if (packet.game_cars[i].team !=
                    (-teams * packet.game_cars[self.index].team +
                     (1 + teams) / 2) or teams == False) and Vec3(
                         packet.game_cars[i].physics.location) != Vec3(
                             0, 0, 0):
                    time_taken = (Vec3(
                        packet.game_cars[i].physics.location
                    ) - ball_location).length() / (Vec3(
                        packet.game_cars[i].physics.velocity
                    ).length() + speed_offset) + math.sin(
                        (Vec3(packet.game_cars[i].physics.velocity) * safe_div(
                            Vec3(packet.game_cars[i].physics.velocity).length(
                            )) - ball_location *
                         safe_div(ball_location.length())).length() /
                        2) * 3 / math.pi
                    if time_taken < best_time:
                        best_time = time_taken
                        nearest = packet.game_cars[i]
            return nearest, best_time

        # Get the list of moments when the ball should be hit
        def opportunities():
            li = []
            prev_pos = ball_location
            for i in range(1, 101):
                time_location = predict_ball(i / 20)
                if time_location.z <= 300:
                    li.append([
                        i / 20,
                        (time_location - car_location).length() * 20 / i
                    ])
                prev_pos = time_location
            return li

        # ???
        def plane_dist(pos, dist):
            if Vec3(pos.x, pos.y, 0).length() <= dist:
                return True
            elif Vec3(pos.x, 0, pos.z).length() <= dist:
                return True
            elif Vec3(0, pos.y, pos.z).length() <= dist:
                return True
            else:
                return False

        # Get the ball's position and velocity at a specific time
        def predict_ball(t):
            ball_in_future = find_slice_at_time(
                ball_prediction, packet.game_info.seconds_elapsed + t)
            if ball_in_future is not None:
                return ball_in_future
            else:
                return packet.game_ball

        # Divide numbers without division by 0
        def safe_div(x):
            if x == 0:
                return math.inf
            else:
                return 1 / x

        # Return the direction of the value from 0
        def sign(x):
            if x < 0:
                return -1
            elif x > 0:
                return 1
            else:
                return 0

        # Return a value with limitations
        def clamp(x, m, M):
            if x < m:
                return m
            elif x > M:
                return M
            else:
                return x

        # Move the target location to straighten the ascent up walls
        def move_target_for_walls(pos1, pos2):
            up1 = distance_from_surface(pos1)
            up2 = distance_from_surface(pos2)
            new_pos = pos2
            if up1.z == 0 and up2.z > 0:
                new_pos = Vec3(new_pos, 0, new_pos) + (up2 - pos2) * safe_div(
                    (up2 - pos2).length()) * up2.z
            if up1.z > 0 and up2.z == 0 and pos1.z >= 30:
                if abs(up1.x) == self.map_size[1]:
                    new_pos = Vec3(up1.x, up2.y, -abs(up2.x - up1.x))
                elif abs(up1.y) == self.map_size[0]:
                    new_pos = Vec3(up2.x, up1.y, -abs(up2.y - up1.y))
            return new_pos

        # Actions
        # Use flip jumps to attack the ball
        def jump_attack():
            dir_y = 0
            dir_x = 0
            if ((car_location + car_velocity / 5) -
                (ball_location + ball_velocity / 5)).length() <= 175:
                if (car_location + Vec3(car_velocity.y, -car_velocity.x, 0) *
                        safe_div(car_velocity.length()) -
                        ball_location).length() < (car_location -
                                                   ball_location).length():
                    dir_x = -1
                if (car_location + Vec3(-car_velocity.y, car_velocity.x, 0) *
                        safe_div(car_velocity.length()) -
                        ball_location).length() < (car_location -
                                                   ball_location).length():
                    dir_x = 1
                if (car_location + car_velocity / 5 - ball_location -
                        ball_velocity / 5
                    ).length() <= (car_location - ball_location).length() - 50:
                    dir_y = -1
                dir_x *= sign(math.pi / 2 -
                              get_angle(car_direction, car_velocity))
                dir_y *= sign(math.pi / 2 -
                              get_angle(car_direction, car_velocity))
                override = self.flip(packet, dir_x, dir_y, not my_car.jumped)

        # Jump over cars to prevent collision
        def avoid_bump():
            for i in range(len(packet.game_cars)):
                if i != self.index and packet.game_cars[
                        i].physics.location.z > 0:
                    pos = car_location
                    pos2 = Vec3(packet.game_cars[i].physics.location)
                    vel = car_velocity
                    vel2 = Vec3(packet.game_cars[i].physics.velocity)
                    dist = (pos - pos2).length()
                    on_course = False
                    if dist > 40:
                        if get_angle(pos2 - pos, vel) <= math.tan(
                                math.sqrt(40**2 / (dist**2 - 40**2))):
                            on_course = True
                    else:
                        on_course = True
                    if on_course == True and dist <= 40 + (vel - vel2).length(
                    ) / 2 and (vel.length() <= vel2.length()
                               or packet.game_cars[i].team != self.team):
                        self.jump_once(packet)

        # Modes
        def attack():
            # Target
            target_ball = predict_ball(earliest_intersection)
            target_location = Vec3(target_ball.physics.location)
            target_location = target_location + (
                target_location - send_location) / (
                    target_location - send_location).length() * 92.75
            # Smoother wall transitions
            target_location = move_target_for_walls(car_location,
                                                    target_location)
            jumping = jump_ready(
                (target_location -
                 distance_from_surface(target_location)).length())
            # Manage speed
            if velocity_from_surface(
                    Vec3(target_ball.physics.location),
                    Vec3(target_ball.physics.velocity)) >= 0 or (Vec3(
                        target_ball.physics.location) - distance_from_surface(
                            Vec3(target_ball.physics.location))).length(
                            ) <= 300 or target_ball.physics.location.y * sign(
                                send_location.y) <= -self.map_size[0]:
                controls.throttle = 1
            else:
                controls.throttle = 0
            # Boost
            controls.boost = abs(
                steer_toward_target(my_car, target_location)
            ) <= 0.1 and car_velocity.length() < 2300 and (
                (Vec3(target_ball.physics.location) - distance_from_surface(
                    Vec3(target_ball.physics.location))).length() <= 300
                or velocity_from_surface(Vec3(target_ball.physics.location),
                                         Vec3(target_ball.physics.velocity)) >=
                0) and car_index == 1
            # Jump
            h = (Vec3(target_ball.physics.location) - distance_from_surface(
                Vec3(target_ball.physics.location))).length()
            if jump_ready(
                (Vec3(target_ball.physics.location) -
                 distance_from_surface(Vec3(target_ball.physics.location))
                 ).length()) >= earliest_intersection and steer_toward_target(
                     my_car, target_location) < 1:
                controls.pitch = 0
                controls.yaw = 0
                controls.roll = 0
                controls.jump = True
                controls.boost = False
            else:
                jump_attack()
            # Catch the ball when in the air
            if abs(
                    target_location.z - car_location.z
            ) <= 92.75 * 0.75 and get_angle(
                    target_location - car_location, car_velocity
            ) >= math.atan(
                    200 * safe_div(car_velocity.length())
            ) and my_car.jumped == True and my_car.double_jumped == False and False:
                controls.yaw = sign(
                    (target_location - car_location -
                     Vec3(car_velocity.y, -car_velocity.x, car_velocity.z)
                     ).length() -
                    (target_location - car_location -
                     Vec3(-car_velocity.y, car_velocity.x, car_velocity.z)
                     ).length())
                controls.jump = True
            # Draw
            self.renderer.draw_line_3d(car_location, target_location,
                                       self.renderer.red())
            self.renderer.draw_rect_3d(target_location,
                                       8,
                                       8,
                                       True,
                                       self.renderer.red(),
                                       centered=True)
            return target_location

        def standby():
            # Friendly/enemey
            if enemy_time >= friendly_time + 0.2:
                nearest_ref = nearest_friendly
                md = "friendly"
            else:
                nearest_ref = nearest_enemy
                md = "enemy"
            # Target
            if md == "enemy" or True:
                target_location = ball_location - (
                    Vec3(nearest_ref.physics.location) - ball_location) / (
                        Vec3(nearest_ref.physics.location) -
                        ball_location).length() * (2500 + Vec3(
                            nearest_ref.physics.velocity).length() * 5 / 2.3)
                target_location = Vec3(
                    target_location.x,
                    ball_location.y + (target_location.y - ball_location.y) *
                    sign(target_location.y - ball_location.y) *
                    -sign(send_location.y), target_location.z)
            else:
                target_location = ball_location - (
                    Vec3(nearest_ref.physics.location) - ball_location) / (
                        Vec3(nearest_ref.physics.location) -
                        ball_location).length() * (2500 + Vec3(
                            nearest_ref.physics.velocity).length() * 5 / 2.3)
                target_location = target_location + (
                    target_location - send_location) / (
                        target_location - send_location).length() * 927.5
            # Walls
            if (distance_from_surface(target_location) -
                    target_location).length() <= 300:
                target_location = distance_from_surface(target_location)
                target_location = move_target_for_walls(
                    car_location, target_location)
            else:
                target_location = Vec3(target_location.x, target_location.y, 0)
            # Draw
            self.renderer.draw_line_3d(car_location, target_location,
                                       self.renderer.green())
            self.renderer.draw_rect_3d(target_location,
                                       8,
                                       8,
                                       True,
                                       self.renderer.green(),
                                       centered=True)
            # Manage speed
            controls.boost = False
            controls.throttle = clamp(
                (target_location - car_location).length() / 1000, -1, 1)
            return target_location

        def refuel():
            # Target
            target_location = find_best_boost_pads()
            # Draw
            self.renderer.draw_line_3d(car_location, target_location,
                                       self.renderer.green())
            self.renderer.draw_rect_3d(target_location,
                                       8,
                                       8,
                                       True,
                                       self.renderer.green(),
                                       centered=True)
            # Speed
            controls.throttle = 1
            controls.boost = False
            return target_location

        def goalie():
            target_location = car_location
            # Roll back onto the wheels
            if abs(car_rotation.roll) >= math.pi * 3 / 4:
                override = self.jump_once(packet)
            # Prepare for a save
            if sign(car_location.y) == -sign(send_location.y) and abs(
                    car_location.y) >= abs(send_location.y):
                target_location = car_location - Vec3(0, send_location.y, 0)
                if car_velocity.length() >= 850:
                    controls.throttle = -1
                else:
                    if Vec3(car_velocity.x, car_velocity.y, 0).length() >= 250:
                        override = self.reverse_flip(packet)
                    else:
                        controls.pitch = 0
                        controls.roll = 0
                        if (not math.pi * 0.4 <= abs(car_rotation.yaw) <=
                                math.pi * 0.6 or sign(car_rotation.yaw)
                                == -sign(send_location.y)) and abs(
                                    car_velocity.z) <= 1:
                            override = self.jump_once(packet)
                        controls.yaw = clamp(
                            steer_toward_target(my_car, send_location) -
                            my_car.physics.angular_velocity.z, -1, 1)
                    controls.throttle = 0
            # Drive into the goal unless it's already done so
            else:
                target_location = defend()
            return target_location

        def defend():
            if not in_goal:
                target_ball = predict_ball(earliest_intersection)
                target_location = Vec3(target_ball.physics.location)
                nearest_surface = (target_location - car_location) / (
                    target_location - car_location).length() * 140
                nearest_surface_r = Vec3(-nearest_surface.y, nearest_surface.x,
                                         nearest_surface.z)
                nearest_surface_l = Vec3(nearest_surface.y, -nearest_surface.x,
                                         nearest_surface.z)
                if False:
                    side = -sign((nearest_surface_l - send_location).length() -
                                 (nearest_surface_r - send_location).length())
                else:
                    side = -sign(((nearest_surface_l - ball_location) -
                                  ball_velocity).length() -
                                 ((nearest_surface_r - ball_location) -
                                  ball_velocity).length())
                nearest_surface = Vec3(-nearest_surface.y * side,
                                       nearest_surface.x * side,
                                       nearest_surface.z)
                if abs(target_location.x +
                       nearest_surface.x) >= self.map_size[1] or get_angle(
                           car_location - send_location,
                           car_location - target_location
                       ) > math.pi / 3 * 2 or ball_location.z > 130:
                    target_location = -send_location
                else:
                    target_location = target_location + nearest_surface / 140 * car_velocity.length(
                    )
                controls.boost = enemy_time < 1 and abs(
                    steer_toward_target(my_car, target_location)) <= 0.1
                # Jump
                h = (Vec3(target_ball.physics.location) -
                     distance_from_surface(Vec3(
                         target_ball.physics.location))).length()
                if jump_ready(
                        h) >= earliest_intersection and steer_toward_target(
                            my_car, target_location) < 1:
                    controls.pitch = 0
                    controls.yaw = 0
                    controls.roll = 0
                    controls.jump = True
                    controls.boost = False
                else:
                    jump_attack()
                # Draw
                self.renderer.draw_line_3d(car_location,
                                           ball_location + nearest_surface,
                                           self.renderer.cyan())
                self.renderer.draw_rect_3d(ball_location + nearest_surface,
                                           8,
                                           8,
                                           True,
                                           self.renderer.cyan(),
                                           centered=True)
                controls.throttle = 1
            else:
                target_location = -send_location
                controls.throttle = 1
            return target_location

        def recovery():
            tx = (self.map_size[1] - car_location.x *
                  sign(car_velocity.x)) * safe_div(car_velocity.x)
            ty = (self.map_size[0] - car_location.y *
                  sign(car_velocity.y)) * safe_div(car_velocity.y)
            tt = 0
            if car_location.z / 325 - (car_velocity.z / 650)**2 >= 0:
                tz = car_velocity.z / 650 + math.sqrt(car_location.z / 325 -
                                                      (car_velocity.z /
                                                       650)**2)
            else:
                tz = car_velocity.z / 650 - math.sqrt(car_location.z / 325 +
                                                      (car_velocity.z /
                                                       650)**2)
            if tx >= tz <= ty:
                controls.roll = clamp(-car_rotation.roll, -1, 1)
                controls.pitch = clamp(-car_rotation.pitch, -1, 1)
                tt = tz
            elif tx >= ty <= tz:
                point = (math.pi / 2 +
                         sign(abs(car_rotation.yaw) - math.pi / 2) * math.pi /
                         2) * sign(car_rotation.yaw)
                controls.roll = clamp(
                    math.pi / 2 * sign(car_velocity.y) *
                    sign(abs(car_rotation.yaw) - math.pi / 2) -
                    car_rotation.roll, -1, 1)
                controls.pitch = clamp(point - car_rotation.yaw, -1, 1)
                tt = ty
            draw_point = Vec3(
                car_location.x + car_velocity.x * tt,
                car_location.y + car_velocity.y * tt,
                car_location.z + car_velocity.z * tt - 325 * tt**2)
            self.renderer.draw_line_3d(car_location, draw_point,
                                       self.renderer.pink())
            self.renderer.draw_rect_3d(draw_point,
                                       8,
                                       8,
                                       True,
                                       self.renderer.pink(),
                                       centered=True)

        # Variables

        my_car = packet.game_cars[self.index]
        car_location = Vec3(my_car.physics.location)
        car_velocity = Vec3(my_car.physics.velocity)
        car_rotation = my_car.physics.rotation
        car_direction = Vec3(
            math.cos(car_rotation.yaw) * math.cos(car_rotation.pitch),
            math.sin(car_rotation.yaw) * math.cos(car_rotation.pitch),
            math.sin(car_rotation.pitch))
        ball_prediction = self.get_ball_prediction_struct()
        ball_location = Vec3(packet.game_ball.physics.location)
        ball_velocity = Vec3(packet.game_ball.physics.velocity)
        send_location = Vec3(0, sign(0.5 - self.team) * self.map_size[0], 0)
        earliest_intersection, easiest_intersection = intersect_time(True)
        team_size, car_index = distance_order(1)
        nearest_enemy, enemy_time = nearest_player(0, 460)
        nearest_friendly, friendly_time = nearest_player(0, 460)
        in_goal = (ball_location + send_location).length() > (
            car_location + send_location).length()
        target_location = car_location
        mode = ""
        override = None

        # Controls
        controls = SimpleControllerState()

        # Half-flip to quickly turn
        if car_velocity.length() <= 500 and get_angle(
                car_velocity,
                target_location - car_location) >= math.pi / 3 * 2:
            override = self.reverse_flip(packet)

        # Assign role in the team
        if abs(send_location.y + Vec3(predict_ball(2).physics.location).y
               ) <= 1000 or abs(send_location.y + ball_location.y) <= 1000:
            if in_goal:
                mode = "Attack"
            else:
                mode = "Defense"
        else:
            if car_index == 1:
                if in_goal:
                    mode = "Attack"
                else:
                    mode = "Defense"
            elif car_index < team_size:
                if my_car.boost == 100 and car_index == 2:
                    mode = "Standby"
                else:
                    mode = "Refuel"
            else:
                mode = "Goalie"
        # Recovery
        if my_car.double_jumped:
            recovery()
        # Demolition
        if mode == "Demo":
            target_location = demo()
        # Attack the ball
        if mode == "Attack":
            avoid_bump()
            target_location = attack()
            controls.use_item = True
        # Stand by for hit
        if mode == "Standby":
            avoid_bump()
            target_location = standby()
        # Collect boost
        if mode == "Refuel":
            avoid_bump()
            target_location = refuel()
        # Retreat
        if mode == "Defense":
            avoid_bump()
            target_location = defend()
        # Goalie
        if mode == "Goalie":
            avoid_bump()
            target_location = goalie()

        controls.steer = steer_toward_target(my_car, target_location)

        # Draw
        if False:
            self.renderer.draw_string_2d(
                800, 200, 1, 1, "X: " +
                str(packet.game_cars[1 - self.index].physics.location.x),
                self.renderer.white())
            self.renderer.draw_string_2d(
                800, 220, 1, 1, "Y: " +
                str(packet.game_cars[1 - self.index].physics.location.y),
                self.renderer.white())
            self.renderer.draw_string_2d(1400, 200, 1, 1,
                                         "Map: " + str(self.map),
                                         self.renderer.white())
        self.renderer.draw_string_2d(
            50, 680 + car_index * 20 * (0.5 - self.team) * 2, 1, 1,
            "Noob Bot " + str(car_index) + ": " + str(mode),
            self.renderer.white())
        self.renderer.draw_line_3d(target_location,
                                   distance_from_surface(target_location),
                                   self.renderer.yellow())

        if override:
            return override
        else:
            return controls

    def flip(self, packet, dir_x, dir_y, first_jump):
        self.active_sequence = Sequence([
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=first_jump)),
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=False)),
            ControlStep(duration=0.2,
                        controls=SimpleControllerState(jump=True,
                                                       yaw=dir_x,
                                                       pitch=dir_y)),
            ControlStep(duration=0.8, controls=SimpleControllerState()),
        ])

        return self.active_sequence.tick(packet)

    def jump_once(self, packet):
        self.active_sequence = Sequence([
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=True)),
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=False))
        ])

        return self.active_sequence.tick(packet)

    def reverse_flip(self, packet):
        self.active_sequence = Sequence([
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=True)),
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=False)),
            ControlStep(duration=0.2,
                        controls=SimpleControllerState(jump=True, pitch=1)),
            ControlStep(duration=0.25,
                        controls=SimpleControllerState(jump=False, pitch=-1)),
            ControlStep(duration=0.3,
                        controls=SimpleControllerState(roll=1, pitch=-1)),
            ControlStep(duration=0.05, controls=SimpleControllerState()),
        ])

        return self.active_sequence.tick(packet)

    def correct_direction(self, packet, dir):
        self.active_sequence = Sequence([
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=True,
                                                       throttle=dir)),
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(jump=False,
                                                       throttle=dir)),
            ControlStep(duration=0.2,
                        controls=SimpleControllerState(jump=True,
                                                       throttle=dir,
                                                       pitch=1)),
            ControlStep(duration=0.25,
                        controls=SimpleControllerState(jump=False,
                                                       throttle=dir,
                                                       pitch=-1)),
            ControlStep(duration=0.3,
                        controls=SimpleControllerState(roll=1,
                                                       throttle=-dir,
                                                       pitch=-1)),
            ControlStep(duration=0.05,
                        controls=SimpleControllerState(throttle=-dir)),
        ])

        return self.active_sequence.tick(packet)
Exemple #16
0
class MyBot(BaseAgent):

    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()
        self.controls = SimpleControllerState()
        self.bot_car = None
        self.ball = None
        self.allies=[]
        self.foes=[]
        self.ball_prediction = None
        self.posts=((Vec3(893,-5120,0),Vec3(-893,-5120,0)),(Vec3(893,5120,0),Vec3(-893,5120,0)))
        self.back_corners=((Vec3(3672,-4096,0),Vec3(-3672,-4096,0)),(Vec3(3672,4096,0),Vec3(-3672,4096,0)))
        self.collision_posts=((Vec3(843,-5070,0),Vec3(-843,-5070,0)),(Vec3(843,5070,0),Vec3(-843,5070,0)))
        self.goal_corners=((Vec3(-893,-6000,0),Vec3(893,-5120,642.775)),(Vec3(-893,5120,0),Vec3(893,6000,642.775)))
        self.boxes=((Vec3(-1600,-6000,0),Vec3(1600,-4120,2044)),(Vec3(-1600,4120,0),Vec3(1600,6000,2044))) 

        self.defending = False
        self.rotating = False
        self.supporting = 0
        self.clearing = False
        self.shooting = False
        self.air_recovery = False
        self.current_strike = None
        self.skip_ticks_to_test = 0

    def initialize_agent(self):
        # Set up information about the boost pads now that the game is active and the info is available
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        

        """ Keep our boost pad info updated with which pads are currently active"""
        self.boost_pad_tracker.update_boost_status(packet)

        
        """Update cars and ball"""
        #ball
        if self.ball is None:
            self.ball = Ball(packet)
        else:
            self.ball.update(packet)

        self.ball_prediction = self.get_ball_prediction_struct()
        #draw 3 sec of path
        self.renderer.draw_polyline_3d([Vec3(ball_slice.physics.location) for ball_slice in self.ball_prediction.slices[:180:5]],self.renderer.yellow())

        #self
        if self.bot_car is None:
            self.bot_car = Car(self.index,packet)
        elif self.bot_car.index != self.index:
            self.bot_car = Car(self.index,packet)
        else:
            self.bot_car.update(packet)

        #check if number of players has changed, and reset allies and foes if it has
        if len(self.allies)+len(self.foes)+1!=len(packet.game_cars):
            self.allies,self.foes = [],[]

        #allies
        if len(self.allies)==0:
            for index in range(packet.num_cars):
                if packet.game_cars[index].team==self.bot_car.team and index!=self.bot_car.index:
                    self.allies.append(Car(index,packet))
        else:
            for car in self.allies:
                car.update(packet)
        

        #foes
        if len(self.foes)==0:
            for index in range(packet.num_cars):
                if packet.game_cars[index].team!=self.bot_car.team:
                    self.foes.append(Car(index,packet))
        else:
            for car in self.foes:
                car.update(packet)

        if self.skip_ticks_to_test > 0:
            self.skip_ticks_to_test -= 1
            return SimpleControllerState()

        """Continue and active sequences"""
        if self.active_sequence is not None and not self.active_sequence.done:
            controls = self.active_sequence.tick(packet)
            if controls is not None:
                return controls
        self.controls = SimpleControllerState()


        
        """put cars in positions (for testing) (set long left atm)
        if (Vec3(packet.game_ball.physics.location).length() > 200 or self.bot_car.location.y > 50) and self.bot_car.team==0:
            car_state0= CarState(boost_amount=45.333, physics=Physics(velocity=Vector3(0,0, 0),location=Vector3(256,-3840, 0),rotation=Rotator(0, 0.5*math.pi, 0),angular_velocity=Vector3(0, 0, 0)))
            car_state1= CarState(boost_amount=45.333, physics=Physics(velocity=Vector3(0,0, 0),location=Vector3(-256,3840, 0),rotation=Rotator(0, -0.5*math.pi, 0),angular_velocity=Vector3(0, 0, 0)))
            if self.bot_car.index!=self.bot_car.team:
                car_state0,car_state1=car_state1,car_state0
            ball_state= BallState(Physics(velocity=Vector3(x=0,y=0,z=0),location=Vector3(x=0,y=0,z=92.75),rotation=Rotator(0,0,0),angular_velocity=Vector3(0,0,0)))

            self.set_game_state(GameState(ball=ball_state,cars={0:car_state0,1:car_state1}))
            self.skip_ticks_to_test = 10
            return SimpleControllerState()
        """
        
        """draw in info for blocking testing
        self.renderer.draw_string_2d(20,20,3,3, f"z: {self.bot_car.location.z}", self.renderer.white())

        if self.bot_car.stable:
            return self.long_jump(packet)
        else:
            return SimpleControllerState()
        """


        """kickoff        NOTE: the diagonal flips need to be more sideways than forward when updating for the diagonal and long"""
        if self.ball.location.flat().length()<1 and self.ball.velocity.flat().length()<1 and packet.game_info.is_kickoff_pause:
            ally_on_short = False
            for ally in self.allies:
                if Vec3(-2048,-2560,0).dist(ally.location)<50 or Vec3(-2048,2560,0).dist(ally.location)<50 or Vec3(2048,-2560,0).dist(ally.location)<50 or Vec3(2048,2560,0).dist(ally.location)<50:
                    ally_on_short = True
            if self.bot_car.location.flat().dist(Vec3(-2048,-2560,0))<50 or self.bot_car.location.flat().dist(Vec3(2048,2560,0))<50:
                self.active_sequence, first_frame = right_diagonal(packet)
                return first_frame
            elif self.bot_car.location.flat().dist(Vec3(2048,-2560,0))<50 or self.bot_car.location.flat().dist(Vec3(-2048,2560,0))<50:
                self.active_sequence, first_frame = left_diagonal(packet)
                return first_frame
            elif (self.bot_car.location.flat().dist(Vec3(-256,-3840))<50 or self.bot_car.location.flat().dist(Vec3(256,3840,0))<50) and not ally_on_short:
                self.active_sequence, first_frame = long_right(packet)
                return first_frame
            elif (self.bot_car.location.flat().dist(Vec3(256,-3840,0))<50 or self.bot_car.location.flat().dist(Vec3(-256,3840,0))<50) and not ally_on_short:
                self.active_sequence, first_frame = long_left(packet)
                return first_frame
            elif (self.bot_car.location.flat().dist(Vec3(0,-4608,0))<50 or self.bot_car.location.flat().dist(Vec3(0,4608,0))<50) and len(self.allies)==0:
                self.active_sequence, first_frame = back_kick(packet)
                return first_frame
            else:
               self.active_sequence, first_frame = kickoff_idle(packet)
               return first_frame

       
        """defend check"""
        if self.ball.velocity.flat().length()!=0:
            post0_ang = self.posts[self.bot_car.team][0].__sub__(self.ball.location).flat().ang_to(Vec3(1,0,0))
            ball_vel_ang = self.ball.velocity.flat().ang_to(Vec3(1,0,0))
            post1_ang = self.posts[self.bot_car.team][1].__sub__(self.ball.location).flat().ang_to(Vec3(1,0,0))
            between_posts = post0_ang < ball_vel_ang < post1_ang
            moving_at_posts = self.ball.velocity.y<0 and self.ball.location.y<4000 if self.bot_car.team==0 else self.ball.velocity.y>0 and self.ball.location.y>-4000
        
            self.defending = True if between_posts and moving_at_posts else False
        
        """rotate check"""
        if self.rotating:
            #check for reasons to stop
            far_enough_behind_ball = self.bot_car.location.y-self.ball.location.y<-4000 if self.bot_car.team==0 else self.bot_car.location.y-self.ball.location.y>4000
            about_to_hit_backwall =  self.bot_car.location.y <-4100 if self.bot_car.team==0 else self.bot_car.location.y >4100
            dunk_on_box = self.ball.location.within(self.boxes[(self.bot_car.team+1)%2][0],self.boxes[(self.bot_car.team+1)%2][1]) and min([foe.vec_to_ball.length() for foe in self.foes])>1000 and len(self.allies)==0
            
            self.rotating = not( far_enough_behind_ball or about_to_hit_backwall or dunk_on_box )
        else:
            #check for reasons to start
            wrong_side_of_ball_and_not_deep = self.bot_car.location.y-self.ball.location.y>0 and self.bot_car.location.y >-4000 if self.bot_car.team==0 else self.bot_car.location.y-self.ball.location.y<0 and self.bot_car.location.y <4000
            
            vec_to_goal = Vec3(0, 5200*(self.bot_car.team*2-1),0) - self.bot_car.location
            ball_to_goal = Vec3(0, 5200*(self.bot_car.team*2-1),0) - self.ball.location
            unproductive_to_keep_chasing = vec_to_goal.length() < ball_to_goal.length()

            self.rotating = wrong_side_of_ball_and_not_deep

        """support check"""
        self.supporting=0
        try:
            if self.bot_car.orientation.forward.ang_to(self.bot_car.vec_to_ball)<1.5 and (self.bot_car.team ==0 and self.bot_car.velocity.normalized().y>-0.7 or self.bot_car.team ==1 and self.bot_car.velocity.normalized().y<0.7):
                #self in a position to look to go
                for ally in self.allies:
                    if ally.orientation.forward.ang_to(ally.vec_to_ball)<1.5 and (ally.team ==0 and ally.velocity.normalized().y>-0.7 or ally.team ==1 and ally.velocity.normalized().y<0.7) and (ally.assumed_maneuver =="BALL" or ally.assumed_maneuver =="SUPPORT"):
                        if ally.vec_to_ball.length() < self.bot_car.vec_to_ball.length():
                            self.supporting += 1
            else:
                #self in a position to look to go, allowing an extra 500 for bots that are facing ball
                for ally in self.allies:
                    if ally.orientation.forward.ang_to(ally.vec_to_ball)<1.5 and (ally.team ==0 and ally.velocity.normalized().y>-0.7 or ally.team ==1 and ally.velocity.normalized().y<0.7) and (ally.assumed_maneuver =="BALL" or ally.assumed_maneuver =="SUPPORT"):
                        if ally.vec_to_ball.length() < self.bot_car.vec_to_ball.length():
                            self.supporting += 1
                    else:
                        if ally.vec_to_ball.length() < self.bot_car.vec_to_ball.length()+500:
                            self.supporting += 1

        except:
            stub="don't want to manually catch div 0"

        if self.ball.location.within(self.boxes[0][0],self.boxes[0][1]) or self.ball.location.within(self.boxes[1][0],self.boxes[1][1]):
            #box panic and dunk, both in one
            self.supporting = max(0,self.supporting-1)

        #draw in boxes
        for xy in [(-1600,4140),(-1600,-4140),(1600,4140),(1600,-4140)]:
                self.renderer.draw_line_3d(Vec3(xy[0],xy[1],0), Vec3(xy[0],xy[1],2000), self.renderer.red())

        """clear check"""
        in_half = self.ball.location.y < -2000 if self.bot_car.team==0 else self.ball.location.y > 2000
        self.clearing = in_half

        """shoot check"""
        self.shooting=True

        """air recovery check"""
        if self.current_strike is None:
            self.air_recovery = not self.bot_car.grounded and self.bot_car.location.z>100
        else:
            self.air_recovery = not self.bot_car.grounded and self.current_strike.strike_type != "will add the aerial strike code later" and self.bot_car.location.z>100

        """if ball threatening net but not on target overide"""
        if self.supporting ==0 and self.ball.location.y*math.copysign(1,self.bot_car.team*2-1)>3000:
            self.defending = True

        """defending, but third override"""
        if self.supporting==2 and self.defending:
            self.defending==False

        
        #dribble code is just linear target code with no offset and a little bit of turning
        
        if self.air_recovery:
            self.perform_air_recovery(packet)
            self.renderer.draw_string_3d(self.bot_car.location, 1, 1, f'AIR RECOVERY', self.renderer.white())
        elif self.defending:
            self.defend(packet)
            self.renderer.draw_string_3d(self.bot_car.location, 1, 1, f'DEFENDING', self.renderer.white())
        elif self.rotating:
            self.rotate(packet)
            self.renderer.draw_string_3d(self.bot_car.location, 1, 1, f'ROTATING', self.renderer.white())
        elif self.supporting>0:
            self.support(packet,self.supporting)
            self.renderer.draw_string_3d(self.bot_car.location, 1, 1, f'SUPPORTING', self.renderer.white())
        elif self.clearing:
            self.clear(packet)
            self.renderer.draw_string_3d(self.bot_car.location, 1, 1, f'CLEARING', self.renderer.white())
        elif self.shooting:
            self.shoot(packet)
            self.renderer.draw_string_3d(self.bot_car.location, 1, 1, f'SHOOTING', self.renderer.white())
            

        
        return self.controls


    """tools"""
    

    def steer_toward(self,car: Car, target:Vec3):
        #always call after throttle set
        angle = car.orientation.forward.signed_ang_to(target-car.location)
        if angle<-1.7 and car.grounded and car.vec_to_ball.flat().length()>500:
            self.controls.steer = -1
            if car.velocity.length()>1200:
                self.controls.throttle*=-1
            self.controls.handbrake=True
        elif angle<-0.1 and car.grounded:
            self.controls.steer = -1
            self.controls.handbrake=False
        elif angle>1.7 and car.grounded and car.vec_to_ball.flat().length()>500:
            self.controls.steer = 1
            if car.velocity.length()>1200:
                self.controls.throttle*=-1
            self.controls.handbrake=True
        elif angle>0.1 and car.grounded:
            self.controls.steer = 1
            self.controls.handbrake=False
        else:
            self.controls.steer = 0
            self.controls.handbrake=False

    def point_in_field(self,vec):
        if abs(vec.x)>4096:
            vec = vec * (4096/abs(vec.x))
        if abs(vec.y)>5120:
            vec = vec * (5120/abs(vec.y))
        if abs(vec.z)>2044:
            vec = vec * (2044/abs(vec.z))
        return vec
    
            



    

    """Routines"""
    def shoot(self,packet):
        
        #get vector of ball to the back of other net
        ideal_shot = Vec3(0,6000,0) - self.ball.location.flat() if self.bot_car.team==0 else Vec3(0,-6000,0) - self.ball.location.flat()
        
               
        #continue any strike after checking it
        if self.current_strike is not None:
            if check_strike(packet, self.ball_prediction, self.current_strike):
                self.active_sequence, strike_controls, strike_location, strike_time = execute_strike(packet,self.bot_car,self.current_strike,self.foes)
                self.controls = strike_controls
                self.renderer.draw_rect_3d(strike_location, 8, 8, True, self.renderer.red(), centered=True)
                self.renderer.draw_line_3d(self.bot_car.location, strike_location, self.renderer.white())
                self.renderer.draw_string_2d(20,20,3,3,f"throttle: {self.controls.throttle}",self.renderer.white())
                return
            else:
                self.current_strike = None

        
        #try to find  strikes
        if self.ball.velocity.length()!=0 and self.current_strike is None and self.bot_car.stable:
            strikes = find_strikes(packet, self.ball_prediction, self.bot_car, ideal_shot)
            for strike in strikes:
                if strike.strike_type==strike_types.simple_linear:
                    #linear
                    if (Vec3(0,6000*(1-self.bot_car.team*2),0) - strike.slice_location).ang_to(self.bot_car.orientation.forward) < 2:
                        #if linear strike is not a massive angle from the goal
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike
                elif strike.strike_type==strike_types.linear_jump:
                    #long jump
                    if (Vec3(0,6000*(1-self.bot_car.team*2-1),0) - strike.slice_location).ang_to(self.bot_car.orientation.forward) < 2:
                        #if linear strike is not a massive angle from the goal
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike
                elif strike.strike_type==strike_types.linear_dblj:
                    #double jump
                    if (Vec3(0,6000*(1-self.bot_car.team*2-1),0) - strike.slice_location).ang_to(self.bot_car.orientation.forward) < 2:
                        #if linear strike is not a massive angle from the goal
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike

            #execute straight away if one was chosen
            if self.current_strike is not None:
                self.active_sequence, strike_controls, strike_location, strike_time = execute_strike(packet,self.bot_car,self.current_strike,self.foes)
                self.controls = strike_controls
                self.renderer.draw_rect_3d(strike_location, 8, 8, True, self.renderer.red(), centered=True)
                self.renderer.draw_line_3d(self.bot_car.location, strike_location, self.renderer.white())
                self.renderer.draw_string_2d(20,20,3,3,f"throttle: {self.controls.throttle}",self.renderer.white())
                return

        #position to get a shot on the ball

        future_location, future_velocity = Vec3(self.ball.location), Vec3(self.ball.velocity)

        future_slice = find_slice_at_time(self.ball_prediction,packet.game_info.seconds_elapsed + 2)
        if future_slice is not None:
            future_location = Vec3(future_slice.physics.location)
            future_velocity = Vec3(future_slice.physics.velocity)
            self.renderer.draw_line_3d(self.ball.location, future_location, self.renderer.cyan())

        target_location = self.point_in_field(future_location.flat()+ideal_shot.rescale(-500))
        self.controls.throttle = 1.0
        self.steer_toward(self.bot_car, target_location)
        self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
        self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
        return

        ##################################################################################################


        
        

    def clear(self,packet):

        #get vector of ball from the cone of own net
        ideal_shot = self.ball.location.flat() - Vec3(0,-8000,0) if self.bot_car.team==0 else self.ball.location.flat() - Vec3(0,8000,0)
        
        #find a future position based off the distance from the ball, using the current location as a backup
        future_location = self.ball.location
        future_velocity = self.ball.velocity


        #continue any strike after checking it
        if self.current_strike is not None and self.bot_car.stable:
            if check_strike(packet, self.ball_prediction, self.current_strike):
                self.active_sequence, strike_controls, strike_location, strike_time = execute_strike(packet,self.bot_car,self.current_strike,self.foes)
                self.controls = strike_controls

                #drive out of goal > priority
                in_goal = self.bot_car.location.within(self.goal_corners[self.bot_car.team][0],self.goal_corners[self.bot_car.team][1])
                post0_ang = self.collision_posts[self.bot_car.team][0].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                std_ang_to_target = self.current_strike.slice_location.__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                post1_ang = self.collision_posts[self.bot_car.team][1].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                between_posts = post0_ang < std_ang_to_target < post1_ang
                if not between_posts and in_goal:
                    target_location = Vec3(0,(2*self.team-1)*5000,0)
                    self.controls.throttle = 1
                    self.steer_toward(self.bot_car, target_location)
                    self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
                    self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
                    return

                
                self.renderer.draw_rect_3d(strike_location, 8, 8, True, self.renderer.red(), centered=True)
                self.renderer.draw_line_3d(self.bot_car.location, strike_location, self.renderer.white())
                self.renderer.draw_string_2d(20,20,3,3,f"throttle: {self.controls.throttle}",self.renderer.white())
                return
            else:
                self.current_strike = None

       

        #try to find  strikes
        if self.ball.velocity.length()!=0 and self.current_strike is None:
            strikes = find_strikes(packet,self.ball_prediction,self.bot_car,ideal_shot)
            for strike in strikes:
                if strike.strike_type==strike_types.simple_linear:
                    #linear
                    if (strike.slice_location - Vec3(0,5500*(self.bot_car.team*2-1),0)).ang_to(self.bot_car.orientation.forward) < 2.2:
                        #if linear strike is not a massive angle from the goal
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike
                elif strike.strike_type==strike_types.linear_jump:
                    #long jump
                    if (strike.slice_location - Vec3(0,5500*(self.bot_car.team*2-1),0)).ang_to(self.bot_car.orientation.forward) < 2:
                        #if linear strike is not a massive angle from the goal
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike
                elif strike.strike_type==strike_types.linear_dblj:
                    #double jump
                    if (strike.slice_location - Vec3(0,5500*(self.bot_car.team*2-1),0)).ang_to(self.bot_car.orientation.forward) < 2:
                        #if linear strike is not a massive angle from the goal
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike

            #execute straight away if one was chosen:

                
            #execute
            if self.current_strike is not None:
                #drive out of goal > priority
                in_goal = self.bot_car.location.within(self.goal_corners[self.bot_car.team][0],self.goal_corners[self.bot_car.team][1])
                post0_ang = self.collision_posts[self.bot_car.team][0].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                std_ang_to_target = self.current_strike.slice_location.__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                post1_ang = self.collision_posts[self.bot_car.team][1].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                between_posts = post0_ang < std_ang_to_target < post1_ang
                if not between_posts and in_goal:
                    target_location = Vec3(0,(2*self.team-1)*5000,0)
                    self.controls.throttle = 1
                    self.steer_toward(self.bot_car, target_location)
                    self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
                    self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
                    return
                    
                #execute
                self.active_sequence, strike_controls, strike_location, strike_time = execute_strike(packet,self.bot_car,self.current_strike,self.foes)
                self.controls = strike_controls
                    
                self.renderer.draw_rect_3d(strike_location, 8, 8, True, self.renderer.red(), centered=True)
                self.renderer.draw_line_3d(self.bot_car.location, strike_location, self.renderer.white())
                self.renderer.draw_string_2d(20,20,3,3,f"throttle: {self.controls.throttle}",self.renderer.white())
                return

                            
        #position for a better shot
        future_location, future_velocity = Vec3(self.ball.location), Vec3(self.ball.velocity)

        future_slice = find_slice_at_time(self.ball_prediction,packet.game_info.seconds_elapsed + 2)
        if future_slice is not None:
            future_location = Vec3(future_slice.physics.location)
            future_velocity = Vec3(future_slice.physics.velocity)
            self.renderer.draw_line_3d(self.ball.location, future_location, self.renderer.cyan())

        target_location = self.point_in_field(future_location.flat()+ideal_shot.rescale(-500))


        #drive out of goal > priority
        in_goal = self.bot_car.location.within(self.goal_corners[self.bot_car.team][0],self.goal_corners[self.bot_car.team][1])
        post0_ang = self.collision_posts[self.bot_car.team][0].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
        std_ang_to_target = target_location.__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
        post1_ang = self.collision_posts[self.bot_car.team][1].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
        between_posts = post0_ang < std_ang_to_target < post1_ang
        if not between_posts and in_goal:
            target_location = Vec3(0,(2*self.team-1)*5000,0)
            self.controls.throttle = 1
            self.steer_toward(self.bot_car, target_location)
            self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
            self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
            return
        self.controls.throttle = 1.0
        self.steer_toward(self.bot_car, target_location)
        self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
        self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
        return

    
        
    def rotate(self,packet):

        #continue any strike after checking it
        if self.current_strike is not None:
            if check_strike(packet,self.ball_prediction,self.current_strike) and abs(self.current_strike.slice_location.y) > abs(self.bot_car.location.y):
                self.active_sequence, strike_controls, strike_location, strike_time = execute_strike(packet,self.bot_car,self.current_strike,self.foes)
                self.controls = strike_controls
                self.renderer.draw_rect_3d(strike_location, 8, 8, True, self.renderer.red(), centered=True)
                self.renderer.draw_line_3d(self.bot_car.location, strike_location, self.renderer.white())
                self.renderer.draw_string_2d(20,20,3,3,f"throttle: {self.controls.throttle}",self.renderer.white())
                return
            else:
                self.current_strike = None


        #aim at the post opposite where the ball is
        target_location = self.posts[self.bot_car.team][0] if self.ball.location.x < 0 else self.posts[self.bot_car.team][1]
        #wavedash to rotate quicker
        if self.bot_car.location.dist(target_location) > 3000 and self.bot_car.stable and self.bot_car.orientation.forward.ang_to(target_location-self.bot_car.location)<0.3 and 500<self.bot_car.velocity.length()<1600:
            self.active_sequence, self.controls = wavedash(packet)
            return

        #add something to avoid collisions later
        if self.bot_car.location.point_in_path(target_location - self.bot_car.location,self.ball.location):
            target_location = self.ball.location + Vec3(0,math.copysign(150,target_location.x),0)
        for ally in self.allies:
            if self.bot_car.location.point_in_path(target_location - self.bot_car.location,ally.location):
                target_location = ally.location + Vec3(0,math.copysign(150,target_location.x),0)
                


        #drive toward target
        self.controls.throttle = 1.0
        self.steer_toward(self.bot_car,target_location)
        self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
        self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
        return
    #############################################################################################################################

    def defend(self,packet):
        #get the vector of the ball to where it will hit the goal (
        ball_to_goal = self.ball.velocity.flat()
        if ball_to_goal.length()!=0:
            ball_to_goal = ball_to_goal.rescale(((5120-abs(self.ball.location.y))/abs(ball_to_goal.y)))
        #target 2/3 way between ball and goal
        target_location = self.ball.location + ball_to_goal/1.5

        #get vector of ball from the cone of own net
        ideal_shot = self.ball.location.flat() - Vec3(0,-8000,0) if self.bot_car.team==0 else self.ball.location.flat() - Vec3(0,8000,0)
        #ideal shot is to corner if on other side of ball
        going_to_overtake_ball = (self.bot_car.location-Vec3(0,6000*(2*self.bot_car.team-1),0)).scalar_proj(self.ball.location-Vec3(0,6000*(2*self.bot_car.team-1),0))+100 > Vec3(0,6000*(2*self.bot_car.team-1),0).dist(self.ball.location)
        if going_to_overtake_ball:
            ideal_shot = Vec3(math.copysign(4096,(ball_to_goal+self.ball.location).x),(self.team*2-1)*5120,0) - self.ball.location
        

        
        
        #continue any strike after checking it
        if self.current_strike is not None:
            if check_strike(packet,self.ball_prediction,self.current_strike):
                
                #otherwise, continue on strike
                self.active_sequence, strike_controls, strike_location, strike_time = execute_strike(packet,self.bot_car,self.current_strike,self.foes,defence=True)
                self.controls = strike_controls
                self.renderer.draw_rect_3d(strike_location, 8, 8, True, self.renderer.red(), centered=True)
                self.renderer.draw_line_3d(self.bot_car.location, strike_location, self.renderer.white())
                self.renderer.draw_string_2d(20,20,3,3,f"throttle: {self.controls.throttle}",self.renderer.white())

                #drive out of goal > priority
                in_goal = self.bot_car.location.within(self.goal_corners[self.bot_car.team][0],self.goal_corners[self.bot_car.team][1])
                post0_ang = self.collision_posts[self.bot_car.team][0].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                std_ang_to_target = strike_location.__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                post1_ang = self.collision_posts[self.bot_car.team][1].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                between_posts = post0_ang < std_ang_to_target < post1_ang
                if not between_posts and in_goal:
                    target_location = Vec3(0,(2*self.team-1)*5000,0)
                    self.controls.throttle = 1
                    self.steer_toward(self.bot_car, target_location)
                    self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
                    self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
                    return

                return
            else:
                self.current_strike = None

       

        #try to find  strikes
        if self.ball.velocity.length()!=0 and self.current_strike is None and self.bot_car.stable:
            strikes = find_strikes(packet,self.ball_prediction,self.bot_car,ideal_shot,defence=True)
            for strike in strikes:
                if strike.strike_type==strike_types.simple_linear:
                    #linear, will check if line to strike location goes into net
                    post0_ang = self.posts[self.bot_car.team][0].__sub__(self.ball.location).flat().ang_to(Vec3(1,0,0))
                    car_slice_ang = (strike.slice_location - self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                    post1_ang = self.posts[self.bot_car.team][1].__sub__(self.ball.location).flat().ang_to(Vec3(1,0,0))
                    between_posts = post0_ang < car_slice_ang < post1_ang
                    if abs(self.bot_car.location.y)>abs(self.ball.location.y):
                        #clear if on correct side
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike
                    elif all(abs(ally.location.y-(1-ally.team*2)*6000) < abs(self.bot_car.location.y-(1-ally.team*2)*6000) or abs(ally.location.x)>2500 for ally in self.allies) and not between_posts:
                        #clear to corner
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike
                elif strike.strike_type==strike_types.linear_jump or strike.strike_type==strike_types.linear_dblj:                    
                    #linear, will check if line to strike location goes into net
                    post0_ang = self.posts[self.bot_car.team][0].__sub__(self.ball.location).flat().ang_to(Vec3(1,0,0))
                    car_slice_ang = (strike.slice_location - self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                    post1_ang = self.posts[self.bot_car.team][1].__sub__(self.ball.location).flat().ang_to(Vec3(1,0,0))
                    between_posts = post0_ang < car_slice_ang < post1_ang
                    if abs(self.bot_car.location.y)>abs(self.ball.location.y):
                        #clear if on correct side
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike
                    elif all(abs(ally.location.y-(1-ally.team*2)*6000) < abs(self.bot_car.location.y-(1-ally.team*2)*6000) or abs(ally.location.x)>2500 for ally in self.allies) and not between_posts:
                        #clear to corner
                        if self.current_strike is not None:
                            self.current_strike = strike if strike.slice_time<self.current_strike.slice_time else self.current_strike
                        else:
                            self.current_strike = strike

            #execute straight away
            if self.current_strike is not None:
                self.active_sequence, strike_controls, strike_location, strike_time = execute_strike(packet,self.bot_car,self.current_strike,self.foes,defence=True)
                self.controls = strike_controls
                self.renderer.draw_rect_3d(strike_location, 8, 8, True, self.renderer.red(), centered=True)
                self.renderer.draw_line_3d(self.bot_car.location, strike_location, self.renderer.white())
                self.renderer.draw_string_2d(20,20,3,3,f"throttle: {self.controls.throttle}",self.renderer.white())

                #drive out of goal > priority
                in_goal = self.bot_car.location.within(self.goal_corners[self.bot_car.team][0],self.goal_corners[self.bot_car.team][1])
                post0_ang = self.collision_posts[self.bot_car.team][0].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                std_ang_to_target = strike_location.__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                post1_ang = self.collision_posts[self.bot_car.team][1].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
                between_posts = post0_ang < std_ang_to_target < post1_ang
                if not between_posts and in_goal:
                    target_location = Vec3(0,(2*self.team-1)*5000,0)
                    self.controls.throttle = 1
                    self.steer_toward(self.bot_car, target_location)
                    self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
                    self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
                    return

                return
        """
        keep the rest for now, esp for defence
        """
        #changed to if car is further from goal than ball
        if Vec3(0,6000*(2*self.bot_car.team-1),0).dist(self.bot_car.location) > Vec3(0,6000*(2*self.bot_car.team-1),0).dist(self.ball.location)-100:
            offset = self.bot_car.vec_to_ball.flat().cross(Vec3(0,0,1)).normalized()
            if offset.y>0 and self.ball.velocity.y <0 or offset.y<0 and self.ball.velocity.y >0:
                offset = -offset
            target_location = target_location + 150*offset
            self.controls.throttle=1.0
            self.steer_toward(self.bot_car, target_location)
            self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
            self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
            return
        

        #Drive to the point, using atan to slow when close to the point (judged by d/v)
        est_time = -1
        try:
            est_time = self.bot_car.location.dist(target_location) / self.bot_car.velocity.flat().scalar_proj((target_location - self.bot_car.location).flat())
        except:
            stub="catch div 0"
        self.controls.throttle = (2*math.atan(est_time)/math.pi)*1.2-0.2 if est_time>0 else 1
        self.steer_toward(self.bot_car, target_location)
        self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
        self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
        return

    def support(self, packet, position:int):

        #continue any strike after checking it
        if self.current_strike is not None:
            if check_strike(packet,self.ball_prediction,self.current_strike) and self.current_strike.slice_time-packet.game_info.seconds_elapsed < 1.5:
                self.active_sequence, strike_controls, strike_location, strike_time = execute_strike(packet,self.bot_car,self.current_strike,self.foes)
                self.controls = strike_controls
                self.renderer.draw_rect_3d(strike_location, 8, 8, True, self.renderer.red(), centered=True)
                self.renderer.draw_line_3d(self.bot_car.location, strike_location, self.renderer.white())
                self.renderer.draw_string_2d(20,20,3,3,f"throttle: {self.controls.throttle}",self.renderer.white())
                return
            else:
                self.current_strike = None
        
        target_location = Vec3(0,0,0)
        if position==1:        
            target_location = self.ball.location.flat() + Vec3(-self.ball.location.x/2,(self.bot_car.team*2-1)*3000,0)

        else:
            target_location = self.ball.location.flat() + (Vec3(0,(self.bot_car.team*2-1)*6500,0) - self.ball.location.flat()).rescale(6000)

        target_location = self.point_in_field(target_location)

        #second man in net on defence, or if would drive up wall
        if self.ball.location.y *(2*self.bot_car.team-1)>0 and self.ball.velocity.y *(2*self.bot_car.team-1)>0 or abs(target_location.y)>4600:
            target_location = Vec3(0,5200*(2*self.bot_car.team-1),0)
            #if it needs to drive around posts, do it
            in_goal = self.bot_car.location.within(self.goal_corners[self.bot_car.team][0],self.goal_corners[self.bot_car.team][1])
            post0_ang = self.collision_posts[self.bot_car.team][0].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
            std_ang_to_target = target_location.__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
            facing_ang = self.bot_car.orientation.forward.ang_to(Vec3(1,0,1))
            post1_ang = self.collision_posts[self.bot_car.team][1].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
            travel_between_posts = post0_ang < std_ang_to_target < post1_ang
            facing_between_posts = post0_ang < facing_ang < post1_ang
            if not in_goal and not travel_between_posts:
                target_location = Vec3(0,5000*(2*self.bot_car.team-1),0)
            for ally in self.allies:
                if ally.location.within(self.goal_corners[self.bot_car.team][0],self.goal_corners[self.bot_car.team][1]):
                    target_location = Vec3(-1*math.copysign(950,self.ball.location.x),4900,0)

            self.controls.throttle = min(self.bot_car.location.dist(target_location)**2/1000**2,1)
            if in_goal and self.bot_car.orientation.forward.y*(1-2*self.bot_car.team) >0.7 and abs(self.bot_car.location.y) <5220:
                self.controls.throttle = 0 if self.bot_car.velocity.length() <20 else -1*math.copysign(1,self.bot_car.velocity.dot(self.bot_car.orientation.forward))
            self.steer_toward(self.bot_car, target_location)
            self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
            self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
            return

        #exit goal if needed
        ##try:
        in_goal = self.bot_car.location.within(self.goal_corners[self.bot_car.team][0],self.goal_corners[self.bot_car.team][1])
        post0_ang = self.collision_posts[self.bot_car.team][0].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
        std_ang_to_target = target_location.__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
        post1_ang = self.collision_posts[self.bot_car.team][1].__sub__(self.bot_car.location).flat().ang_to(Vec3(1,0,0))
        between_posts = post0_ang < std_ang_to_target < post1_ang
        if not between_posts and in_goal:
            target_location = Vec3(0,(2*self.team-1)*5000,0)
            self.controls.throttle = min(self.bot_car.location.dist(target_location)**2/800**2+0.1,1)
            self.steer_toward(self.bot_car, target_location)
            self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
            self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
            return
        ##except:
            ##stub="catch div 0 errors"

        self.controls.throttle = min(self.bot_car.location.dist(target_location)**2/1000**2,1)
        self.steer_toward(self.bot_car, target_location)
        self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)
        self.renderer.draw_line_3d(self.bot_car.location, target_location, self.renderer.white())
        return

    def perform_air_recovery(self, packet):
        try:
            self.controls.steer = self.bot_car.orientation.right.dot(self.bot_car.velocity.flat().normalized())
            self.controls.pitch = self.bot_car.orientation.up.dot(self.bot_car.velocity.flat().normalized())
            self.controls.roll = self.bot_car.orientation.right.dot(Vec3(0,0,1))
        except:
            stub="I'm too lazy to catch div 0 properly"
        return
Exemple #17
0
class MyBot(BaseAgent):

  # Default constructor
  def __init__(self, name, team, index):
    super().__init__(name, team, index)
    self.active_sequence: Sequence = None
    self.boost_pad_tracker = BoostPadTracker()

  # Track boost pad information
  def initialize_agent(self): self.boost_pad_tracker.initialize_boosts(self.get_field_info())

  # Main controller function - called many times per second
  def get_output(self, packet: GameTickPacket) -> SimpleControllerState:

    # Get currently active boost pad info
    self.boost_pad_tracker.update_boost_status(packet)

    # Continue sequences from previous call
    if self.active_sequence and not self.active_sequence.done:
      controls = self.active_sequence.tick(packet)
      if controls is not None: return controls

    # Gather information about car and ball
    my_car = packet.game_cars[self.index]
    car_location = Vec3(my_car.physics.location)
    car_velocity = Vec3(my_car.physics.velocity)
    ball_location = Vec3(packet.game_ball.physics.location)

    if car_location.dist(ball_location) > 1500:
      # Set path of car to future ball location
      ball_prediction = self.get_ball_prediction_struct()  # This can predict bounces, etc
      ball_in_future = find_slice_at_time(ball_prediction, packet.game_info.seconds_elapsed + 2)
      target_location = Vec3(ball_in_future.physics.location)
      self.renderer.draw_line_3d(ball_location, target_location, self.renderer.cyan())
    else:
      target_location = ball_location

    # Draw rendering lines
    self.renderer.draw_line_3d(car_location, target_location, self.renderer.white())
    self.renderer.draw_string_3d(car_location, 1, 1, f'Speed: {car_velocity.length():.1f}', self.renderer.white())
    self.renderer.draw_rect_3d(target_location, 8, 8, True, self.renderer.cyan(), centered=True)

    # Front flip if car is moving at a certain speed
    if 750 < car_velocity.length() < 800: return self.begin_front_flip(packet)

    controls = SimpleControllerState()
    controls.steer = steer_toward_target(my_car, target_location)
    controls.throttle = 1.0

    return controls

  # Car flip function
  def begin_front_flip(self, packet):

    # Do a front flip
    self.active_sequence = Sequence([
      ControlStep(duration=0.05, controls=SimpleControllerState(jump=True)),
      ControlStep(duration=0.05, controls=SimpleControllerState(jump=False)),
      ControlStep(duration=0.2, controls=SimpleControllerState(jump=True, pitch=-1)),
      ControlStep(duration=0.8, controls=SimpleControllerState()),
    ])

    # Return the controls associated with the beginning of the sequence
    return self.active_sequence.tick(packet)
Exemple #18
0
 def __init__(self, name, team, index):
     super().__init__(name, team, index)
     self.active_sequence: Sequence = None
     self.boost_pad_tracker = BoostPadTracker()
Exemple #19
0
class Agent(DecisionAgent):


    def __init__(self, name, team, index):
        super().__init__(name, team, index)
        self.active_sequence: Sequence = None
        self.boost_pad_tracker = BoostPadTracker()
        self.init_db()
    
    
    def initialize_agent(self):
        # Set up information about the boost pads now that the game is active and the info is available
        self.boost_pad_tracker.initialize_boosts(self.get_field_info())
    

    def init_db(self):
        self.client = pymongo.MongoClient("mongodb+srv://first_child:[email protected]/RocketBot?retryWrites=true&w=majority")
        self.db = self.client.get_database("RocketBot")
        self.flip_physics = self.db.get_collection("flip_physics")
    

    def write_flip_physics(self, flip_physics):
        if flip_physics is None:
            log_warn("Attempt to write None to database. Nothing will be written.", {})
            return
        self.flip_physics.insert_one(flip_physics)


    def draw_state(self, parsed_packet: ParsedPacket, packet: rl.GameTickPacket):
        # Draw ball prediction line for where the ball is going to go
        ball_prediction = self.get_ball_prediction_struct()
        slices = list(map(lambda x : Vector(x.physics.location), ball_prediction.slices))
        self.renderer.draw_polyline_3d(slices[::10], self.renderer.white())

        # Write to the car the appropriate string
        self.write_string(parsed_packet.my_car.physics.location, self.display_on_car(parsed_packet, packet))

        # Determine whether or not the ball is going to go into the goal
        goal_overlap: Vector = self.get_goal_overlap()
        if goal_overlap is not None:        # The ball is going in
            self.draw_circle(goal_overlap, 100)

    def get_goal_overlap(self) -> Vector:
        ball_prediction = self.get_ball_prediction_struct()
        slices = list(map(lambda x : Vector(x.physics.location), ball_prediction.slices))
        threshold = self.field_info.my_goal.location.y
        for (index, loc) in enumerate(slices):
            if abs(loc.y) < threshold:
                continue
            if index < len(slices) - 1 and abs(slices[index + 1].y) < threshold:
                continue
            return loc

    colissions: int = 0

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        # Parse the packet to gather relevant information
        parsed_packet = parse_packet(self.team, packet)
        my_car = parsed_packet.my_car
        ball = parsed_packet.ball
        self.field_info = parse_field_info(self.team, self.get_field_info())

        # Draw the ball if appropriate
        legend_entries: [LegendEntry] = []
        if self.WRITE_STATE:
            state: str = f"{self.state}"
            legend_entries += [
                LegendEntry(f"{self.state.__class__.__name__}", self.renderer.white()),
            ]

        if self.DRAW_BALL_PHYSICS:
            legend_entries += [
                LegendEntry("Velocity", self.renderer.green()),
                LegendEntry("Angular Velocity", self.renderer.blue()),
            ]
            self.draw_physics_info(ball_physics)
        

        # self.draw_car_hitbox(parsed_packet.my_car.physics.location, parsed_packet.my_car.hitbox, Orientation(parsed_packet.my_car.physics.rotation))
        # Draw if the car is currently colliding with the ball
        if __is_colliding(
            parsed_packet.my_car.physics.location,
            parsed_packet.my_car.hitbox,
            Orientation(parsed_packet.my_car.physics.rotation),
            parsed_packet.ball.physics.location,
            parsed_packet.ball.hitbox
        ):
            self.colissions += 1

        # legend_entries.append(LegendEntry(f"Colissions: {self.colissions}", self.renderer.orange()))
        self.draw_legend(legend_entries)

        # Draw the state / debug information
        self.draw_state(parsed_packet, packet)

        # Keep our boost pad info updated with which pads are currently active
        self.boost_pad_tracker.update_boost_status(packet)

        # For fernado, make the bot shit talk a little bit
        if (my_car.physics.location.dist(ball.physics.location)) < 165:
            self.send_quick_chat(team_only=False, quick_chat=QuickChatSelection.Reactions_CloseOne)
            if self.current_flip_physics:
                self.current_flip_physics["contact"] = True

        # Check for current sequence and continue sequence if there is one
        if self.active_sequence and not self.active_sequence.done:
            controls = self.active_sequence.tick(packet)
            if controls is not None:
                self.prev_seq_done = False
                continue_sequence = self.sequence_hook(controls)
                if continue_sequence:
                    return controls

        # Determine game state (different from draw state)
        self.state = self.next_state(parsed_packet, packet)
        return self.state.get_output(parsed_packet, packet, self)