我正在尝试构建自定义 OpenAI Gym 环境。为此,我正在使用 Pygame 编写渲染函数。在我的环境中,我想想象一辆由强化学习代理通过赛道控制的汽车。我想让相机跟随汽车穿过赛道。因此,当赛道在移动时,汽车在 pygame 窗口内保持固定位置。汽车仅围绕其上轴(偏航)旋转。 汽车的位置和偏航由强化学习代理实时确定。赛道的形状是事先知道的。
我是 pygame 的超级新手。我遇到了很多问题。我无法让轨道越过汽车。汽车的旋转似乎有效,但我什至看不到轨道。
我真的迷路了,希望能得到一些指导和具体的例子来说明如何实现我想要的结果。
我尝试了很多不同的方法。这就是我现在所拥有的。我评论了代码并在评论中包含了问题。汽车的旋转现在似乎可以正常工作,但是,我看不到赛道,我也不知道为什么。我也完全不确定我的方法是否正确。
def render(self):
VIEWPORT_W = 1000
VIEWPORT_H = 800
SCALE = 30
veh_length, veh_width = self.sim_model.params.veh_length, self.sim_model.params.veh_width
if self.render_mode is None:
gym.logger.warn(
"You are calling render method without specifying any render mode. "
"You can specify the render_mode at initialization, "
f'e.g. gym("{self.spec.id}", render_mode="rgb_array")'
)
return
if self.screen is None and self.render_mode == "human":
pygame.init()
pygame.display.init()
self.screen = pygame.display.set_mode((VIEWPORT_W, VIEWPORT_H))
if self.clock is None:
self.clock = pygame.time.Clock()
self.screen.fill(0)
# ROTATING THE CAR
# define a surface (RECTANGLE), with SRCALPHA for transparency during rotation
# I use SCALE to make the car bigger, else it is super tiny
car = pygame.Surface((veh_width*SCALE, veh_length*SCALE), pygame.SRCALPHA)
# fill the rectangle / surface with green color
car.fill((0, 255, 0))
# creating a copy of orignal image for smooth rotation
car_copy = car.copy()
car_copy.set_colorkey((0, 0, 0))
# define rect for placing the rectangle at the desired position
rect_around_car = car_copy.get_rect()
rect_around_car.center = (VIEWPORT_W // 2, (2 * VIEWPORT_H) // 3)
old_car_center = rect_around_car.center
rot = self.current_sim_state[2] * 180 / np.pi # the RL agent returns a yaw in radians
rotated_car = pygame.transform.rotate(car, -rot) # pygame has opposite rotation direction... so I need a -
rotated_rect_around_car = rotated_car.get_rect()
rotated_rect_around_car.center = old_car_center
# HERE I WANT TO PLOT THE RACE TRACK ON A SURFACE AND MOVE THAT SURFACE IN OPPOSITE DIRECTION OF THE CAR
x_c = self.track["X"] # list of x coordinates of time optimal race line
x_i = self.track["X_i"] # list of x coordinates of inner boundary of the track
x_o = self.track["X_o"] # list of x coordinates of outer boundary of the track
# corresponding y coordinates
y_c = self.track["Y"]
y_i = self.track["Y_i"]
y_o = self.track["Y_o"]
# Draw all lines on the track surface. Then move the entire surface
track = pygame.Surface((VIEWPORT_W, VIEWPORT_H), pygame.SRCALPHA)
# some data processing to be able to draw lines
center_line_points = list(zip(x_c, y_c))
inner_line_points = list(zip(x_i, y_i))
outer_line_points = list(zip(x_o, y_o))
# drawing all lines on the track surface
# How can I use SCALE here, so that the track is proportional to the rectangle representing the car?
pygame.draw.aalines(track, "white", closed=False, points=center_line_points)
pygame.draw.aalines(track, "white", closed=False, points=inner_line_points)
pygame.draw.aalines(track, "white", closed=False, points=outer_line_points)
# that is the x and y position of the current x and y coordinate of the car this coordinate is calculated
# outside the render function and is set to a new value every time before I call render()
# I have no idea how to go about the coordinate systems. The calculation of the position of the car
# is completely independent of the coordinate system in pygame.
car_x = self.current_sim_state[0]
car_y = self.current_sim_state[1]
if self.render_mode == "human":
assert self.screen is not None
# here I blit the surfaces. No idea if this is how you are supposed to do it
self.screen.blit(rotated_car, rotated_rect_around_car)
self.screen.blit(track, (-car_x, -car_y))
pygame.event.pump()
self.clock.tick(self.metadata["render_fps"])
pygame.display.flip()
elif self.render_mode == "rgb_array":
# here I want to output a np.array with the rgb matrix of the current frame
# so I can render the frames to a mp4 once the simulation is over
return np.transpose(
np.array(pygame.surfarray.pixels3d(rotated_car)), axes=(1, 0, 2)
)
return