在Pygame中获取点击的精灵遇到问题
抱歉,如果这个问题和之前的重复了,但我在这个网站上看了很多页面,试图找到答案,却一直没有成功。
我用过的一些页面有:
可能是我对编程的理解不够,我对此表示歉意。不过,我觉得最“有帮助”的页面是第一个链接。根据Sloth的第一个回答,看起来很简单,我觉得我可以做到。但当他的办法不奏效时,我又在YouTube和其他网站上搜索,还是找不到答案。
我想做的就是在点击一个精灵时简单地打印“clicked”。这是我的代码。
import pygame
size = (700,500)
screen = pygame.display.set_mode(size)
done = False
clock = pygame.time.Clock()
itunes = pygame.image.load('itunes.png')
screen.blit(itunes,(200,200))
sprites = [itunes]
while not done:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
clicked_sprites = [s for s in sprites if s.rect.collidepoint(pos)]
for i in clicked_sprites:
print('clicked sprite')
pygame.display.flip()
clock.tick(60)
我对Python语言了解得很少,但我发现自己做同样的文本程序越来越无聊,想要继续学习。
编辑:抱歉,我应该说明我遇到的错误。我得到的错误是:AttributeError: 'pygame.Surface'对象没有'rect'属性。
编辑:在屏幕上绘制图像时遇到麻烦。
import pygame
size = (700,500)
screen = pygame.display.set_mode(size)
done = False
clock = pygame.time.Clock()
white = (0,0,0)
image = 'itunes.png'
class Thing(pygame.sprite.Sprite):
def __init__(self, image, x, y):
self.image = pygame.image.load('itunes.png')
self.x = x
self.y = y
@property
def rect(self):
return self.image.get_rect(topleft=(self.x, self.y))
itunes = Thing(image,200,200)
SpriteGroup = pygame.sprite.Group()
SpriteGroup.add(itunes)
while not done:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
clicked_sprites = [s for s in SpriteGroup if s.rect.collidepoint(pos)]
for i in clicked_sprites:
print('clicked sprite')
screen.fill((0, 0, 0))
SpriteGroup.draw(screen)
pygame.display.flip()
clock.tick(60)
2 个回答
让我们来看看你的代码在做什么。
- 你把一张新图片加载到一个叫做 itunes 的变量里。
- 你把这张图片显示在屏幕上的坐标 (200, 200) 位置。
- 你把这张图片添加到一个精灵列表中。
- 当你点击鼠标时,你会遍历这个精灵列表,检查鼠标的位置是否在列表中某个对象的范围内。
那么,我们怎么知道精灵列表中对象的位置呢?答案是我们不知道。在这个表面上并没有关于对象位置的信息。
为了解决这个问题,你可以自己创建一个精灵类,这个类会包含一个 rect
和一个表面,或者更好的是,使用 pygame.sprite.Sprite
,因为它已经包含了 rect
。
图像是 pygame.Surface
对象,它们没有 rect
这个属性。不过,你可以通过调用 SurfaceObject.get_rect()
来获取这个 Surface 对象的矩形区域。这样会创建一个 pygame.Rect
对象,它表示这个 Surface 的大小,虽然不一定表示它的位置。
根据你的对象创建新的 rect
或者根据它在窗口中的位置来修改它的频率,你可能会想要继承 pygame.sprite.Sprite
类,并使用一个属性来获取正确位置的 Rect。例如:
class Thing(pygame.sprite.Sprite):
def __init__(self, image, x, y):
super(Thing, self).__init__() #don't forget to do this!! (like I did :D, haha)
self.image = pygame.image.load(image)
self.x = x
self.y = y
@property
def rect(self):
return self.image.get_rect(topleft=(self.x, self.y))
调用 surface.get_rect()
时,可以传入一些关键字参数,这样可以在创建对象时设置它的属性。实际上,这就相当于把下面的代码简化成了一行:
new_rect = self.image.get_rect()
new_rect.x = self.x
new_rect.y = self.y
return new_rect
整个过程返回一个在窗口中正确位置的矩形,这样就可以用来检测碰撞,或者判断是否是你点击的那个对象,就像你举的例子一样。
这种方法的另一个好处是(使用属性来获取 rect
),使得对象能够很好地与 pygame.sprite.Group.draw()
方法配合使用,这个方法会通过绘制它们的 obj.image
和 obj.rect
属性来绘制该组中的所有 Sprite
对象。
所以你可以利用这一点,把 sprites
从一个 list
转换成一个 sprite.Group 对象,并对你的代码进行以下更改:
SpriteGroup = pygame.sprite.Group() #use these for working with Sprite objects
SpriteGroup.add(itunes) #add itunes to sprites Group
while not done:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
clicked_sprites = [s for s in sprites if s.rect.collidepoint(pos)]
for i in clicked_sprites:
print('clicked sprite')
screen.fill((0, 0, 0)) #wipes the screen
SpriteGroup.draw(screen) #draws every Sprite object in this Group
pygame.display.flip()
clock.tick(60)