无法检测 Pygame 中的多个矩形碰撞

发布于 2025-01-20 16:09:33 字数 6217 浏览 0 评论 0原文

我一直在开发一个简单的 Pygame 项目,该项目涉及模拟开放区域中的运动传感器灯,并创建了多个送货骑手、吸烟者和平民的实例。当用户处于一定距离内时,地面上的灯就会亮起。我面临的问题是,当物体与驱动程序发生碰撞时, CollideRect 根本不会触发(使用 print 语句进行测试)。理想情况下,除了司机和吸烟者之外,所有平民都应该相互碰撞和反射。

这是我的虚拟原型的记录: LUmen 模拟器

显示设置和距离函数

screen = width,height = 800,600
fps = 60 
cellsize = 50 
padding = 40 # create identations from the window 
rows = cols = (width - 50) // cellsize 
print(rows, cols) 

def euclid_dist(mX, mY, x, y): # distance to grid 
        dist = math.sqrt((mX - x)**2 + (mY - y)**2)

        if dist <= 80: 
            return True
        else: 
            return False 

对象实例化

class Cell_1: # sample of user object 
    def __init__(self):
        self.x = random.randrange(20, width-20) #x position
        self.y = random.randrange(20, height-20) #y position
        self.x_speed = 2
        self.y_speed = 2 

        self.image = char # pre-loaded img 
        self.image = pygame.transform.scale(self.image, (cellsize, cellsize+20))
        self.rect = pygame.Surface.get_rect(self.image, center= (self.x, self.y))

    def wander(self):
        self.x += self.x_speed 
        self.y += self.y_speed

        if self.x <= 30 or self.x >= width - 30:
            self.x_speed *= -1 

        elif self.y <= 30 or self.y >= height - 30:
            self.y_speed *= -1

    def draw(self): 
        surface.blit(self.image, (self.x, self.y))

class Cell_2: 
    def __init__(self):
        self.x = random.randrange(20, width-20) #x position
        self.y = random.randrange(20, height-20) #y position
        self.x_speed = 2
        self.y_speed = 2 

        self.image = char # pre-loaded img 
        self.image = pygame.transform.scale(self.image, (cellsize, cellsize+20))
        self.rect = pygame.Surface.get_rect(self.image, center= (self.x, self.y))

    def wander(self):
        self.x += self.x_speed 
        self.y += self.y_speed

        if self.x <= 30 or self.x >= width - 30:
            self.x_speed *= -1 

        elif self.y <= 30 or self.y >= height - 30:
            self.y_speed *= -1

    def draw(self): 
        surface.blit(self.image, (self.x, self.y))


class Driver: 
    # make driving linear 
    def __init__(self):
        self.x = random.randrange(20, width-20) #x position
        self.y = height - 20 #bottom of screen 
        self.y_speed = 12
        self.x_speed = 12

        self.image = char3
        self.image = pygame.transform.scale(self.image, (cellsize+20, cellsize+20))
        self.rect = pygame.Surface.get_rect(self.image, center = (self.x, self.y))

    def wander(self):
        if self.y <= 20: # height 
            self.y = height 
            self.x = random.randrange(20, width-20)

        else: 
            self.y -= self.y_speed

    def draw(self): 
        surface.blit(self.image, (self.x, self.y))

rects = [] 
cells_1 = []
for i in range(2): 
    cell = Cell_1()
    cells_1.append(cell)
    rects.append(cell) # for collision detection 

cells_2 = []
for i in range(2): 
    cell = Cell_2()
    cells_2.append(cell)
    rects.append(cell)

driver = Driver()

运行游戏

while running:
    warm_col = (255, random.randint(0, 255), 0)
    surface.fill(black)

    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            # upon closing the window with mouse 
            running = False 

    driver.wander()
    driver.draw() 
        
    for npc in cells_1: 
        npc.wander()
        npc.draw()

    for npc in cells_2: 
        npc.wander()
        npc.draw()

    for rectangle in rects:
        if (rectangle.rect.colliderect(driver.rect)): 
            rectangle.x_speed *= -1 
            rectangle.y_speed *= -1 
        
    (mX, mY) = pygame.mouse.get_pos()
    char1 = pygame.transform.scale(char1, (cellsize-10, cellsize+20)) 
    surface.blit(char1, (mX, mY))

    for row in range(rows): 
        for col in range(cols): 
            for i in rects: 
                    x = col * cellsize + padding
                    y = row * cellsize + padding 
                    within_dist = euclid_dist(mX, mY, x, y)
                    npc_within = euclid_dist(i.x, i.y, x, y) 

                    if within_dist == True or npc_within == True:
                        pygame.draw.circle(surface, warm_col, (x,y), 3) 


for row in range(rows): 
        for col in range(cols): 
            for i in cells_1: 
                    x = col * cellsize + padding
                    y = row * cellsize + padding 
                    within_dist = euclid_dist(mX, mY, x, y)
                    npc_within = euclid_dist(i.x, i.y, x, y) 

                    if within_dist == True or npc_within == True:
                        pygame.draw.circle(surface, warm_col, (x,y), 3) 

    for row in range(rows): 
        for col in range(cols): 
            for i in cells_2: 
                    x = col * cellsize + padding
                    y = row * cellsize + padding 
                    within_dist = euclid_dist(mX, mY, x, y)
                    npc_within = euclid_dist(i.x, i.y, x, y) 

                    if within_dist == True or npc_within == True:
                        pygame.draw.circle(surface, warm_col, (x,y), 3) 

    for row in range(rows): 
        for col in range(cols):  
                    x = col * cellsize + padding
                    y = row * cellsize + padding 
                    within_dist = euclid_dist(mX, mY, x, y)
                    npc_within = euclid_dist(driver.x, driver.y, x, y) 

                    if within_dist == True or npc_within == True:
                        pygame.draw.circle(surface, warm_col, (x,y), 3)   

              

    pygame.display.update() 
    pygame.time.Clock().tick(fps) 
    pygame.mouse.set_visible(False) 

pygame.quit()

我尝试过欧氏距离,但它只适用于显示器的边缘(gif) 我还尝试在这里实现碰撞逻辑https://youtu.be/1_H7InPMjaY,但无济于事

我可以知道吗是否有更有效的方法来解决这个问题?我正在考虑使用精灵而不是位块传送,但不确定它是否会有什么不同。另外,我是 Pygame 的新手,所以任何帮助或建议将不胜感激!

I'm been working on a simple Pygame project that involves simulating motion sensor lights in open areas, and have created multiple instances of delivery riders, smokers and civilians. When users are within a certain distance, the lights on the ground would light up. The problem I faced was, when objects came into collision with the drivers, colliderect did not trigger at all (tested with print statements). Ideally all the civilians should collide and reflect off one another except the driver and smokers.

Here is a recording of my virtual prototype:
LUmen Simulator

Display setup and distance function

screen = width,height = 800,600
fps = 60 
cellsize = 50 
padding = 40 # create identations from the window 
rows = cols = (width - 50) // cellsize 
print(rows, cols) 

def euclid_dist(mX, mY, x, y): # distance to grid 
        dist = math.sqrt((mX - x)**2 + (mY - y)**2)

        if dist <= 80: 
            return True
        else: 
            return False 

Instantiation of objects

class Cell_1: # sample of user object 
    def __init__(self):
        self.x = random.randrange(20, width-20) #x position
        self.y = random.randrange(20, height-20) #y position
        self.x_speed = 2
        self.y_speed = 2 

        self.image = char # pre-loaded img 
        self.image = pygame.transform.scale(self.image, (cellsize, cellsize+20))
        self.rect = pygame.Surface.get_rect(self.image, center= (self.x, self.y))

    def wander(self):
        self.x += self.x_speed 
        self.y += self.y_speed

        if self.x <= 30 or self.x >= width - 30:
            self.x_speed *= -1 

        elif self.y <= 30 or self.y >= height - 30:
            self.y_speed *= -1

    def draw(self): 
        surface.blit(self.image, (self.x, self.y))

class Cell_2: 
    def __init__(self):
        self.x = random.randrange(20, width-20) #x position
        self.y = random.randrange(20, height-20) #y position
        self.x_speed = 2
        self.y_speed = 2 

        self.image = char # pre-loaded img 
        self.image = pygame.transform.scale(self.image, (cellsize, cellsize+20))
        self.rect = pygame.Surface.get_rect(self.image, center= (self.x, self.y))

    def wander(self):
        self.x += self.x_speed 
        self.y += self.y_speed

        if self.x <= 30 or self.x >= width - 30:
            self.x_speed *= -1 

        elif self.y <= 30 or self.y >= height - 30:
            self.y_speed *= -1

    def draw(self): 
        surface.blit(self.image, (self.x, self.y))


class Driver: 
    # make driving linear 
    def __init__(self):
        self.x = random.randrange(20, width-20) #x position
        self.y = height - 20 #bottom of screen 
        self.y_speed = 12
        self.x_speed = 12

        self.image = char3
        self.image = pygame.transform.scale(self.image, (cellsize+20, cellsize+20))
        self.rect = pygame.Surface.get_rect(self.image, center = (self.x, self.y))

    def wander(self):
        if self.y <= 20: # height 
            self.y = height 
            self.x = random.randrange(20, width-20)

        else: 
            self.y -= self.y_speed

    def draw(self): 
        surface.blit(self.image, (self.x, self.y))

rects = [] 
cells_1 = []
for i in range(2): 
    cell = Cell_1()
    cells_1.append(cell)
    rects.append(cell) # for collision detection 

cells_2 = []
for i in range(2): 
    cell = Cell_2()
    cells_2.append(cell)
    rects.append(cell)

driver = Driver()

Running the game

while running:
    warm_col = (255, random.randint(0, 255), 0)
    surface.fill(black)

    for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
            # upon closing the window with mouse 
            running = False 

    driver.wander()
    driver.draw() 
        
    for npc in cells_1: 
        npc.wander()
        npc.draw()

    for npc in cells_2: 
        npc.wander()
        npc.draw()

    for rectangle in rects:
        if (rectangle.rect.colliderect(driver.rect)): 
            rectangle.x_speed *= -1 
            rectangle.y_speed *= -1 
        
    (mX, mY) = pygame.mouse.get_pos()
    char1 = pygame.transform.scale(char1, (cellsize-10, cellsize+20)) 
    surface.blit(char1, (mX, mY))

    for row in range(rows): 
        for col in range(cols): 
            for i in rects: 
                    x = col * cellsize + padding
                    y = row * cellsize + padding 
                    within_dist = euclid_dist(mX, mY, x, y)
                    npc_within = euclid_dist(i.x, i.y, x, y) 

                    if within_dist == True or npc_within == True:
                        pygame.draw.circle(surface, warm_col, (x,y), 3) 


for row in range(rows): 
        for col in range(cols): 
            for i in cells_1: 
                    x = col * cellsize + padding
                    y = row * cellsize + padding 
                    within_dist = euclid_dist(mX, mY, x, y)
                    npc_within = euclid_dist(i.x, i.y, x, y) 

                    if within_dist == True or npc_within == True:
                        pygame.draw.circle(surface, warm_col, (x,y), 3) 

    for row in range(rows): 
        for col in range(cols): 
            for i in cells_2: 
                    x = col * cellsize + padding
                    y = row * cellsize + padding 
                    within_dist = euclid_dist(mX, mY, x, y)
                    npc_within = euclid_dist(i.x, i.y, x, y) 

                    if within_dist == True or npc_within == True:
                        pygame.draw.circle(surface, warm_col, (x,y), 3) 

    for row in range(rows): 
        for col in range(cols):  
                    x = col * cellsize + padding
                    y = row * cellsize + padding 
                    within_dist = euclid_dist(mX, mY, x, y)
                    npc_within = euclid_dist(driver.x, driver.y, x, y) 

                    if within_dist == True or npc_within == True:
                        pygame.draw.circle(surface, warm_col, (x,y), 3)   

              

    pygame.display.update() 
    pygame.time.Clock().tick(fps) 
    pygame.mouse.set_visible(False) 

pygame.quit()

I have tried euclidean distance but it only worked for the edges of the display (gif)
I also tried implementing colliderect logic here https://youtu.be/1_H7InPMjaY, but to no avail

May I know if there is a more efficient way to go about this? I was thinking of using sprites instead of blit, but not sure if it would be any different. Also, I'm new to Pygame, so any help or suggestions would be appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

拥有 2025-01-27 16:09:33

您必须在碰撞测试之前更新矩形的位置:

driver.rect.x = round(self.y)
driver.rect.y = round(self.y)
for rectangle in rects:
    rectangle.rect.x = round(rectangle.x)
    rectangle.rect.y = round(rectangle.y)
    if rectangle.rect.colliderect(driver.rect): 
        rectangle.x_speed *= -1 
        rectangle.y_speed *= -1 

You have to update the position of the rectangle before the collision test:

driver.rect.x = round(self.y)
driver.rect.y = round(self.y)
for rectangle in rects:
    rectangle.rect.x = round(rectangle.x)
    rectangle.rect.y = round(rectangle.y)
    if rectangle.rect.colliderect(driver.rect): 
        rectangle.x_speed *= -1 
        rectangle.y_speed *= -1 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文