我正在制作经典的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坐标在没有蛇实际接触的情况下发生变化。它只应在蛇接触绿色矩形时改变位置。
我没有显示我的所有代码,因为它的篇幅很长。如果有必要,我可以 写出类蠕虫。那么 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))
答案 0 :(得分:1)
我想我明白这里发生了什么:
您的类Worm
由一个对象组成,该对象包含一个xy元组列表,每个像素占一个像素。 '蠕虫'穿过游戏区域,在其路径中添加下一个像素到该列表,并在它达到最大长度时丢弃多余的像素位置。但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
,如果您有更新请求列表),则应设置。
就目前而言,崩溃的蠕虫代码会自动运行,但不起作用。
还有一个建议:您可能希望将Worm.surface
重命名为Worm.display_surface
,因为pygame也有一个名为Surface
的东西,它可能会让其他人更容易了解这两者是否更明确。
如果您正在寻找由list
Rect
组成的更复杂的蠕虫,那么这也是可能的。只需使用Worm.body
替换rect
列表中的xy元组,并将if (self.x, self.y) in self.body:
替换为if self.rect.collidelist(self.body) != -1:
,它应该以相同的方式工作。 (collidelist(<list of Rects>)
返回该列表中第一个碰撞rect的索引,如果没有则返回-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
代替蠕虫的身体代替xy元组。我设置它以便蠕虫在初始化期间定义每个段的大小,然后以该大小的步长向前移动(取决于行进轴)。请注意,蠕虫移动速度非常快,没有任何阻止它逃离游戏区域,并且长度为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
这就是我的所作所为。请注意,您可以指定您喜欢的任何段大小(只要每个维度都是大于零的整数),即使您喜欢使用单像素或矩形(即非方形&#39;)段