我正在制作经典的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
的东西,如果这两个定义更清晰,可能会使其他人更容易理解。如果您正在寻找由
list
的Rect
组成的更复杂的蠕虫,那也是可行的。只需将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_x
和self.dir_y
,使其分别等于+/- segment_width
和segment_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/