我正在制作经典的Snake游戏。我想绘制一个绿色矩形(green_rect),每当我的蛇碰到它时,该绿色矩形就会移动到新的随机位置。当我在蠕虫的colliderect()上运行surface时,由于某种原因,即使蠕虫没有碰到矩形,它总是返回True

到目前为止,我已经尝试过:

width  = 640
height = 400
screen = pygame.display.set_mode((width, height))
green  = pygame.Surface((10,10)) #it's the rectangle
green.fill((0,255,0))
green_rect = pygame.Rect((100,100), green.get_size())

  # Our worm.
w = Worm(screen, width/2, height/2, 100)   # I have a class called Worm, described later...

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            w.key_event(event)   # direction control method in the Worm class

    if green_rect.colliderect(w.rect):  # w.rect is coming from Worm class: self.rect=self.surface.get_rect()
        # surface variable is 100 coming from: w = Worm(screen, width/2, height/2, 100) -- it describes the worm's length in segments / pixels.
        green_rect.x, green_rect.y = (random.randrange(420),random.randrange(300))


    screen.fill((0, 0, 0))
    screen.blit(green, green_rect)

    w.move() #function for movement in Worm class
    w.draw() #function for drawing the snake in Worm class


但这是行不通的,即使我没有用蛇碰到它,绿色矩形也无法控制地移动。 colliderect一定不能工作,因为绿色矩形的x-y坐标在没有蛇实际接触的情况下发生了变化。仅当蛇碰到绿色矩形时才应更改位置。


我没有显示所有代码,因为它有点长。如果有必要我可以
还要写出Class Worm。好的rect方法不起作用
列表,所以我不知道如何解决此问题。


编辑:另外,我想知道如何调整蛇段的大小,因为我的默认大小是像素(点)。我希望它更大,因此,如果它碰到一个大矩形,即使在矩形的一个角上或沿侧面,矩形仍会移动。


编辑2:这是我的Worm类:


class Worm():
    def __init__(self, surface, x, y, length):
        self.surface = surface
        self.x = x
        self.y = y
        self.length  = length
        self.dir_x   = 0
        self.dir_y   = -1
        self.body    = []
        self.crashed = False


    def key_event(self, event):
        """ Handle key events that affect the worm. """
        if event.key == pygame.K_UP:
            self.dir_x = 0
            self.dir_y = -1
        elif event.key == pygame.K_DOWN:
            self.dir_x = 0
            self.dir_y = 1
        elif event.key == pygame.K_LEFT:
            self.dir_x = -1
            self.dir_y = 0
        elif event.key == pygame.K_RIGHT:
            self.dir_x = 1
            self.dir_y = 0


    def move(self):
        """ Move the worm. """
        self.x += self.dir_x
        self.y += self.dir_y

        if (self.x, self.y) in self.body:
            self.crashed = True

        self.body.insert(0, (self.x, self.y))

        if len(self.body) > self.length:
            self.body.pop()


    def draw(self):
        for x, y in self.body:
            self.surface.set_at((int(x),int(y)), (255, 255, 255))

最佳答案

我想我知道这里发生了什么:
您的类Worm由一个包含xy-tuple列表的对象组成,每个xy-tuple占用一个像素。 “蠕虫”在整个运动场上爬行,将路径中的下一个像素添加到该列表中,并在达到最大长度时丢弃多余的像素位置。但是Worm从未定义自己的矩形,而Worm.surface实际上是显示区域的表面。

目标green_rect一直跳来跳去的原因是w.surface是指screen,而不是蠕虫自己的像素区域。因此,怀疑的是w.surface.get_rect()返回整个显示区域的矩形。绿色矩形无处可去,不会与该矩形碰撞。

考虑到这一点,这是为您提供的解决方案:

  # in class Worm...
def __init__(self, surface, x, y, length):
    self.surface = surface
    self.x = x
    self.y = y
    self.length = length
    self.dir_x = 0
    self.dir_y = -1
    self.body = []
    self.crashed = False

    self.rect = pygame.Rect(x,y,1,1)  # the 1,1 in there is the size of each worm segment!
      # ^ Gives the 'head' of the worm a rect to collide into things with.

  #...

def move(self):
    """ Move the worm. """
    self.x += self.dir_x
    self.y += self.dir_y

    if (self.x, self.y) in self.body:
        self.crashed = True

    self.body.insert(0, (self.x, self.y))

    if len(self.body) > self.length:
        self.body.pop()

    self.rect.topleft = self.x, self.y
      # ^ Add this line to move the worm's 'head' to the newest pixel.


请记住,将代码放在代码顶部的import pygame, random, sys并在结尾处放入pygame.display.flip()(或update,如果您有更新rect的列表),则应该设置。

就目前而言,崩溃的蠕虫代码会运行,但没有效果。

还有一个建议:您可能想将Worm.surface重命名为Worm.display_surface之类的东西,因为pygame也有一个名为Surface的东西,如果这两个定义更清晰,可能会使其他人更容易理解。



如果您正在寻找由listRect组成的更复杂的蠕虫,那也是可行的。只需将Worm.body列表中的xy-tuples替换为rect,并用if (self.x, self.y) in self.body:替换if self.rect.collidelist(self.body) != -1:,它应该以相同的方式工作。 (collidelist(<list of Rects>)返回该列表中第一个冲突矩形的索引;如果不存在则返回-1。)

只要确保您还更改了self.rect中的class Worm,使其更像

`self.rect = pygame.Rect(x,y, segment_width, segment_height)`


...并调整self.dir_xself.dir_y,使其分别等于+/- segment_widthsegment_height。您还需要每个段fill或使用pygame.draw.rects代替set_at中的Worm.draw()



更新:可变大小的蠕虫段

这是一些使用Rect代替蠕虫主体的代码。我进行了设置,使蠕虫将在初始化期间定义每个段的大小,然后以该大小的步长前进(取决于行进轴)。请注意,蠕虫移动非常快,没有阻止蠕虫逃离游戏区域的功能,而且它的长度非常长,为100个单位!

无论如何,这是我的解决方案-首先是修改后的class Worm代码。我已经用注释标记了更改的行,包括原始答案中的新行。

class Worm(pygame.sprite.Sprite): # MODIFIED CONTENTS!
    def __init__(self, surface, x, y, length, (seg_width, seg_height)): # REVISED
        self.surface = surface
        self.x = x
        self.y = y
        self.length = length
        self.dir_x = 0
        self.dir_y = -seg_width # REVISED
        self.body = []
        self.crashed = False

        self.rect = pygame.Rect(x,y,seg_width,seg_height) # NEW/REVISED
        self.segment = pygame.Rect(0,0,seg_width,seg_height) # NEW


    def key_event(self, event):
        """ Handle key events that affect the worm. """
        if event.key == pygame.K_UP:
            self.dir_x = 0
            self.dir_y = -self.segment.height # REVISED
        elif event.key == pygame.K_DOWN:
            self.dir_x = 0
            self.dir_y = self.segment.height # REVISED
        elif event.key == pygame.K_LEFT:
            self.dir_x = -self.segment.width # REVISED
            self.dir_y = 0
        elif event.key == pygame.K_RIGHT:
            self.dir_x = self.segment.width # REVISED
            self.dir_y = 0


    def move(self):
        """ Move the worm. """
        self.x += self.dir_x
        self.y += self.dir_y

        self.rect.topleft = self.x, self.y # NEW/MOVED

        if self.rect.collidelist(self.body) != -1: # REVISED
            self.crashed = True
            print "CRASHED!"

        new_segment = self.segment.copy() # NEW
        self.body.insert(0, new_segment.move(self.x, self.y)) # REVISED

        if len(self.body) > self.length:
            self.body.pop()


    def draw(self): # REVISED
        for SEGMENT in self.body:   # REPLACEMENT
            self.surface.fill((255,255,255), SEGMENT) # REPLACEMENT


...也必须在分配w时修改参数,以包括所需的蠕虫段尺寸。在这种情况下,我关闭了4像素宽乘以4像素高的位置。

w = Worm(screen, width/2, height/2, 100, (4,4)) # REVISED


那就是我要做的。请注意,您可以分配任意大小的段(只要每个尺寸都是大于零的整数),即使您愿意,也可以使用单像素或矩形(即“非正方形”)段。

关于pygame - colliderect()意外触发,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27643698/

10-10 13:49