Reputation: 53
I am making a memory game and I can't get the program to check if the tiles match and if they do match get the tiles to stay exposed, and keep the tiles exposed for one second if the tiles don't match. lines 116-122 I think that part of the program is supposed to check but it never returns true for is_matching(). I feel like I am supposed to check if the actual tiles themselves are equal to each other but to me, that seems counterproductive because the tile is just a location on the grid and the image is what's drawn on the tile?? thanks in advance
# Code Example 2
#
import pygame
import random
import 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('Tic Tac Toe')
# 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.board = []
self.score = [0]
self.board_size = 4
self.create_board()
self.click = 0
self.exposed = 0
self.first_image= None
self.second_image= None
self.tile1 = None
self.tile2 = None
self.match = None
def create_board(self):
Tile.set_surface(self.surface)
# width = self.surface.get_width()//self.board_size
# height = self.surface.get_height() // self.board_size
# image is of type surface
self.images = []
new_image =['image1.bmp','image2.bmp','image3.bmp','image4.bmp', 'image5.bmp','image6.bmp','image7.bmp',
'image8.bmp','image1.bmp','image2.bmp','image3.bmp','image4.bmp', 'image5.bmp','image6.bmp',
'image7.bmp','image8.bmp']
for file_name in new_image:
image = pygame.image.load(file_name)
self.images.append(image)
# random.shuffle(self.images)
cover = pygame.image.load('image0.bmp')
#image1 = pygame.image.load(images_list)
width = image.get_width()
height = image.get_height()
for row_index in range(0, self.board_size):
row = []
for col_index in range(0, self.board_size):
x = width * col_index
y = height * row_index
imageindex = row_index * self.board_size + col_index
image = self.images[imageindex]
tile = Tile(x,y,image,cover)
row.append(tile)
self.board.append(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.MOUSEBUTTONUP and self.continue_game == True:
self.handle_mouse_up(event)
def update(self):
# Update the game objects for the next frame.
# - self is the Game to update
self.score[0] = pygame.time.get_ticks() // 1000
if self.first_image != None and self.match:
print(self.check_matching())
self.first_image = None
self.tile1 = None
self.second_image = None
self.tile2 = None
self.exposed += 1
print(self.exposed)
if self.first_image != None:
if self.second_image != None and not self.match:
# time.sleep(1)
print(self.check_matching())
self.tile1.hide_tile()
self.tile2.hide_tile()
self.second_image = None
self.tile2 = None
self.first_image = None
self.tile1 = None
def handle_mouse_up(self,event):
for row in self.board:
for tile in row:
valid_click = tile.select(event.pos)
if valid_click == True:
# self.number_exposed += 1
# time.sleep(1)
tile.expose_tile()
print(self.click)
if self.click == 0:
self.first_image = tile.image
self.tile1 = tile
elif self.click == 1:
self.second_image = tile.image
self.tile2 = tile
self.click += 1
print(self.first_image)
print(self.second_image)
if self.click > 1:
self.click = 0
def draw(self):
# Draw all game objects.
# - self is thae Game to draw
# draw tiles
self.surface.fill(self.bg_color) # clear the display surface first
for each_row in self.board:
for each_tile in each_row:
each_tile.draw()
self.draw_score()
pygame.display.update() # make the updated surface appear on the display
def draw_score(self):
# 1. Set the color
size = self.surface.get_width()
fg_color = pygame.Color('white')
# 2.create the font object
font = pygame.font.SysFont('', 70)
# 3 Create a text box by rendering the font
text_string = '' + str(self.score[0])
text_box = font.render(text_string, True, fg_color, self.bg_color)
surface_height = self.surface.get_width()
text_box_height = text_box.get_width()
location = (surface_height - text_box_height, 0)
# 4 Compute the location of the text box
#location = (430, 0)
# 5 Blit or pin the text box on the surface
self.surface.blit(text_box, location)
def decide_continue(self):
if self.exposed >= 1:
self.continue_game = False
def check_matching(self):
self.match = self.first_image == self.second_image
return self.match
# Check and remember if the game should continue
# - self is the Game to check
class Tile:
surface = None
border_size = 3
border_color = pygame.Color('black')
# An object in this class represents a Dot that moves
@classmethod
def set_surface(cls,game_surface):
cls.surface = game_surface
# instance method
def __init__(self,x , y, image, cover):
self.image = image
self.cover = cover
self.covered = True
width = self.image.get_width()
height = self.image.get_height()
self.rect = pygame.Rect(x, y, width, height)
def draw(self):
pygame.draw.rect(Tile.surface,Tile.border_color,self.rect,Tile.border_size)
Tile.surface.blit(self.image,self.rect)
if self.covered:
Tile.surface.blit(self.cover, self.rect)
else:
Tile.surface.blit(self.image, self.rect)
# Draw the dot on the surface
# - self is the Dot
def select(self, position):
valid_click = False
if self.rect.collidepoint(position):
if self.covered:
valid_click = True
self.expose_tile()
else:
valid_click = False
return valid_click
def expose_tile(self):
# if a tile is clicked this method will show the picture underneath that tile
self.covered = False
def hide_tile(self):
self.covered = True
def __eq__(self, other_tile):
if self.first_image == other_tile.image:
return True
else:
return False
main()
Upvotes: 3
Views: 1205
Reputation: 210909
The tiles do not match, because what you actually do is to compare image objects:
self.match = self.first_image == self.second_image
but each image is loaded twice. For each image are generated to different objects, so they will never match.
Load each image once and use it for 2 matching tiles:
# define unique image names
new_image =['image1.bmp','image2.bmp','image3.bmp','image4.bmp',
'image5.bmp','image6.bmp','image7.bmp','image8.bmp']
# load each unique image
for file_name in new_image:
image = pygame.image.load(file_name)
self.images.append(image)
# create a list where each loaded image object is used twice
self.images = self.images + self.images
Furthermore, since the image names just differ in the number, the definition of the name list can be simplified:
new_image = ['image' + str(i) + '.bmp' for i in range(1,9)]
Extension according to the commend
what about the time delay
Completely remove self.first_image
and self.second_image
. Adapt Tile
:
class Tile:
# [...]
def __eq__(self, other_tile):
return self.image == other_tile.image
Once tiles have been clicked then keep them stated in self.tile1
and self.tile2
. When the 1st click occurs, then hide the exposed tiles, if they do not match:
if self.click == 0:
if self.tile1 != self.tile2:
if self.tile1:
self.tile1.hide_tile()
if self.tile2:
self.tile2.hide_tile()
When the 2nd click occurs then set the time (e.g. pygame.time.get_ticks() + 2000
) when they have to be covered automatically:
elif self.click == 1:
self.tile2 = tile
self.hide_time = pygame.time.get_ticks() + 2000
Evaluate if the tiles have to be covered in update
:
ticks = pygame.time.get_ticks()
if self.tile1 and self.tile2:
if self.tile1 != self.tile2 and self.hide_time > 0 and ticks > self.hide_time:
self.tile1.hide_tile()
self.tile2.hide_tile()
Changes to your code:
class Game:
def __init__(self, surface):
# [...]
self.hide_time = 0
# [...]
def update(self):
ticks = pygame.time.get_ticks()
self.score[0] = ticks // 1000
if self.tile1 and self.tile2:
if self.tile1 != self.tile2 and self.hide_time > 0 and ticks > self.hide_time:
self.tile1.hide_tile()
self.tile2.hide_tile()
def handle_mouse_up(self,event):
self.hide_time = 0
if self.click == 0:
if self.tile1 != self.tile2:
if self.tile1:
self.tile1.hide_tile()
if self.tile2:
self.tile2.hide_tile()
tiles = [t for row in self.board for t in row if t.select(event.pos) and not t.covered]
if any(tiles):
tile = tiles[0]
if self.click == 0:
self.tile1 = tile
elif self.click == 1:
self.tile2 = tile
self.hide_time = pygame.time.get_ticks() + 2000
tile.expose_tile()
self.click += 1
if self.click > 1:
self.click = 0
# [...]
def check_matching(self):
self.match = self.tile1.image == self.tile2.image
return self.match
Upvotes: 2