Pygame object has no attribute 'rect' (pygame) - python

I'm currently making Memory, a game for school which involves matching 8 pairs of images that are hidden underneath covers. I was successful in setting up the 4x4 grid, with a timer for score and randomizing the location of the images, but removing the cover on the tiles is giving me some issues. I end up getting the error: builtins.AttributeError: type object 'Tile' has no attribute 'rect'
The traceback is:
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'
My Tile class is:
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
and I am not too sure why it is saying it has no attribute 'rect'.
Here is my full code
# 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()

The problem is this:
Tile.handle_click( Tile, event )
The code is confusing the class definition of the Tile object, with an instantiated object - like a "live copy" of it ~ a_tile. So when it calls Tile.something(), the __init__() has never been called, so .rect does not exist. Of course a_tile has a .rect, because it has been instantiated.
It should probably be something like:
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
Except for #classmethod functions (i.e.: what every other language calls static member functions), member functions are almost never called on the class definition. So if you find yourself writing Tile.something to call a function, you should be questioning yourself.
Unless you have an object with no internal state, it's normal to have none-to-few #classmethod functions. Sometimes you might do a class, say a unit-converter, which is in an object simply to collect a whole bunch of small functions together. These would all be called on the definition, e.g.: Units.furlongsToMetres( fur ). For your Tile, this is not the case.

Related

AttributeError: 'pygame.mask.Mask' object has no attribute 'rect'

I am trying to get pixel perfect collision but I keep running into this error:
Traceback (most recent call last):
File "D:\Projects\games\venv\lib\site-packages\pygame\sprite.py", line 1528, in collide_circle
xdistance = left.rect.centerx - right.rect.centerx
AttributeError: 'pygame.mask.Mask' object has no attribute 'rect'
Process finished with exit code 1
I am not sure of what's going wrong. Is it my implementation or logic or maybe both?
My code:
class AlienShooting(pygame.sprite.Sprite):
def __init__(self, w=640, h=640):
# init display
# init game state
self.spaceship_main = pygame.image.load('spacecraft_1.png').convert_alpha()
self.alien_spacecraft1 = pygame.image.load('spacecraft_alien.png').convert_alpha()
self.alien_spacecraft_rec1 = self.alien_spacecraft1.get_rect()
self.mask1 = pygame.mask.from_surface(self.alien_spacecraft1)
self.main_spaceship_mask = pygame.mask.from_surface(self.spaceship_main)
def play_step(self):
# user input
# Move the spaceship
# check if game over
game_over = False
if self._is_collision():
game_over = True
# Add new alien spaceships
# Randomly move alien spaceships
# update ui and clock
# return game over and score
return False
def _is_collision(self):
if pygame.sprite.collide_circle(self.mask1, self.main_spaceship_mask):
return True
return False
It might be because both my main space ship and my alien spaceship are in the same class, but I'm not sure.
See How do I detect collision in pygame? and Pygame mask collision. If you want to use pygame.sprite.collide_circle() or pygame.sprite.collide_mask you have to create pygame.sprite.Sprite objects.
spaceship_main and alien_spacecraft1 have to be Sprite objects. Sprite objects must have a rect and image attribute and can optionally have a mask attribute.
e.g.:
class AlienShooting():
def __init__(self, w=640, h=640):
self.spaceship_main = pygame.sprite.Sprite()
self.spaceship_main.image = pygame.image.load('spacecraft_1.png').convert_alpha()
self.spaceship_main.rect = self.spaceship_main.image.get_rect(center = (140, 140))
self.spaceship_main.mask = pygame.mask.from_surface(self.spaceship_main.image)
self.alien_spacecraft1 = pygame.sprite.Sprite()
self.alien_spacecraft1.image = pygame.image.load('spacecraft_alien.png').convert_alpha()
self.alien_spacecraft1.rect = self.alien_spacecraft1.image.get_rect(center = (160, 160))
self.alien_spacecraft1.mask = pygame.mask.from_surface(self.alien_spacecraft1.image)
def _is_collision(self):
if pygame.sprite.collide_mask(self.spaceship_main, self.alien_spacecraft1):
return True
return False

How can I change this surface image to the image I want in pygame?

# Memory V2
# The second version contains the complete tile grid and the black panel on the right, there is score in the black panel. All 8 pairs of two tiles are covered by question mark when the game starts . Each time the game is played, the tiles spawn in random locations in the grid. Player can click tiles to reveal images. Game ends upon clicking close screen or all 16 tiles being exposed. Game occurs on a 4x4 grid.
import pygame,random, time
# User-defined functions
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 v1')
# 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.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 = 60
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
Tile.set_surface(self.surface)
# tell grid to be size 4 meaning 4x4 or 16 squares total
grid_size = 4
self.create_grid(grid_size)
self.score=0
def draw_score(self):
# this method draws the player's score in the top-right corner of the
# game window.
# - self : the game the score is being drawn for
font_color = pygame.Color("white")
font_bg = pygame.Color("black")
font = pygame.font.SysFont("arial", 32)
text_img = font.render(str(self.score), True, font_color, font_bg)
text_pos = (460,0)
self.surface.blit(text_img, text_pos)
def create_grid(self, grid_size):
# Creates a grid of tiles that is grid_size x grid_size in size.
self.grid = [ ]
# Create list of image names to be used on the squares (we just append image(1-9) and the file type bmp
# Then we create image surfaces of each image name and add image surfaces to itself which provides us with two of each image
img_names = ['image' + str(i) + '.bmp' for i in range(1,9)]
image_surfaces = [pygame.image.load(name) for name in img_names]
image_surfaces = image_surfaces + image_surfaces
random.shuffle(image_surfaces)
# this for loop creates each row in our grid
for row_num in range(grid_size):
new_row = self.create_row(row_num, grid_size,image_surfaces)
self.grid.append(new_row)
def create_row(self, row_num, size,images):
# Create one row in a grid. Each row contains size Tiles
# required for calculating the tile's x,y coordinates on screen
# - row_num: the nth row of the grid being created
# - size : the number of tiles in the row
# returns the newly created row'
tile_height = self.surface.get_height() // size
# 3/4 to leave space for black column on side
tile_width = 3/4*self.surface.get_width() // size
new_row = [ ]
for col_num in range(size):
# number of row x tile height produces y position
# number of col x tile_width produces x position
# + 10 so it fits
pos = (row_num*tile_height+10,col_num*tile_width+10)
# assigns one of the images to each tile by pairing it with a unique coordinate
#content=pygame.image.load('image0.bmp')
#content = images[row_num*size+col_num]
one_tile = Tile(pos, tile_width, tile_height)
content=pygame.image.load('image0.bmp')
#content=images[row_num*size+col_num]
if self.handle_mouse_click==True:
content=images[row_num*size+col_num]
one_tile.set_content(content)
#one_tile = Tile(pos, tile_width, tile_height)
#one_tile.set_content(content)
new_row.append(one_tile)
return new_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.decide_continue()
self.game_Clock.tick(self.FPS) # run at most with FPS listed
def handle_events(self):
# Handle each user event by changing the game state
# - 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
if event.type == pygame.MOUSEBUTTONDOWN:
self.handle_mouse_click(event)
def handle_mouse_click(self, event):
# responds to one mouse click on screen; that means flipping the
# tile
#print("Screen was clicked at " + str(event.pos))
for row in self.grid:
for tile in row:
if tile.select(event.pos)==True:
print('hi')
#def change_content(self,content):
#return False
#return content_switch
def draw(self):
# Draw all game objects.
# - self is the Game to draw
self.surface.fill(self.bg_color) # clear the display surface
# draws the grid
for row in self.grid:
for tile in row:
tile.draw()
self.draw_score()
pygame.display.update() # updates 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
pass
def decide_continue(self):
# Check and remember if the game should continue
filled_tiles = [ ]
for row in self.grid:
for tile in row:
if tile.tile_content==True:
filled_tiles.append(tile)
if len(filled_tiles) == self.grid_size ** 2:
return False
else:
return True
class Tile:
# A tile represents one location on a grid. Tiles hold content
# (in this case, an X or an O).
# class attributes that are common to all tiles
# setting surface to none isnt exactly necessary, however we set class wide attributes here before putting it in a method
surface = None
fg_color = pygame.Color("white")
bg_color = pygame.Color("black")
# set border width for each tile in grid
border_width = 5
#classmethod
def set_surface(cls, surface):
# sets the class attribute, surface
cls.surface = surface
def __init__(self, screen_position, width, height):
# initialize one instance of our Tile class. Tiles represent
# one 'position' in our tic-tac-toe board.
# - self: the tile being initialized
# - screen_position: the [x, y] coordinates to draw the tile at
# - width: the width of the tile
# - height: the height of the tile
self.screen_position = screen_position
#self.content = ''
# create a rectangle defining our boundaries
x, y = screen_position
self.rect = pygame.Rect(x, y, width, height)
def draw_content(self):
# create an rect object of image so we can blit images to surface of grid tiles
image_rect=self.content.get_rect(center=self.rect.center)
Tile.surface.blit(self.content,image_rect)
def draw(self):
# draw the contents of a tile to its surface.
# - self: the tile being drawn
self.draw_content()
pygame.draw.rect(Tile.surface, Tile.bg_color, self.rect,
Tile.border_width)
def set_content(self, new_content):
# change our tile content.
self.content = new_content
def select(self, pos):
selected=False
if self.rect.collidepoint(pos):
if self.content==pygame.image.load('image0.bmp'):
selected=True
return selected
def __eq__(self):
if self.content==pygame.image.load('image0.bmp'):
return True
def tile_content(self):
if self.content == pygame.image.load('image0.bmp'):
return False
else:
return True
main()
So I'm trying to build another version of the game memory where upon clicking one of the tiles the question mark image 'flips' and becomes the actual image I assigned in my code and then the game ends after I flip all of the tiles. However, when I use self.content==pygame.image.load('image0.bmp') it doesn't seem to work or return true or anything even though I set it to do so. My professor said I need to overload the == operator which I think I did but for some reason it still refuses to flip upon me clicking it and I have no idea why? Can someone explain?
This is because pygame.image.load() returns a pygame.Surface(). Any object (instance of a class) is never exactly the same.
So:
pygame.image.load("image.png") == pygame.image.load("image.png") will always be False.
Also, when asking a question, try to put small snippets of code instead of the whole thing.

builtins.AttributeError: 'module' object has no attribute 'one_tile'

HI I keep getting that error message from the line below
pygame.one_tile.blit(self.i_list[img_index], pos)
and this is from the function below
def create_grid(self, grid_size):
self.grid = [ ]
tile_width = self.surface.get_width() / grid_size
tile_height = self.surface.get_height() / grid_size
# this for loop creates each row in our grid
for i in range(grid_size):
one_row = [ ]
img_index = 0
for j in range(grid_size):
y = i * tile_height
x = j * tile_width
pos = (x,y)
one_tile = Tile(pos, tile_width, tile_height, self.surface)
pygame.one_tile.blit(self.i_list[img_index], pos)
img_index += 1
one_row.append(one_tile)
self.grid.append(one_row)
I'm writing a code for the memory game version 1 (the game that has 8 pairs of images and you need to memorize which image was on which card and match a pair) and I keep get that error message but I don;t really know what I should do to solve it. Any help would be appreciated very much. Thank you!!
and my full code is
import pygame, random
# User-defined functions
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('A template for graphical games with two moving dots')
# 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.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 = 60
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
# === game specific objects
self.max_frames = 150
self.frame_counter = 0
self.i_list = []
self.images = ["image1.bmp", "image2.bmp", "image3.bmp", "image4.bmp", "image5.bmp", "image6.bmp", "image7.bmp", "image8.bmp"]
for i in self.images:
pygame.image.load(i)
self.i_list.append(i)
self.i_list.append(i)
random.shuffle(self.i_list)
self.create_grid(4)
def create_grid(self, grid_size):
self.grid = [ ]
tile_width = self.surface.get_width() / grid_size
tile_height = self.surface.get_height() / grid_size
# this for loop creates each row in our grid
for i in range(grid_size):
one_row = [ ]
img_index = 0
for j in range(grid_size):
y = i * tile_height
x = j * tile_width
pos = (x,y)
one_tile = Tile(pos, tile_width, tile_height, self.surface)
pygame.one_tile.blit(self.i_list[img_index], pos)
img_index += 1
one_row.append(one_tile)
self.grid.append(one_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.decide_continue()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames Per Second
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
def draw(self):
# Draw all game objects.
# - self is the Game to draw
self.surface.fill(self.bg_color) # clear the display surface first
for row in self.grid:
for tile in row:
tile.draw()
pygame.display.update()
def update(self):
# Update the game objects for the next frame.
# - self is the Game to update
pass
def decide_continue(self):
# Check and remember if the game should continue
# - self is the Game to check
return True
class Tile:
# A tile represents one location on a grid. Tiles hold content
# (in this case, an X or an O).
def __init__(self, screen_position, width, height, surface):
# initialize one instance of our Tile class. Tiles represent
# one 'position' in our tic-tac-toe board.
# - self: the tile being initialized
# - screen_position: the [x, y] coordinates to draw the tile at
# - surface: the surface on which to draw the tile
# - height: the height of the tile when it is drawn
# - width: the width of the tile when it is drawn
self.screen_position = screen_position
self.surface = surface
self.content = ''
self.height = height
self.width = width
def draw(self):
# draw the contents of a tile to its surface.
tile_boundary = pygame.Rect(self.screen_position[0],
self.screen_position[1],
self.width,
self.height)
pygame.draw.rect(self.surface, pygame.Color("white"), tile_boundary, 2)
main()
I recommend to add an .image attribute and .visible attribute to the class Tile. Each tile knows the associated image and has a state if the image in on the tile is visible:
class Tile:
# A tile represents one location on a grid. Tiles hold content
# (in this case, an X or an O).
def __init__(self, screen_position, width, height, surface, image):
# initialize one instance of our Tile class. Tiles represent
# one 'position' in our tic-tac-toe board.
# - self: the tile being initialized
# - screen_position: the [x, y] coordinates to draw the tile at
# - surface: the surface on which to draw the tile
# - height: the height of the tile when it is drawn
# - width: the width of the tile when it is drawn
self.screen_position = screen_position
self.surface = surface
self.content = ''
self.height = height
self.width = width
self.image = image
self.visible = False
def show(self, visible):
self.visible = visible
def draw(self):
# draw the contents of a tile to its surface.
tile_boundary = pygame.Rect(self.screen_position[0],
self.screen_position[1],
self.width,
self.height)
pygame.draw.rect(self.surface, pygame.Color("white"), tile_boundary, 2)
if self.visible:
img_rect = self.image.get_rect(center = tile_boundary.center)
self.surface.blit(self.image, img_rect.topleft)
To create an image list, you've to load the image. The return value of pygame.image.load is a pygame.Surface object which can be append to i_list:
self.i_list = []
self.images = ["image1.bmp", "image2.bmp", "image3.bmp", "image4.bmp", "image5.bmp", "image6.bmp", "image7.bmp", "image8.bmp"]
for imgname in self.images:
img = pygame.image.load(imgname)
self.i_list.append(img)
random.shuffle(self.i_list)
Pass the image to the constructor of Tile:
for i in range(grid_size):
one_row = [ ]
img_index = 0
for j in range(grid_size):
pos = (j * tile_width, i * tile_height)
one_tile = Tile(pos, tile_width, tile_height, self.surface, self.i_list[img_index])
img_index += 1
one_row.append(one_tile)
self.grid.append(one_row)
Note, for debug reasons you can all the state of all the images "visible" (self.visible = True in the constructor of Tiles).

Rendering an Isometric Grid in PyGame [duplicate]

# User-defined functions
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.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
self.surface = surface
self.bg_color = pygame.Color('black')
self.FPS = 60
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
Tile.set_surface(self.surface)
grid_size = 4
self.create_grid(grid_size)
def create_grid(self, grid_size):
# Creates a grid of tiles that is grid_size x grid_size in size.
self.grid = [ ]
# this for loop creates each row in our grid
for row_num in range(grid_size):
new_row = self.create_row(row_num, grid_size)
self.grid.append(new_row)
def create_row(self, row_num, size):
# Create one row in a grid. Each row contains size Tiles. a
#row_num is
# required for calculating the tile's x,y coordinates on screen
# - row_num: the nth row of the grid being created
# - size : the number of tiles in the row
# returns the newly created row'
image_1=pygame.image.load('image1.bmp')
image_2=pygame.image.load('image2.bmp')
image_3=pygame.image.load('image3.bmp')
image_4=pygame.image.load('image4.bmp')
image_5=pygame.image.load('image5.bmp')
image_6=pygame.image.load('image6.bmp')
image_7=pygame.image.load('image7.bmp')
image_8=pygame.image.load('image8.bmp')
pygame_image_surfaces=[]
pygame_image_surfaces.append(image_1)
pygame_image_surfaces.append(image_2)
pygame_image_surfaces.append(image_3)
pygame_image_surfaces.append(image_4)
pygame_image_surfaces.append(image_5)
pygame_image_surfaces.append(image_6)
pygame_image_surfaces.append(image_7)
pygame_image_surfaces.append(image_8)
pygame_image_surfaces=pygame_image_surfaces+pygame_image_surfaces
random.shuffle(pygame_image_surfaces)
image_surfaces=pygame_image_surfaces
tile_height = self.surface.get_height() // size
tile_width = 3/4*self.surface.get_width() // size
one_row = [ ]
for col_num in range(size):
y = row_num * tile_height
x = col_num * tile_width
pos = (x,y)
one_tile = Tile(pos, tile_width, tile_height)
i=0
content = image_surfaces[i]
i+=1
one_tile.set_content(content)
one_row.append(one_tile)
return one_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.decide_continue()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames
#Per Second
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
if event.type == pygame.MOUSEBUTTONDOWN:
self.handle_mouse_click(event)
def handle_mouse_click(self, event):
# responds to one mouse click on screen; that means changing the
# content of a tile if it is empty.
print("Screen was clicked at " + str(event.pos))
def draw(self):
# Draw all game objects.
# - self is the Game to draw
self.surface.fill(self.bg_color) # clear the display surface
#first
for row in self.grid:
for tile in row:
tile.draw()
pygame.display.update() # make the updated surface appear on the
def update(self):
# Update the game objects for the next frame.
# - self is the Game to update
pass
def decide_continue(self):
# Check and remember if the game should continue
# - self is the Game to check
return True
class Tile:
# A tile represents one location on a grid. Tiles hold content
# class attributes that are common to all tiles
surface = None
fg_color = pygame.Color("white")
bg_color = pygame.Color("black")
border_width = 3
#classmethod
def set_surface(cls, surface):
# sets the class attribute, surface
cls.surface = surface
def __init__(self, screen_position, width, height):
# initialize one instance of our Tile class. Tiles represent
# one 'position' in our board.
# - self: the tile being initialized
# - screen_position: the [x, y] coordinates to draw the tile at
# - width: the width of the tile
# - height: the height of the tile
self.screen_position = screen_position
self.content = ''
# create a rectangle defining our boundaries
x, y = screen_position
self.rect = pygame.Rect(x, y, width, height)
def draw_content(self):
image_1=pygame.image.load('image1.bmp')
image_2=pygame.image.load('image2.bmp')
image_3=pygame.image.load('image3.bmp')
image_4=pygame.image.load('image4.bmp')
image_5=pygame.image.load('image5.bmp')
image_6=pygame.image.load('image6.bmp')
image_7=pygame.image.load('image7.bmp')
image_8=pygame.image.load('image8.bmp')
pygame_image_surfaces=[]
pygame_image_surfaces.append(image_1)
pygame_image_surfaces.append(image_2)
pygame_image_surfaces.append(image_3)
pygame_image_surfaces.append(image_4)
pygame_image_surfaces.append(image_5)
pygame_image_surfaces.append(image_6)
pygame_image_surfaces.append(image_7)
pygame_image_surfaces.append(image_8)
pygame_image_surfaces=pygame_image_surfaces+pygame_image_surfaces
random.shuffle(pygame_image_surfaces)
image_surfaces=pygame_image_surfaces
for i in range(len(image_surfaces)):
Tile.surface.blit(i)
#Tile.surface.blit(text_img, text_pos)
def draw(self):
# draw the contents of a tile to its surface.
# - self: the tile being drawn
self.draw_content()
pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect,
Tile.border_width)
def set_content(self, new_content):
# - self: the tile whose content is being updated
self.content = new_content
main()
Trying to create a memory game in pygame but I'm having problems trying to blit the images onto each individual tile and would like some help troubleshooting. What I'm trying to do is from the list of image files that are now surface objects, I would like to blit one onto each tile. For some reason though my logic is wrong. I'm not sure if this stuff should go in my game class or my tile class since its describing the tile rather than the game.
Tldr: don't know how to blit the images onto each tile from a list
First of all, t he code which defines and loads the images, can be simplified a lot:
il = ['image' + str(i) + '.bmp' for i in range(1,9)]
pygame_image_surfaces = [pygame.image.load(os.path.join(path, name)) for name in imagenames]
The image which is associated to a Tile is stored in the instance attribute self.content of the Tile object. Use this attribute to draw the tile:
class Tile:
# [...]
def draw_content(self):
image_rect = self.content.get_rect(center = self.rect.center)
Tile.surface.blit(self.content, image_rect)
def draw(self):
# draw the contents of a tile to its surface.
# - self: the tile being drawn
self.draw_content()
pygame.draw.rect(Tile.surface, Tile.fg_color, self.rect, Tile.border_width)
def set_content(self, new_content):
# - self: the tile whose content is being updated
self.content = new_content
Create 1 random list of images. And use this list to set the images for the entire grid of tiles:
class Game:
# [...]
def create_grid(self, grid_size):
# Creates a grid of tiles that is grid_size x grid_size in size.
imgnames = ['image' + str(i) + '.bmp' for i in range(1,9)]
image_surfaces = [pygame.image.load(os.path.join(path, name)) for name in imgnames]
image_surfaces = image_surfaces + image_surfaces
random.shuffle(image_surfaces)
self.grid = []
# this for loop creates each row in our grid
for row_num in range(grid_size):
new_row = self.create_row(row_num, grid_size, image_surfaces)
self.grid.append(new_row)
def create_row(self, row_num, size, images):
# Create one row in a grid. Each row contains size Tiles.
# required for calculating the tile's x,y coordinates on screen
# - row_num: the nth row of the grid being created
# - size : the number of tiles in the row
# returns the newly created row'
tile_height = self.surface.get_height() // size
tile_width = 3/4*self.surface.get_width() // size
new_row = []
for col_num in range(size):
pos = (row_num * tile_height + 10, col_num * tile_width + 10)
content = images[row_num*size + col_num]
one_tile = Tile(pos, tile_width, tile_height)
one_tile.set_content(content)
new_row.append(one_tile)
return new_row

Controlling pygame animation through text input

I need to create a fighting game that gives prompts and accepts input through text, such as a raw input and then performs the animation, while still have the characters animated, e.g. moving back and forth in a ready to fight stance. How would I go about this?
Please note that this is not going to be your typical answer. StackOverflow is to help after all that you can do on your part when you are stuck, it's not meant as a place to come for code, but since I'm assuming other people new to programming will also be confused on things such as these. So I'm going to write some code, and some psuedo code, just so that you get the just of what you would do in such a scenario.
# TODO put your imports up here
pygame.init()
clock = pygame.time.Clock()
gameSurface = pygame.display.set_mode((600, 400)) # 2/3 aspect ratio
FPS = 40 # Set to your own Frames per second
class Animator:
def __init__(self, surface, rows, cols, time_between_frames, on_finish):
self.images = []
self.current_image = 0
self.time_between_frames = time_between_frames # time animator waits before changing surface
self.current_time # tracks time for frames to change
self.on_finish = on_finish # function to call when animation finishes
surf_width = (surface.get_width() / cols) # calculate width
surf_height = (surface.get_height() / rows) # calculate height
for x in range(cols):
for y in range(rows):
surf = pygame.Surface(surface.get_size()) # temp surface
from_rect = pygame.Rect(x * surf_width, y * surf_height, surf_width, surf_height) # rect to blit from
surf.blit(surface, (0,0), from_rect) # draw to temp surface
self.images.append(surf) # add temp surface to the images list
def update(delta):
self.current_time += delta # update current time
if (self.current_time >= self.time_between_frames): # if time to switch surfaces
self.current_time -= self.time_between_frames # take away time from current time
self.current_image += 1 # change image
if self.current_image >= len(self.images): # if current image would throw an out of bounds exception
self.current_image = 0 # reset the current image to the first
def get_frame(self):
return self.images[self.current_image]
class Player:
resting = 0
abdomenKick = 1
def __init__(self, x, y):
self.x = x
self.y = y
self.action = Player.resting
self.restingAnimation = Animation(pygame.image.load("resting.png"), 2, 3, 500)
self.abdomenKickAnimation = Animation(pygame.image.load("abdomenKick.png"), 4, 6, 50)
self.currentAnimation = self.restingAnimation
def update(self, delta):
self.currentAnimation.update(delta)
def draw(self, surface):
surface.blit(self.currentAnimation.get_frame(), (self.x, self.y))
def abdomenKick(self):
self.currentAnimation = self.restingAnimation
class Game:
def __init__(self):
self.player = Player()
def update(self, delta):
self.player.update(delta)
def draw_screen(self, surface):
self.player.draw(surface)
def gameLoop():
game = Game()
while True:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == A:
game.player.abdomenKick() #Or whatever move you have
game.update(clock.get_rawtime())
game.draw_screen()
clock.tick(FPS)
So here is just a brief showcase you can call it of what this might look like.

Categories