Skip to content

Commit 9b29b71

Browse files
authored
Adding Noob Black (#332)
* Add files via upload * Update bot.cfg
1 parent 14cea34 commit 9b29b71

File tree

13 files changed

+985
-0
lines changed

13 files changed

+985
-0
lines changed

RLBotPack/Noob_Black/src/__init__.py

Whitespace-only changes.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# You don't have to manually edit this file!
2+
# RLBotGUI has an appearance editor with a nice colorpicker, database of items and more!
3+
# To open it up, simply click the (i) icon next to your bot's name and then click Edit Appearance
4+
5+
[Bot Loadout]
6+
team_color_id = 60
7+
custom_color_id = 0
8+
car_id = 23
9+
decal_id = 0
10+
wheels_id = 1565
11+
boost_id = 35
12+
antenna_id = 0
13+
hat_id = 0
14+
paint_finish_id = 1681
15+
custom_finish_id = 1681
16+
engine_audio_id = 0
17+
trails_id = 3220
18+
goal_explosion_id = 3018
19+
20+
[Bot Loadout Orange]
21+
team_color_id = 3
22+
custom_color_id = 0
23+
car_id = 23
24+
decal_id = 0
25+
wheels_id = 1565
26+
boost_id = 35
27+
antenna_id = 0
28+
hat_id = 0
29+
paint_finish_id = 1681
30+
custom_finish_id = 1681
31+
engine_audio_id = 0
32+
trails_id = 3220
33+
goal_explosion_id = 3018
34+
35+
[Bot Paint Blue]
36+
car_paint_id = 12
37+
decal_paint_id = 0
38+
wheels_paint_id = 7
39+
boost_paint_id = 7
40+
antenna_paint_id = 0
41+
hat_paint_id = 0
42+
trails_paint_id = 2
43+
goal_explosion_paint_id = 0
44+
45+
[Bot Paint Orange]
46+
car_paint_id = 12
47+
decal_paint_id = 0
48+
wheels_paint_id = 14
49+
boost_paint_id = 14
50+
antenna_paint_id = 0
51+
hat_paint_id = 0
52+
trails_paint_id = 14
53+
goal_explosion_paint_id = 0

RLBotPack/Noob_Black/src/bot.cfg

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[Locations]
2+
# Path to loadout config. Can use relative path from here.
3+
looks_config = ./appearance.cfg
4+
5+
# Path to python file. Can use relative path from here.
6+
python_file = ./bot.py
7+
8+
# Name of the bot in-game
9+
name = Noob Black
10+
11+
# The maximum number of ticks per second that your bot wishes to receive.
12+
maximum_tick_rate_preference = 120
13+
14+
[Details]
15+
# These values are optional but useful metadata for helper programs
16+
# Name of the bot's creator/developer
17+
developer = Scumclass
18+
19+
# Short description of the bot
20+
description = Noob Bot V3, made with code from the black market.
21+
As always, mainly designed for 3s.
22+
23+
# Fun fact about the bot
24+
fun_fact = The bot has a Roblox background.
25+
26+
# Tags
27+
tags = teamplay
28+
29+
# Link to github repository
30+
github = https://github.com/RLBot/RLBotPythonExample
31+
32+
# Programming language
33+
language = python

RLBotPack/Noob_Black/src/bot.py

Lines changed: 528 additions & 0 deletions
Large diffs are not rendered by default.

RLBotPack/Noob_Black/src/logo.png

3.63 KB
Loading

RLBotPack/Noob_Black/src/util/__init__.py

Whitespace-only changes.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from typing import Callable
2+
3+
from rlbot.utils.structures.ball_prediction_struct import BallPrediction, Slice
4+
5+
# field length(5120) + ball radius(93) = 5213 however that results in false positives
6+
GOAL_THRESHOLD = 5235
7+
8+
# We will jump this number of frames when looking for a moment where the ball is inside the goal.
9+
# Big number for efficiency, but not so big that the ball could go in and then back out during that
10+
# time span. Unit is the number of frames in the ball prediction, and the prediction is at 60 frames per second.
11+
GOAL_SEARCH_INCREMENT = 20
12+
13+
14+
def find_slice_at_time(ball_prediction: BallPrediction, game_time: float):
15+
"""
16+
This will find the future position of the ball at the specified time. The returned
17+
Slice object will also include the ball's velocity, etc.
18+
"""
19+
start_time = ball_prediction.slices[0].game_seconds
20+
approx_index = int((game_time - start_time) * 60) # We know that there are 60 slices per second.
21+
if 0 <= approx_index < ball_prediction.num_slices:
22+
return ball_prediction.slices[approx_index]
23+
return None
24+
25+
26+
def predict_future_goal(ball_prediction: BallPrediction):
27+
"""
28+
Analyzes the ball prediction to see if the ball will enter one of the goals. Only works on standard arenas.
29+
Will return the first ball slice which appears to be inside the goal, or None if it does not enter a goal.
30+
"""
31+
return find_matching_slice(ball_prediction, 0, lambda s: abs(s.physics.location.y) >= GOAL_THRESHOLD,
32+
search_increment=20)
33+
34+
35+
def find_matching_slice(ball_prediction: BallPrediction, start_index: int, predicate: Callable[[Slice], bool],
36+
search_increment=1):
37+
"""
38+
Tries to find the first slice in the ball prediction which satisfies the given predicate. For example,
39+
you could find the first slice below a certain height. Will skip ahead through the packet by search_increment
40+
for better efficiency, then backtrack to find the exact first slice.
41+
"""
42+
for coarse_index in range(start_index, ball_prediction.num_slices, search_increment):
43+
if predicate(ball_prediction.slices[coarse_index]):
44+
for j in range(max(start_index, coarse_index - search_increment), coarse_index):
45+
ball_slice = ball_prediction.slices[j]
46+
if predicate(ball_slice):
47+
return ball_slice
48+
return None
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from dataclasses import dataclass
2+
from typing import List
3+
4+
from rlbot.utils.structures.game_data_struct import GameTickPacket, FieldInfoPacket
5+
6+
from util.vec import Vec3
7+
8+
9+
@dataclass
10+
class BoostPad:
11+
location: Vec3
12+
is_full_boost: bool
13+
is_active: bool # Active means it's available to be picked up
14+
timer: float # Counts the number of seconds that the pad has been *inactive*
15+
16+
17+
class BoostPadTracker:
18+
"""
19+
This class merges together the boost pad location info with the is_active info so you can access it
20+
in one convenient list. For it to function correctly, you need to call initialize_boosts once when the
21+
game has started, and then update_boost_status every frame so that it knows which pads are active.
22+
"""
23+
24+
def __init__(self):
25+
self.boost_pads: List[BoostPad] = []
26+
self._full_boosts_only: List[BoostPad] = []
27+
28+
def initialize_boosts(self, game_info: FieldInfoPacket):
29+
raw_boosts = [game_info.boost_pads[i] for i in range(game_info.num_boosts)]
30+
self.boost_pads: List[BoostPad] = [BoostPad(Vec3(rb.location), rb.is_full_boost, False, 0) for rb in raw_boosts]
31+
# Cache the list of full boosts since they're commonly requested.
32+
# They reference the same objects in the boost_pads list.
33+
self._full_boosts_only: List[BoostPad] = [bp for bp in self.boost_pads if bp.is_full_boost]
34+
35+
def update_boost_status(self, packet: GameTickPacket):
36+
for i in range(packet.num_boost):
37+
our_pad = self.boost_pads[i]
38+
packet_pad = packet.game_boosts[i]
39+
our_pad.is_active = packet_pad.is_active
40+
our_pad.timer = packet_pad.timer
41+
42+
def get_full_boosts(self) -> List[BoostPad]:
43+
return self._full_boosts_only
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import math
2+
3+
from rlbot.utils.structures.game_data_struct import PlayerInfo
4+
5+
from util.orientation import Orientation, relative_location
6+
from util.vec import Vec3
7+
8+
9+
def limit_to_safe_range(value: float) -> float:
10+
"""
11+
Controls like throttle, steer, pitch, yaw, and roll need to be in the range of -1 to 1.
12+
This will ensure your number is in that range. Something like 0.45 will stay as it is,
13+
but a value of -5.6 would be changed to -1.
14+
"""
15+
if value < -1:
16+
return -1
17+
if value > 1:
18+
return 1
19+
return value
20+
21+
22+
def steer_toward_target(car: PlayerInfo, target: Vec3) -> float:
23+
relative = relative_location(Vec3(car.physics.location), Orientation(car.physics.rotation), target)
24+
angle = math.atan2(relative.y, relative.x)
25+
return limit_to_safe_range(angle * 5)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import math
2+
3+
from util.vec import Vec3
4+
5+
6+
# This is a helper class for calculating directions relative to your car. You can extend it or delete if you want.
7+
class Orientation:
8+
"""
9+
This class describes the orientation of an object from the rotation of the object.
10+
Use this to find the direction of cars: forward, right, up.
11+
It can also be used to find relative locations.
12+
"""
13+
14+
def __init__(self, rotation):
15+
self.yaw = float(rotation.yaw)
16+
self.roll = float(rotation.roll)
17+
self.pitch = float(rotation.pitch)
18+
19+
cr = math.cos(self.roll)
20+
sr = math.sin(self.roll)
21+
cp = math.cos(self.pitch)
22+
sp = math.sin(self.pitch)
23+
cy = math.cos(self.yaw)
24+
sy = math.sin(self.yaw)
25+
26+
self.forward = Vec3(cp * cy, cp * sy, sp)
27+
self.right = Vec3(cy*sp*sr-cr*sy, sy*sp*sr+cr*cy, -cp*sr)
28+
self.up = Vec3(-cr*cy*sp-sr*sy, -cr*sy*sp+sr*cy, cp*cr)
29+
30+
31+
# Sometimes things are easier, when everything is seen from your point of view.
32+
# This function lets you make any location the center of the world.
33+
# For example, set center to your car's location and ori to your car's orientation, then the target will be
34+
# relative to your car!
35+
def relative_location(center: Vec3, ori: Orientation, target: Vec3) -> Vec3:
36+
"""
37+
Returns target as a relative location from center's point of view, using the given orientation. The components of
38+
the returned vector describes:
39+
40+
* x: how far in front
41+
* y: how far right
42+
* z: how far above
43+
"""
44+
x = (target - center).dot(ori.forward)
45+
y = (target - center).dot(ori.right)
46+
z = (target - center).dot(ori.up)
47+
return Vec3(x, y, z)

0 commit comments

Comments
 (0)