Pygame 对象没有属性 'rect' (pygame)
Pygame object has no attribute 'rect' (pygame)
我目前正在制作 Memory,这是一款学校游戏,需要匹配隐藏在封面下的 8 对图像。我成功地设置了 4x4 网格,带有计分计时器和随机化图像位置,但是移除瓷砖上的盖子给我带来了一些问题。我最终收到错误:builtins.AttributeError: type object 'Tile' has no attribute 'rect'
回溯是:
Traceback (most recent call last):
File "/home/user/Documents/Lab 4/memory2cover.py", line 179, in <module>
main()
File "/home/user/Documents/Lab 4/memory2cover.py", line 21, in <module>
game.play()
File "/home/user/Documents/Lab 4/memory2cover.py", line 92, in <module>
self.handle_events()
File "/home/user/Documents/Lab 4/memory2cover.py", line 117, in <module>
Tile.handle_click(Tile, event)
File "/home/user/Documents/Lab 4/memory2cover.py", line 175, in <module>
if self.rect.collidepoint(pos):
builtins.AttributeError: type object 'Tile' has no attribute 'rect'
我的板块 class 是:
class Tile:
# An object in this class represents a Tile
# Shared or Class Attributes
surface = None
fg_color = pygame.Color('black')
border_width = 10
cover = pygame.image.load('image0.bmp')
@classmethod
def set_surface(cls,surface_from_Game):
cls.surface = pygame.display.get_surface()
def __init__(self, x,y,width,height, image):
# Initialize a Tile.
# - self is the Tile to initialize
# - x,y top left coordinates of the rectangle
# - - width, height are the dimensions of the rectangle
# Instance Attributes or Object Attributes
self.rect = pygame.Rect(x,y,width,height)
self.image = image
self.covered = True
def draw(self):
# Draw the dot on the surface
# - self is the Tile
# then blit the tile content onto the surface
pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect,Tile.border_width)
if self.covered:
Tile.surface.blit(Tile.cover, self.rect)
else:
Tile.surface.blit(self.image, self.rect)
def handle_click(self, event):
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
pos = pygame.mouse.get_pos()
if self.rect.collidepoint(pos):
self.covered = False
我不太确定为什么说它没有属性 'rect'。
这是我的完整代码
# Memory 1
import pygame
import random
# User-defined functions
# board[row_index][col_index]
def main():
# initialize all pygame modules (some need initialization)
pygame.init()
# create a pygame display window
pygame.display.set_mode((500, 400))
# set the title of the display window
pygame.display.set_caption('Memory')
# get the display surface
w_surface = pygame.display.get_surface()
# create a game object
game = Game(w_surface)
# start the main game loop by calling the play method on the game object
game.play()
# quit pygame and clean up the pygame window
pygame.display.quit()
pygame.quit()
# User-defined classes
class Game:
# An object in this class represents a complete game.
def __init__(self, surface):
# Initialize a Game.
# - self is the Game to initialize
# - surface is the display window surface object
# === objects that are part of every game that we will discuss
self.surface = surface
self.bg_color = pygame.Color('black')
self.FPS = 70
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
# === game specific objects
Tile.set_surface(self.surface) # this is how you call a class method
self.board_size = 4
self.board = []
self.score = 0
self.load_images()
self.create_board()
self.image_index = 0
def load_images(self):
# loads a specified amount of images into a list
# that list of images is then shuffled so an images index is randomized
self.image_list = []
for self.image_index in range(1,9):
self.image_list.append(pygame.image.load('image' + str(self.image_index) + '.bmp'))
self.full_list = self.image_list + self.image_list
random.shuffle(self.full_list)
def create_board(self):
# multiple rows and columns are appended to the board with the tiles added
# utlizes the different images for each tile
index = 0
img = self.full_list[0]
width = img.get_width()
height = img.get_height()
for row_index in range(0,self.board_size):
self.row = []
for col_index in range(0,self.board_size):
#item = (row_index,col_index)
# game = Game(), dot1 = Dot(), student = Student()
image = self.full_list[index]
x = width * col_index
y = height * row_index
a_tile = Tile(x,y,width,height, image)
self.row.append(a_tile)
index = index + 1
self.board.append(self.row)
def play(self):
# Play the game until the player presses the close box.
# - self is the Game that should be continued or not.
while not self.close_clicked: # until player clicks close box
# play frame
self.handle_events()
self.draw()
if self.continue_game:
self.update()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames Per Second
def draw_score(self):
fg = pygame.Color('white')
bg = pygame.Color('black')
font = pygame.font.SysFont('',70)
text_box = font.render(str(self.score),True,fg,bg)
#x = self.surface.get_width() - text_box.get_width()
#y = self.surface.get_height() - text_box.get_height()
location = (self.surface.get_width() -70,0)
self.surface.blit(text_box,location)
def handle_events(self):
# Handle each user event by changing the game state appropriately.
# - self is the Game whose events will be handled
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
for item in self.row:
Tile.handle_click(Tile, event)
def draw(self):
# Draw all game objects.
# - self is the Game to draw
coordinates = self.create_board()
# clear the display surface first
self.surface.fill(self.bg_color)
# drawing of the board
for row in self.board:
for tile in row:
tile.draw()
self.draw_score()
pygame.display.update() # make the updated surface appear on the display
def update(self):
# Update the game objects for the next frame.
# - self is the Game to update
self.score = pygame.time.get_ticks()//1000
class Tile:
# An object in this class represents a Tile
# Shared or Class Attributes
surface = None
fg_color = pygame.Color('black')
border_width = 10
cover = pygame.image.load('image0.bmp')
@classmethod
def set_surface(cls,surface_from_Game):
cls.surface = pygame.display.get_surface()
def __init__(self, x,y,width,height, image):
# Initialize a Tile.
# - self is the Tile to initialize
# - x,y top left coordinates of the rectangle
# - - width, height are the dimensions of the rectangle
# Instance Attributes or Object Attributes
self.rect = pygame.Rect(x,y,width,height)
self.image = image
self.covered = True
def draw(self):
# Draw the dot on the surface
# - self is the Tile
# then blit the tile content onto the surface
pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect,Tile.border_width)
if self.covered:
Tile.surface.blit(Tile.cover, self.rect)
else:
Tile.surface.blit(self.image, self.rect)
def handle_click(self, event):
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
pos = pygame.mouse.get_pos()
if self.rect.collidepoint(pos):
self.covered = False
main()
问题是这样的:
Tile.handle_click( Tile, event )
代码混淆了 Tile
对象的 class 定义和实例化对象 - 就像它的 "live copy" ~ a_tile
。所以当它调用 Tile.something()
时,__init__()
从未被调用过,所以 .rect
不存在。当然a_tile
有个.rect
,因为已经实例化了
大概应该是这样的:
def handle_events(self):
# Handle each user event by changing the game state appropriately.
# - self is the Game whose events will be handled
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
for item in self.row:
item.handle_click( event ) # <-- HERE
除了 @classmethod
函数(即:所有其他语言都称为 static
成员函数),几乎从不在 class 定义中调用成员函数。所以如果你发现自己写 Tile.something
来调用一个函数,你应该问问自己。
除非你有一个没有内部状态的对象,否则通常会有 none 到很少的 @class 方法函数。有时你可能会做一个 class,比如说一个单位转换器,它在一个对象中只是为了将一大堆小函数收集在一起。这些都将在定义中被调用,例如:Units.furlongsToMetres( fur )
。对于你的Tile
,情况并非如此。
我目前正在制作 Memory,这是一款学校游戏,需要匹配隐藏在封面下的 8 对图像。我成功地设置了 4x4 网格,带有计分计时器和随机化图像位置,但是移除瓷砖上的盖子给我带来了一些问题。我最终收到错误:builtins.AttributeError: type object 'Tile' has no attribute 'rect'
回溯是:
Traceback (most recent call last):
File "/home/user/Documents/Lab 4/memory2cover.py", line 179, in <module>
main()
File "/home/user/Documents/Lab 4/memory2cover.py", line 21, in <module>
game.play()
File "/home/user/Documents/Lab 4/memory2cover.py", line 92, in <module>
self.handle_events()
File "/home/user/Documents/Lab 4/memory2cover.py", line 117, in <module>
Tile.handle_click(Tile, event)
File "/home/user/Documents/Lab 4/memory2cover.py", line 175, in <module>
if self.rect.collidepoint(pos):
builtins.AttributeError: type object 'Tile' has no attribute 'rect'
我的板块 class 是:
class Tile:
# An object in this class represents a Tile
# Shared or Class Attributes
surface = None
fg_color = pygame.Color('black')
border_width = 10
cover = pygame.image.load('image0.bmp')
@classmethod
def set_surface(cls,surface_from_Game):
cls.surface = pygame.display.get_surface()
def __init__(self, x,y,width,height, image):
# Initialize a Tile.
# - self is the Tile to initialize
# - x,y top left coordinates of the rectangle
# - - width, height are the dimensions of the rectangle
# Instance Attributes or Object Attributes
self.rect = pygame.Rect(x,y,width,height)
self.image = image
self.covered = True
def draw(self):
# Draw the dot on the surface
# - self is the Tile
# then blit the tile content onto the surface
pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect,Tile.border_width)
if self.covered:
Tile.surface.blit(Tile.cover, self.rect)
else:
Tile.surface.blit(self.image, self.rect)
def handle_click(self, event):
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
pos = pygame.mouse.get_pos()
if self.rect.collidepoint(pos):
self.covered = False
我不太确定为什么说它没有属性 'rect'。
这是我的完整代码
# Memory 1
import pygame
import random
# User-defined functions
# board[row_index][col_index]
def main():
# initialize all pygame modules (some need initialization)
pygame.init()
# create a pygame display window
pygame.display.set_mode((500, 400))
# set the title of the display window
pygame.display.set_caption('Memory')
# get the display surface
w_surface = pygame.display.get_surface()
# create a game object
game = Game(w_surface)
# start the main game loop by calling the play method on the game object
game.play()
# quit pygame and clean up the pygame window
pygame.display.quit()
pygame.quit()
# User-defined classes
class Game:
# An object in this class represents a complete game.
def __init__(self, surface):
# Initialize a Game.
# - self is the Game to initialize
# - surface is the display window surface object
# === objects that are part of every game that we will discuss
self.surface = surface
self.bg_color = pygame.Color('black')
self.FPS = 70
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
# === game specific objects
Tile.set_surface(self.surface) # this is how you call a class method
self.board_size = 4
self.board = []
self.score = 0
self.load_images()
self.create_board()
self.image_index = 0
def load_images(self):
# loads a specified amount of images into a list
# that list of images is then shuffled so an images index is randomized
self.image_list = []
for self.image_index in range(1,9):
self.image_list.append(pygame.image.load('image' + str(self.image_index) + '.bmp'))
self.full_list = self.image_list + self.image_list
random.shuffle(self.full_list)
def create_board(self):
# multiple rows and columns are appended to the board with the tiles added
# utlizes the different images for each tile
index = 0
img = self.full_list[0]
width = img.get_width()
height = img.get_height()
for row_index in range(0,self.board_size):
self.row = []
for col_index in range(0,self.board_size):
#item = (row_index,col_index)
# game = Game(), dot1 = Dot(), student = Student()
image = self.full_list[index]
x = width * col_index
y = height * row_index
a_tile = Tile(x,y,width,height, image)
self.row.append(a_tile)
index = index + 1
self.board.append(self.row)
def play(self):
# Play the game until the player presses the close box.
# - self is the Game that should be continued or not.
while not self.close_clicked: # until player clicks close box
# play frame
self.handle_events()
self.draw()
if self.continue_game:
self.update()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames Per Second
def draw_score(self):
fg = pygame.Color('white')
bg = pygame.Color('black')
font = pygame.font.SysFont('',70)
text_box = font.render(str(self.score),True,fg,bg)
#x = self.surface.get_width() - text_box.get_width()
#y = self.surface.get_height() - text_box.get_height()
location = (self.surface.get_width() -70,0)
self.surface.blit(text_box,location)
def handle_events(self):
# Handle each user event by changing the game state appropriately.
# - self is the Game whose events will be handled
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
for item in self.row:
Tile.handle_click(Tile, event)
def draw(self):
# Draw all game objects.
# - self is the Game to draw
coordinates = self.create_board()
# clear the display surface first
self.surface.fill(self.bg_color)
# drawing of the board
for row in self.board:
for tile in row:
tile.draw()
self.draw_score()
pygame.display.update() # make the updated surface appear on the display
def update(self):
# Update the game objects for the next frame.
# - self is the Game to update
self.score = pygame.time.get_ticks()//1000
class Tile:
# An object in this class represents a Tile
# Shared or Class Attributes
surface = None
fg_color = pygame.Color('black')
border_width = 10
cover = pygame.image.load('image0.bmp')
@classmethod
def set_surface(cls,surface_from_Game):
cls.surface = pygame.display.get_surface()
def __init__(self, x,y,width,height, image):
# Initialize a Tile.
# - self is the Tile to initialize
# - x,y top left coordinates of the rectangle
# - - width, height are the dimensions of the rectangle
# Instance Attributes or Object Attributes
self.rect = pygame.Rect(x,y,width,height)
self.image = image
self.covered = True
def draw(self):
# Draw the dot on the surface
# - self is the Tile
# then blit the tile content onto the surface
pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect,Tile.border_width)
if self.covered:
Tile.surface.blit(Tile.cover, self.rect)
else:
Tile.surface.blit(self.image, self.rect)
def handle_click(self, event):
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
pos = pygame.mouse.get_pos()
if self.rect.collidepoint(pos):
self.covered = False
main()
问题是这样的:
Tile.handle_click( Tile, event )
代码混淆了 Tile
对象的 class 定义和实例化对象 - 就像它的 "live copy" ~ a_tile
。所以当它调用 Tile.something()
时,__init__()
从未被调用过,所以 .rect
不存在。当然a_tile
有个.rect
,因为已经实例化了
大概应该是这样的:
def handle_events(self):
# Handle each user event by changing the game state appropriately.
# - self is the Game whose events will be handled
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
for item in self.row:
item.handle_click( event ) # <-- HERE
除了 @classmethod
函数(即:所有其他语言都称为 static
成员函数),几乎从不在 class 定义中调用成员函数。所以如果你发现自己写 Tile.something
来调用一个函数,你应该问问自己。
除非你有一个没有内部状态的对象,否则通常会有 none 到很少的 @class 方法函数。有时你可能会做一个 class,比如说一个单位转换器,它在一个对象中只是为了将一大堆小函数收集在一起。这些都将在定义中被调用,例如:Units.furlongsToMetres( fur )
。对于你的Tile
,情况并非如此。