Compare commits
28 commits
Author | SHA1 | Date | |
---|---|---|---|
|
f87e6dd836 | ||
|
c8020398a9 | ||
|
3df378dd21 | ||
|
b14c6d2660 | ||
|
4ed1f12107 | ||
|
76a43c94b4 | ||
|
d3ab01ff02 | ||
|
3249c2d2e9 | ||
|
bc04eaf0c8 | ||
|
562623c713 | ||
|
7bdebab0f5 | ||
|
5b284ee2bb | ||
|
32508d1738 | ||
|
ab0589ddf2 | ||
|
01306f9ee0 | ||
|
8d147ad1df | ||
|
3b266b2169 | ||
|
0ca1eca5a3 | ||
|
0068baa68e | ||
|
4a03d31439 | ||
|
aec64b7408 | ||
|
bdcb1dbe55 | ||
|
985dc40ab1 | ||
|
8a34f10a2e | ||
|
d1c265eac9 | ||
|
f95288736c | ||
|
67e6a83952 | ||
|
de30a74c6d |
9 changed files with 167 additions and 25 deletions
24
README.md
24
README.md
|
@ -1,5 +1,23 @@
|
|||
## Memory Game
|
||||
# Memory Game
|
||||
### Benjamin Zimmerman
|
||||
|
||||
This is my final project (option 1) for ITSE-1479.
|
||||
Instead of using the provided cardback.png image, I used a photo of one of my turtles as the card back.
|
||||
---
|
||||
|
||||
Info for users:
|
||||
- This is my final project (option 1) for ITSE-1479 (Intro to Scripting Languages)
|
||||
- It is a memory game with a graphical interface.
|
||||
- You can click on a card to flip it. Match 2 cards correctly and the cards will stay flipped. Match all cards to win.
|
||||
- Scoring:
|
||||
- When you make an incorrect match, you lose 1 point.
|
||||
- When you make a correct match, you gain 5 points.
|
||||
|
||||
Technical info:
|
||||
- This program is written in Python 3, using the turtle module for graphics, and the pygame module for sound and music.
|
||||
- Instead of using the provided cardback.png image, I used a photo of one of my turtles as the card back.
|
||||
- Notable game behavior: If you make an incorrect match, the cards will flip back over after 1 second. However, if you click on a card while the incorrect match is still face up, nothing will happen.
|
||||
- Just wait until the cards flip back over.
|
||||
|
||||
Future plans:
|
||||
- Change the game behavior to a queue of cards to flip over, 1 pair at a time.
|
||||
- Expand the game to include a stopwatch.
|
||||
- Expand score to include number of correct and incorrect matches.
|
||||
|
|
58
audio.py
Normal file
58
audio.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
from pygame import mixer
|
||||
|
||||
|
||||
class Audio:
|
||||
background_music = 0
|
||||
click_sound = 0
|
||||
match_made_sound = 0
|
||||
no_match_sound = 0
|
||||
game_success_sound = 0
|
||||
|
||||
@staticmethod
|
||||
def start_audio():
|
||||
mixer.init()
|
||||
|
||||
# Background music is Fisticuffs in Frederick Street, by Christophe Saunière
|
||||
mixer.music.load('audio/background.wav')
|
||||
|
||||
# Click sound... I don't remember where I got it. Sorry for no link.
|
||||
Audio.click_sound = mixer.Sound('audio/mouse_click.wav')
|
||||
|
||||
# Match made sound
|
||||
# https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=music&utm_content=43637
|
||||
Audio.match_made_sound = mixer.Sound('audio/match_made.wav')
|
||||
|
||||
# no_match sound is from https://freesound.org/people/distillerystudio/sounds/327738/
|
||||
Audio.no_match_sound = mixer.Sound('audio/no_match.wav')
|
||||
|
||||
# game_success_sound is TMNT turtle Michaelangelo saying "Cowabunga!"
|
||||
Audio.game_success_sound = mixer.Sound('audio/game_success.wav')
|
||||
|
||||
@staticmethod
|
||||
def play_background_music():
|
||||
mixer.music.play(-1)
|
||||
mixer.music.set_volume(0.5)
|
||||
|
||||
@staticmethod
|
||||
def pause_music():
|
||||
mixer.music.pause()
|
||||
|
||||
@staticmethod
|
||||
def unpause_background_music():
|
||||
mixer.music.unpause()
|
||||
|
||||
@staticmethod
|
||||
def click():
|
||||
Audio.click_sound.play()
|
||||
|
||||
@staticmethod
|
||||
def match_made():
|
||||
Audio.match_made_sound.play()
|
||||
|
||||
@staticmethod
|
||||
def no_match():
|
||||
Audio.no_match_sound.play()
|
||||
|
||||
@staticmethod
|
||||
def game_success():
|
||||
Audio.game_success_sound.play()
|
BIN
audio/background.wav
Normal file
BIN
audio/background.wav
Normal file
Binary file not shown.
BIN
audio/game_success.wav
Normal file
BIN
audio/game_success.wav
Normal file
Binary file not shown.
BIN
audio/match_made.wav
Normal file
BIN
audio/match_made.wav
Normal file
Binary file not shown.
BIN
audio/mouse_click.wav
Normal file
BIN
audio/mouse_click.wav
Normal file
Binary file not shown.
BIN
audio/no_match.wav
Normal file
BIN
audio/no_match.wav
Normal file
Binary file not shown.
30
card.py
30
card.py
|
@ -3,30 +3,46 @@ from tkinter import PhotoImage
|
|||
|
||||
|
||||
class Card(turtle.Turtle):
|
||||
card_count = 0
|
||||
|
||||
def __init__(self, image_path):
|
||||
"""
|
||||
Initializes Card object.
|
||||
:param image_path: Path to image
|
||||
:param image_path: Path to image for card_front
|
||||
"""
|
||||
super().__init__()
|
||||
|
||||
# self.size = 150 # desired image height and width (in pixels)
|
||||
self.image_path = image_path
|
||||
self.card_id = Card.card_count
|
||||
Card.card_count += 1
|
||||
self.penup()
|
||||
self.speed(8)
|
||||
self.smaller_back = PhotoImage(file='images/turtle.png').subsample(4, 4)
|
||||
turtle.addshape('card_back', turtle.Shape('image', self.smaller_back))
|
||||
self.smaller_front = PhotoImage(file=image_path).subsample(4, 4)
|
||||
turtle.addshape('card_front', turtle.Shape('image', self.smaller_front))
|
||||
self.back = PhotoImage(file='images/turtle.png').subsample(4, 4)
|
||||
turtle.addshape('card_back', turtle.Shape('image', self.back))
|
||||
self.front = PhotoImage(file=image_path).subsample(4, 4)
|
||||
turtle.addshape(f'card_front{self.card_id}', turtle.Shape('image', self.front))
|
||||
self.shape('card_back')
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
Checks if two cards have the same front image.
|
||||
:param other: Another Card object
|
||||
:return: True if cards have the same front image, False otherwise.
|
||||
"""
|
||||
if type(other) is not Card:
|
||||
raise TypeError('Can only compare Card objects to other Card objects.')
|
||||
else:
|
||||
return self.image_path == other.image_path
|
||||
|
||||
def to_front(self):
|
||||
self.shape('card_front')
|
||||
self.shape(f'card_front{self.card_id}')
|
||||
|
||||
def to_back(self):
|
||||
self.shape('card_back')
|
||||
|
||||
def is_mouse_over(self, x, y):
|
||||
# Collision code reused from D. Atkinson's Turtle Crossing program, with some minor modifications.
|
||||
# http://tiny.cc/ShortCodeLink
|
||||
top_edge = self.ycor() + 103
|
||||
bottom_edge = self.ycor() - 103
|
||||
car_left_edge = self.xcor() - 103
|
||||
|
|
80
main.py
80
main.py
|
@ -1,3 +1,7 @@
|
|||
from tkinter import PhotoImage
|
||||
|
||||
from audio import Audio
|
||||
|
||||
try:
|
||||
import os
|
||||
import random
|
||||
|
@ -14,6 +18,24 @@ try:
|
|||
screen = turtle.Screen()
|
||||
turtle.bgcolor('#46a38d')
|
||||
screen.setup(WIDTH, HEIGHT)
|
||||
screen.title('Turtle Match - Benjamin Zimmerman')
|
||||
|
||||
success_t = turtle.Turtle()
|
||||
success_t.hideturtle()
|
||||
success_t.penup()
|
||||
turtle.register_shape('success_turtle', turtle.Shape('image', PhotoImage(file='images/turtle.png')))
|
||||
success_t.shape('success_turtle')
|
||||
success_t.goto(-379, 0)
|
||||
|
||||
Audio.start_audio()
|
||||
Audio.play_background_music()
|
||||
|
||||
# Scoreboard
|
||||
score_text = turtle.Turtle()
|
||||
score_text.hideturtle()
|
||||
score_text.penup()
|
||||
score_text.goto((WIDTH - HEIGHT) // 2, HEIGHT * .25)
|
||||
score_text.write('Score: 0', font=('Arial', 24, 'bold'))
|
||||
|
||||
|
||||
def coord_translation(x, y):
|
||||
|
@ -26,13 +48,17 @@ try:
|
|||
return x - (WIDTH / 2), y - (HEIGHT / 2)
|
||||
|
||||
|
||||
# Creates list of images, doubles it, and shuffles it
|
||||
image_files = os.listdir('images')
|
||||
|
||||
# Creates list of images, doubles it, and shuffles it
|
||||
image_files.remove('turtle.png')
|
||||
image_files.extend(image_files)
|
||||
random.shuffle(image_files)
|
||||
|
||||
cards = [Card(f'images/{file}') for file in image_files]
|
||||
cards = []
|
||||
for file in image_files:
|
||||
path = f'images/{file}'
|
||||
cards.append(Card(path))
|
||||
|
||||
# Move sprites
|
||||
for i in range(16):
|
||||
|
@ -42,36 +68,60 @@ try:
|
|||
x, y = coord_translation((210 * (i % 4)) + 105, (210 * int(i / 4)) + 105)
|
||||
cards[i].goto(x, y)
|
||||
|
||||
score = 0
|
||||
matches = 0
|
||||
game_is_running = True
|
||||
end_routine_done = False
|
||||
clicked_cards = []
|
||||
|
||||
|
||||
def clicked_card(x, y):
|
||||
"""
|
||||
:return: The card which was clicked
|
||||
Appends the card which was clicked on to the list clicked_cards.
|
||||
"""
|
||||
global clicked_cards
|
||||
if len(clicked_cards) == 2:
|
||||
return None
|
||||
for card in cards:
|
||||
if card.is_mouse_over(x, y):
|
||||
print(cards.index(card))
|
||||
if card.is_mouse_over(x, y) and card.shape()[:10] != 'card_front':
|
||||
card.to_front()
|
||||
clicked_cards.append(card)
|
||||
Audio.click()
|
||||
|
||||
|
||||
def update_score():
|
||||
score_text.clear()
|
||||
score_text.write(f'Score: {score}', font=('Arial', 24, 'bold'))
|
||||
|
||||
|
||||
screen.onclick(fun=clicked_card)
|
||||
|
||||
game_is_running = True
|
||||
clicked_cards = []
|
||||
score = 0
|
||||
|
||||
while game_is_running:
|
||||
time.sleep(0.1)
|
||||
if not end_routine_done:
|
||||
if matches >= 8:
|
||||
success_t.showturtle()
|
||||
Audio.pause_music()
|
||||
Audio.game_success()
|
||||
time.sleep(3.1)
|
||||
Audio.unpause_background_music()
|
||||
end_routine_done = True
|
||||
if len(clicked_cards) == 2:
|
||||
if clicked_cards[0].shape() != clicked_cards[1].shape():
|
||||
time.sleep(2)
|
||||
if clicked_cards[0] == clicked_cards[1]:
|
||||
time.sleep(0.5)
|
||||
clicked_cards[0].hideturtle()
|
||||
clicked_cards[1].hideturtle()
|
||||
score += 5
|
||||
update_score()
|
||||
Audio.match_made()
|
||||
matches += 1
|
||||
else:
|
||||
time.sleep(1)
|
||||
clicked_cards[0].to_back()
|
||||
clicked_cards[1].to_back()
|
||||
print('Wrong!')
|
||||
score -= 1
|
||||
else:
|
||||
print('Correct!')
|
||||
score += 5
|
||||
update_score()
|
||||
Audio.no_match()
|
||||
clicked_cards = []
|
||||
screen.update()
|
||||
|
||||
|
|
Loading…
Reference in a new issue