-
Notifications
You must be signed in to change notification settings - Fork 81
Input and Output Data
Every tick, your bot will receive a GameTickPacket from the framework. The packet will contain all the raw values from the game (such as car and ball locations). Your bot receives the packet in the get_output(self, packet)
function and you should return a ControllerState which describes what your bot's response is.
Getting values from the packet is simple:
def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
# You can get values out of the packet like this:
x_location_of_first_car = packet.game_cars[0].physics.location.x;
NOTE: Some structs/lists in the GameTickPacket has a fixed length. So make sure you use the num_cars
and the num_boosts
values as lengths if you iterate through the associated lists.
packet: {
'game_cars': [
{
'physics': {
'location': {'x': 0.0, 'y': 0.0, 'z': 0.0},
'rotation': {'pitch': 0.0, 'yaw': 0.0, 'roll': 0.0},
'velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0},
'angular_velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0}
},
'score_info': {
'score': 350,
'goals': 1,
'own_goals': 0,
'assists': 1,
'saves': 0,
'shots': 2,
'demolitions': 0,
},
'is_demolished': False,
'has_wheel_contact': True,
'is_super_sonic': False,
'is_bot': True,
'jumped': False,
'double_jumped': True,
'name': 'Jupiter',
'team': 0,
'boost': 48.0
},
{ ... }
],
'num_cars': 2,
'game_boosts': [
{
'is_active': True,
'timer': 0.0
},
{ ... }
],
'num_boost': 36,
'game_ball': {
'physics': {
'location': {'x': 0.0, 'y': 0.0, 'z': 0.0},
'rotation': {'pitch': 0.0, 'yaw': 0.0, 'roll': 0.0},
'velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0},
'angular_velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0}
},
'latest_touch': {
'player_name': 'Beavis',
'time_seconds': 120.63,
'hit_location': {'x': 0.0, 'y': 0.0, 'z': 0.0},
'hit_normal': {'x': 0.0, 'y': 0.0, 'z': 0.0}
},
'drop_shot_info': {
'damage_index': 0,
'absorbed_force': 0,
'force_accum_recent': 0
}
},
'game_info': {
'seconds_elapsed': 405.12,
'game_time_remaining': 34.88,
'is_overtime': False,
'is_unlimited_time': False,
'is_round_active': True,
'is_kickoff_pause': False,
'is_match_ended': False,
'world_gravity_z': -650.0,
'game_speed': 1.0
},
'dropshot_tiles': [
{
'tile_state': 0 // UNKNOWN
},
{
'tile_state': 1 // FILLED
},
{
'tile_state': 2 // DAMAGED
},
{
'tile_state': 3 // OPEN
}
],
'num_tiles': 140,
'teams': [
{
'team_index': 0,
'score': 7
},
{ ... }
],
'num_teams': 2,
}
A ControllerState is the controller input the bot should perform. Import ControllerState like this: from rlbot.agents.base_agent import SimpleControllerState
, and create a new instance with SimpleControllerState()
Example:
from rlbot.agents.base_agent import BaseAgent, SimpleControllerState
from rlbot.utils.structures.game_data_struct import GameTickPacket
class ExampleBot(BaseAgent):
def initialize_agent(self):
pass
def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
# Make the bot go forwards by setting throttle to 1
controller = SimpleControllerState()
controller.throttle = 1
return controller
The ControllerState has the following attributes:
table ControllerState {
throttle:float; /// -1 for full reverse, 1 for full forward
steer:float; /// -1 for full left, 1 for full right
pitch:float; /// -1 for nose down, 1 for nose up
yaw:float; /// -1 for full left, 1 for full right
roll:float; /// -1 for roll left, 1 for roll right
jump:bool; /// true if you want to press the jump button
boost:bool; /// true if you want to press the boost button
handbrake:bool; /// true if you want to press the handbrake button
}
A few values are constant, like the locations of boosts and goals. Some of these can be found in the FieldInfo data. FieldInfo contains the following:
field_info: {
'boost_pads': [
{
'location': Vector3,
'is_full_boost': boolean
},
{ ... }
],
'num_boosts': int,
'goals': [
{
'team_num': int,
'location': Vector3,
'direction': Vector3
},
{ ... }
],
'num_goals': int
}
Note: Dropshot tiles can be found in FieldInfo as GoalInfo objects.
Note2: Boost pads and Dropshot tiles will be sorted according to y * 100 + x
, just like their counterparts (game_boosts
and dropshot_tiles
that contain their current state) in the game tick packet.
In Python, you can retrieve this information by calling get_field_info()
on the BaseAgent:
from rlbot.agents.base_agent import BaseAgent, SimpleControllerState
from rlbot.utils.structures.game_data_struct import GameTickPacket
class ExampleBot(BaseAgent):
def initialize_agent(self):
pass
def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
# Constant values can be found the the FieldInfo:
info = self.get_field_info()
# Manually construct a list of all big boost pads
# info.boost_pads has a fixed size but info.num_boosts is how many pads there actually are
big_pads = []
for i in range(info.num_boosts):
pad = info.boost_pads[i]
if pad.is_full_boost:
big_pads.append(pad)
You can find descriptions of the tricky values in this file:
https://github.com/RLBot/RLBot/blob/master/src/main/flatbuffers/rlbot.fbs
You will recognize some of the previous mentioned classes as tables. I.e. packet.score_info
is a ScoreInfo table.