首页 > 解决方案 > pygame.Surface和鼠标之间的碰撞检测不起作用

问题描述

我正在尝试为像素艺术制作画布。

class Canvas:
    def __init__(self):
        self.__blocks = []
        self.__positions = []
        for i in range(1830):
            self.__blocks.append(pygame.Surface((20, 20)).convert())
        for y in range(30):
            y *= 20
            for x in range(61):
                x = x* 20
                self.__positions.append([x, y])
        self.__color = False

    def draw(self, window):
        for i in range(1830):
            self.__color = not self.__color
            if self.__color:
                self.__blocks[i].fill((200, 200, 200))
            else:
                self.__blocks[i].fill((50, 50, 50))
            window.blit(self.__blocks[i], (self.__positions[i][0]
                                , self.__positions[i][1]))

在这里,我正在尝试生成和绘制 1830 个独特的表面,这很有效。然后我尝试在每个块和鼠标之间实现碰撞检测,但失败了。

def collided(self, pos):
      for i in range(1380):
          block = self.__blocks[i].get_rect()
          if block.collidepoint(pos[0], pos[1]):
              print(block.x, block.y)

然后我对为什么它可能会失败进行了不同的测试。这是其中之一。我将更改单个块的颜色,在我们的例子中将第 10 个块self.__blocks[10].fill((255, 0, 0))更改为红色,以便我们知道要单击哪个框。然后我们将尝试检查该特定块的碰撞。

def testBlock(self, pos):
    block = self.__blocks[10].get_rect()
    if block.collidepoint(pos[0], pos[1]):
        print(block.x)

它不起作用,但奇怪的是它适用于第一个块(在第 0 个索引中),并且无论我测试哪个表面,它都只适用于第一个块。任何有关如何解决此问题的想法将不胜感激。下面是复制粘贴代码。

import pygame
pygame.init()

win = pygame.display
D = win.set_mode((1220, 600))

class Canvas:
    def __init__(self):
        self.__blocks = []
        self.__positions = []
        for i in range(1830):
            self.__blocks.append(pygame.Surface((20, 20)).convert())
        for y in range(30):
            y *= 20
            for x in range(61):
                x = x* 20
                self.__positions.append([x, y])
        self.__color = False
        self.testBlock = 10

    def draw(self, window):
        for i in range(1830):
            self.__color = not self.__color
            if self.__color:
                self.__blocks[i].fill((200, 200, 200))
            else:
                self.__blocks[i].fill((50, 50, 50))
            self.__blocks[self.testBlock].fill((255, 0, 0)) # Changing the color for testing 
                                                
            window.blit(self.__blocks[i], (self.__positions[i][0]
                                , self.__positions[i][1]))


    def test(self, pos):
        block = self.__blocks[self.testBlock].get_rect()
        if block.collidepoint(pos[0], pos[1]):
            print(block.x, block.y)


canvas = Canvas()
while True:
    D.fill((0, 0, 0))
    pygame.event.get()
    mousepos = pygame.mouse.get_pos()
    canvas.draw(D)
    canvas.test(mousepos)
    win.flip()

标签: pythonpygamepygame-surface

解决方案


当你调用.get_rect()一个 Surface 时,它​​不知道它的当前位置,因为那不是 Surface 信息。因此,您需要在碰撞检测之前将位置分配给 Rect。

使用您当前的代码布局,您可以在构建期间执行此操作。随着 Canvass 块位置现在保留在__rects列表中,__positions列表变得多余。

class Canvass:
    
    def __init__(self):
        self.__blocks    = []
        self.__rects     = []

        for y in range( 30 ):
            for x in range( 61 ):
                self.__blocks.append(pygame.Surface((20, 20)).convert())
                self.__rects.append( self.__blocks[-1].get_rect() )
                self.__rects[-1].topleft = ( x, y )

        self.__color = False
        self.testBlock = 10

这给了你一个简单的测试:

def collided(self, pos):
    hit = False
    for i in range( len( self.__rects ) ):
        if ( self.__rects[i].collidepoint( pos[0], pos[1] ) ):
            print( "Click on block %d" % ( i ) )
            hit = True
            break
    return hit, i
    

推荐阅读