Exemple #1
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

    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)

        """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 air recovery atm)
        if self.bot_car.grounded and self.bot_car.team==0:
            car_state0= CarState(boost_amount=45, physics=Physics(velocity=Vector3(x=randint(-1000,1000),y=randint(-1000,1000),z=randint(-1000,1000)),location=Vector3(x=0,y=-2608,z=1000),rotation=Rotator(randint(-300,300)/100,randint(-300,300)/100,randint(-300,300)/100),angular_velocity=Vector3(randint(-300,300)/100,randint(-300,300)/100,randint(-300,300)/100)))
            car_state1= CarState(boost_amount=45, physics=Physics(velocity=Vector3(x=randint(-1000,1000),y=randint(-1000,1000),z=randint(-1000,1000)),location=Vector3(x=0,y=2608,z=1000),rotation=Rotator(randint(-300,300)/100,randint(-300,300)/100,randint(-300,300)/100),angular_velocity=Vector3(randint(-300,300)/100,randint(-300,300)/100,randint(-300,300)/100)))
            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}))
        """
        
        """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 #2
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 #3
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 #4
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 #5
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.jumping = 0

    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
            if last > 1:
                return (nearest - 1) / (last - 1), nearest
            else:
                return 0, 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
                return 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)

        def deja_vu():
            if car_velocity.length() > 100:
                point_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))
                controls.handbrake = (
                    (target_location - car_location) * safe_div(
                        (target_location - car_location).length()) -
                    point_direction).length() > 0.2

        # Modes
        def demo():
            nearest = None
            best_time = math.inf
            last = True
            for i in range(len(packet.game_cars)):
                if packet.game_cars[i].team != self.team and Vec3(
                        packet.game_cars[i].physics.location).z > 0:
                    time_taken = (Vec3(packet.game_cars[i].physics.location) -
                                  car_location).length()
                    if time_taken < best_time:
                        best_time = time_taken
                        nearest = packet.game_cars[i]
            # Get location
            target_location = Vec3(
                nearest.physics.location) + Vec3(nearest.physics.velocity) * (
                    (Vec3(nearest.physics.location) - car_location).length() -
                    30) * safe_div(car_velocity.length())
            controls.throttle = 1
            controls.boost = abs(steer_toward_target(
                my_car,
                target_location)) <= 0.1 and car_velocity.length() < 2200
            self.renderer.draw_line_3d(car_location, target_location,
                                       self.renderer.black())
            self.renderer.draw_rect_3d(target_location,
                                       8,
                                       8,
                                       True,
                                       self.renderer.black(),
                                       centered=True)
            return target_location

        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)
            # 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 nearest_car == 0
            # 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
                self.jumping = 0
            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 / 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" and False:
                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 = (target_location -
                                 car_location).length() / 1000
            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:
                return 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:
                        return 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:
                            return self.jump_once(packet)
                        controls.yaw = steer_toward_target(
                            my_car,
                            send_location) - my_car.physics.angular_velocity.z
                    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
                    self.jumping = 0
                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 = -car_rotation.roll
                controls.pitch = -car_rotation.pitch
                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 = math.pi / 2 * sign(car_velocity.y) * sign(
                    abs(car_rotation.yaw) - math.pi / 2) - car_rotation.roll
                controls.pitch = point - car_rotation.yaw
                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
        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)
        nearest_car, 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 = ""

        # 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:
            return 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 nearest_car == 0:
                if in_goal:
                    mode = "Attack"
                else:
                    mode = "Defense"
            elif nearest_car < 1:
                if my_car.boost == 100 and car_index == 2:
                    mode = "Standby"
                else:
                    mode = "Refuel"
            elif nearest_car < 1:
                if my_car.boost >= 50 or car_velocity.length() >= 2200:
                    mode = "Demo"
                else:
                    mode = "Refuel"
            else:
                mode = "Goalie"

        # Recovery
        if self.jumping >= 1:
            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())

        self.jumping += 1 / 60

        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)
Exemple #6
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)