Learn how to program
by playing video games.

RLBot Rocket League Botting Tutorial

Your First Rocket League Bot: BoostHog!

December 28, 2019
Part of: RLBot Rocket League Botting Tutorial

Let's write the code for our basic boost stealing bot! Conceptually it's simple: 1. Figure out where the boosts are located on the pitch and 2. Tell our car to drive to the nearest boost we find. In this video, I take you step-by-step through how I would write this code in Python.

If you'd like to learn Python by making a game AI, this is a great beginner project to get you started.

Links
GitHub repo for this project: https://github.com/learncodebygaming/rlbot_boosthog
Download RLBot: https://www.rlbot.org/
RLBot Wiki for Input and Output Data: https://github.com/RLBot/RLBotPythonExample/wiki/Input-and-Output-Data

So our goal again is simple: we just need to find the nearest boost and go get it.

To begin, let's dig into the data. Make sure you have the "Input and Output Data" section of the RLBot wiki open. Looking through the example GameTickPacket there, we can see that it contains some information about the boosts (whether a boost is active or not, and when it will respawn if not) but it doesn't contain the information we need: the location of the boosts.

Scrolling further down this page in the documentation, we get to see how the SimpleControllerState is structured. It's a simple dictionary with all the input values.

Keep scrolling down until you come to the Field Info section. In the example data, we can immediately see that this contains the information we need: the location vector of each boost pad. Certain information never changes during the course of a game, like the boost and goal locations, so these values are kept separate from the dynamic game tick information. Our bot can use the self.get_field_info() method to access this data.

Let's confirm that the packet and the field info contain the data we expect from reading the documentation. One option is to simply print the values we're interested in to the console. But since the console would quickly fill with text each tick, it would be nicer to write these values to the Rocket League game window itself.

To do that, we can modify draw_debug() to call renderer.draw_string_2d() with the text we want to see. I'll add a new parameter to draw_debug() to pass along the string we want to draw from the main game loop.

def draw_debug(renderer, car, target, action_display, corner_debug=None):
    renderer.begin_rendering()
    # draw a line from the car to the target
    renderer.draw_line_3d(car.physics.location, target, renderer.white())
    # print the action that the bot is taking
    renderer.draw_string_3d(car.physics.location, 2, 2, action_display, renderer.white())
    # print the corner debug string
    # adjust y position depending on how many lines of text there are
    if corner_debug:
        corner_display_y = 900 - (corner_debug.count('\n') * 20)
        renderer.draw_string_2d(10, corner_display_y, 1, 1, corner_debug, renderer.white())
    renderer.end_rendering()  

Now that we've confirmed how the boost information can be accessed from the field info and the game tick packet, it's time to use that information to figure out which boost is closest to our car. To do that, we simply loop over all the boosts, ignore the small and inactive boosts, and calculate the distance to each boost by using car_location.dist(), which is a function provided to us by the Vec3 class. When we've identified the nearest boost, we can return that from our get_nearest_boost() helper function.

def get_nearest_boost(info, packet, car_location):
    nearest_boost_loc = None

    # loop over all the boosts
    for i, boost in enumerate(info.boost_pads):
        # only want large boosts that haven't been taken
        if boost.is_full_boost and packet.game_boosts[i].is_active:
            # if we haven't found any boosts yet, use this one
            if not nearest_boost_loc:
                nearest_boost_loc = boost.location
            else:
                # if this boost is closer, save that
                if car_location.dist(Vec3(boost.location)) < car_location.dist(Vec3(nearest_boost_loc)):
                    nearest_boost_loc = boost.location

    return Vec3(nearest_boost_loc)

Confirm that get_nearest_boost() is working for you by printing its return value in the corner debug string. If everything looks good, we can now use that location instead of the ball location in get_output() to tell our car to drive to the boost we've identified. You'll also want to tell your bot to use the boost it collects by setting self.controller_state.boost = True. You now have a functional boost stealer!

If you run your bot in a couple games, you'll quickly notice a few issues, though. First, you'll want to update draw_debug() to draw a line to the boost your bot is grabbing instead of to the ball.

You might also notice that it'd be better to go for the ball on kickoff, and only boost steal after that. In preparation for doing this in the next video, I recommend moving the logic in the middle of your get_output() method to its own generic action_goto() function. We want this function to allow us to steer our car towards any location we give it. You should test this by alternating between giving it the ball location and the nearest boost location. Remember you can change the code while your bot is playing.

The major issue you'll notice is all the errors we get in the console when all the large boosts are taken (run BoostHog 3v3 against itself if you haven't seen this). We'll discuss strategies for fixing this in the next tutorial. There we'll also introduce some intelligent decision making into our bot, so it's not merely chasing boost all the time.


Coding a simple Artificial Intelligence for Rocket League
Basic video game AI is built up from many simpler components whose actions are coordinated by decision making logic. Complex behavior emerges as we add …
Ben Johnson My name is Ben and I help people learn how to code by gaming. I believe in the power of project-based learning to foster a deep understanding and joy in the craft of software development. On this site I share programming tutorials, coding-game reviews, and project ideas for you to explore.