Metriche repository
- Star
- (5771 stelle)
- Metriche merge PR
- (Nessuna PR mergiata in 30 g)
Descrizione
Next Steps
- Add a small test case proving the issue in test/rect.py
- The code for Rect.clipline is in src_c/rect.c@pg_rect_clipline
Issue details
Environment:
- Operating system (e.g. Windows, Linux(Debian), Linux(Ubuntu), Mac): Ubuntu 22.04 LTS AMD64
- Python version (e.g. 3.7.9, 3.8.5) : 3.10.12
- SDL version (e.g. SDL 2.0.12): 2.28.2
- PyGame version (e.g. 2.0.0.dev10, 1.9.6): 2.5.1
Current behavior:
I have a rectangle as floor defined manually. Sometimes the rays generated in radius 180 degree don't collide with the floor. Is it caused by bug in the rect.clipline(line) method?
Expected behavior:
I need a robust and stable collision system for rays (as line) and floor (as rectangle)! The every collision between rectangle and line must be correctly evaluated.
Screenshots
https://github.com/pygame/pygame/assets/74611856/f61e7bf6-78f1-490b-b9b2-3c422a6fd443
Steps to reproduce:
- create more than or equal four rectangles
- create 180 rays in radius 180 degrees
- try to collide with lines to the rectangle
Test code
If possible add a simple test program that shows the problem described in this report.
import numpy as np
import pygame
from flappy_bird_gymnasium.envs.constants import (
BASE_HEIGHT,
BASE_WIDTH,
PIPE_HEIGHT,
PIPE_WIDTH,
PLAYER_ROT_THR,
)
class LIDAR:
def __init__(self, max_distance):
self._max_distance = max_distance
self.collisions = np.zeros((180, 2))
def scan(self, player_x, player_y, player_rot, upper_pipes, lower_pipes, ground):
result = np.empty([180])
# sort pipes from nearest to farthest
upper_pipes = sorted(upper_pipes, key=lambda pipe: pipe["x"])
lower_pipes = sorted(lower_pipes, key=lambda pipe: pipe["x"])
# get collisions with precision 1 degree
for i, angle in enumerate(range(0, 180, 1)):
# Getting player's rotation
visible_rot = PLAYER_ROT_THR
if player_rot <= PLAYER_ROT_THR:
visible_rot = player_rot
rad = np.radians(angle - 90 - visible_rot)
x = self._max_distance * np.cos(rad) + player_x
y = self._max_distance * np.sin(rad) + player_y
line = (player_x, player_y, x, y)
self.collisions[i] = (x, y)
# check ground collision
ground_rect = pygame.Rect(0, ground["y"], BASE_WIDTH, BASE_HEIGHT)
collision = ground_rect.clipline(line)
# print("gound collision: ", collision, " ", angle, "line: ", line)
if collision:
self.collisions[i] = collision[0]
print(self.collisions[i][1])
assert self.collisions[i][1] < 408, "collision with ground"
# check pipe collision
for up_pipe, low_pipe in zip(upper_pipes, lower_pipes):
# upper and lower pipe rects
up_pipe_rect = pygame.Rect(
up_pipe["x"], up_pipe["y"], PIPE_WIDTH, PIPE_HEIGHT
)
low_pipe_rect = pygame.Rect(
low_pipe["x"], low_pipe["y"], PIPE_WIDTH, PIPE_HEIGHT
)
# check collision
collision_A = up_pipe_rect.clipline(line)
collision_B = low_pipe_rect.clipline(line)
if collision_A:
self.collisions[i] = collision_A[0]
break
elif collision_B:
self.collisions[i] = collision_B[0]
break
print(self.collisions[i][1])
assert self.collisions[i][1] < 405, "collision with ground"
# calculate distance
result[i] = np.sqrt(
(player_x - self.collisions[i][0]) ** 2
+ (player_y - self.collisions[i][1]) ** 2
)
return result
Rendering of rays:
# LIDAR
for i in range(self.game.lidar.collisions.shape[0]):
pygame.draw.line(
self.surface,
"red",
(
self.game.player_x + PLAYER_WIDTH,
self.game.player_y + (PLAYER_HEIGHT / 2),
),
(
self.game.lidar.collisions[i][0],
self.game.lidar.collisions[i][1],
),
1,
)