-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathbot.py
More file actions
128 lines (103 loc) · 5.25 KB
/
bot.py
File metadata and controls
128 lines (103 loc) · 5.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from typing import override
from rlbot.flat import BallAnchor, ControllerState, GamePacket
from rlbot.managers import Bot
from rlbot_flatbuffers import CarAnchor
from util.ball_prediction_analysis import find_slice_at_time
from util.boost_pad_tracker import BoostPadTracker
from util.drive import steer_toward_target
from util.sequence import ControlStep, Sequence
from util.vec import Vec3
class MyBot(Bot):
active_sequence: Sequence | None = None
boost_pad_tracker: BoostPadTracker = BoostPadTracker()
@override
def initialize(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.field_info)
@override
def get_output(self, packet: GamePacket) -> ControllerState:
"""
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)
if len(packet.balls) == 0:
# If there are no balls current in the game (likely due to being in a replay), skip this tick.
return ControllerState()
# we can now assume there's at least one ball in the match
# 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:
return self.active_sequence.tick(packet)
# Gather some information about our car and the ball
my_car = packet.players[self.index]
car_location = Vec3(my_car.physics.location)
car_velocity = Vec3(my_car.physics.velocity)
ball_location = Vec3(packet.balls[0].physics.location)
# By default we will chase the ball, but target_location can be changed later
target_location = ball_location
self.renderer.begin_rendering()
if car_location.dist(ball_location) > 1500:
# We're far away from the ball, let's try to lead it a little bit
# self.ball_prediction can predict bounces, etc
ball_in_future = find_slice_at_time(
self.ball_prediction, packet.match_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)
# BallAnchor(0) will dynamically start the point at the ball's current location
# 0 makes it reference the ball at index 0 in the packet.balls list
self.renderer.draw_line_3d(
BallAnchor(0), target_location, self.renderer.cyan
)
# Draw some things to help understand what the bot is thinking
self.renderer.draw_line_3d(
CarAnchor(self.index), target_location, self.renderer.white
)
self.renderer.draw_string_3d(
f"Speed: {car_velocity.length():.1f}",
CarAnchor(self.index),
1,
self.renderer.white,
)
self.renderer.draw_line_3d(
target_location - Vec3(0, 0, 50),
target_location + Vec3(0, 0, 50),
self.renderer.cyan,
)
self.renderer.end_rendering()
if 750 < car_velocity.length() < 800:
# We'll do a front flip if the car is moving at a certain speed.
return self.begin_front_flip(packet)
controls = ControllerState()
controls.steer = steer_toward_target(my_car, target_location)
controls.throttle = 1.0
# You can set more controls if you want, like controls.boost.
return controls
def begin_front_flip(self, packet: GamePacket) -> ControllerState:
# Send some quickchat just for fun
# There won't be any content of the message for other bots,
# but "I got it!" will be display for a human to see!
self.send_match_comm(b"", "I got it!")
# 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=ControllerState(jump=True)),
ControlStep(duration=0.05, controls=ControllerState(jump=False)),
ControlStep(
duration=0.2, controls=ControllerState(jump=True, pitch=-1)
),
ControlStep(duration=0.8, controls=ControllerState()),
]
)
# Return the controls associated with the beginning of the sequence so we can start right away.
return self.active_sequence.tick(packet)
if __name__ == "__main__":
# Connect to RLBot and run
# Having the agent id here allows for easier development,
# as otherwise the RLBOT_AGENT_ID environment variable must be set.
MyBot("rlbot_community/python_example").run()