I am working on a machine learning project that involves training a 2D car to drive around a top-down racing track. I'll be training neural networks using different algorithms and one essential form of data I need to give the model is vision input. I'm modeling the car and track in the python module Pyglet.

Looking at other similar projects it seems this would work best by casting out rays from multiple angles and calculating the distance of each ray from the nearest point. I'm also trying to optimise for performance because I need to cut down training time as much as possible.

I've already been able to convert the track png data into all kinds of forms, including a dictionary which has image pixel coordinates as keys and stores a 1 if the pixel is part of the track, and a zero if it is not. I also have made a list of all pixels which are the track.

Also, I've already run the math on which angles I need to project the lines out of, and I think I have the right math for the lines themselves. Below is code that accurately casts 8 rays, explained in the comments of the code. The issue is I don't know how to combine the data of the line co-ordinates, with the dictionaries and lists containing the data of the track.

Any help would be greatly appreciated, if I am doing some other fundamental part of this process wrong any direction would also be appreciated. I've been stuck on this for weeks. I've attached images to help visually understand where I am thus far.

# presets stores the pre-calculated angle and length of each 
# line in a tuple, totalling 8 tuples for 8 lines. Angles and 
# length are calculated to reach the 4 corners of the car, and
# the midpoints of the four lines. The lines can then be 
# lengthened by changing the leng variable. 
presets = (
   (116.56505117707799 - player_angle, 21.242645786248),
   (180 - player_angle, 9.5),
   (243.43494882292202 - player_angle, 21.242645786248),
   (270 - player_angle, 19.0),
   (296.565051177078 - player_angle, 21.242645786248),
   (0 - player_angle, 9.5),
   (63.43494882292201 - player_angle, 21.242645786248),
   (90 - player_angle, 19.0),
leng = 0
lis = []
for i in presets:
    pos = (int(math.cos(math.radians(i[0])) * (i[1] + leng) + player_rect[0]),int(math.sin(math.radians(i[0])) * (i[1] + leng) + player_rect[1]))
# creates line by converting the angle preset to radians, using the cos of that 
# value for x coordinate and the sin for the y coordinate, and mulitplies both by  
# the preset length.

    lis.append((pos[0], pos[1], player_rect[0], player_rect[1])) 

Here is the car with the lines projecting out from it

enter image description here

Here is the car with the entire track in frame aswell

enter image description here

This image shows running the program and setting leng to 10.

enter image description here

  • \$\begingroup\$ Dictionaries are not your friends here. Your queries are spatially coherent (if you query one pixel, you're likely to soon query the pixels beside it), but dictionaries randomize access patterns, thrashing your cache and making it harder for the CPU's prediction and prefetching mechanisms to stay ahead. Why not store a collection of straight line segments and circular arcs? You could build this track out of just 36 such primitives, which is far less data to query than thousands of pixels, and testing a ray against each one is just a tiny bit of math. \$\endgroup\$
    – DMGregory
    Commented Sep 18, 2023 at 11:32


You must log in to answer this question.