Skip to content

Commit 21982f7

Browse files
all files for the game play it using exe provide
1 parent 6090184 commit 21982f7

File tree

7 files changed

+290
-0
lines changed

7 files changed

+290
-0
lines changed

Fruit Frenzy/1.mp3

271 KB
Binary file not shown.

Fruit Frenzy/FruitFrenzy.py

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
import tkinter as tk
2+
import random
3+
from PIL import Image, ImageTk
4+
import pygame
5+
import sys
6+
import os
7+
8+
# --- Helper Function for PyInstaller ---
9+
def resource_path(relative_path):
10+
""" Get absolute path to resource, works for dev and for PyInstaller """
11+
try:
12+
# PyInstaller creates a temp folder and stores path in _MEIPASS
13+
base_path = sys._MEIPASS
14+
except Exception:
15+
base_path = os.path.abspath(".")
16+
return os.path.join(base_path, relative_path)
17+
18+
# --- Game Constants ---
19+
WINDOW_WIDTH = 800
20+
WINDOW_HEIGHT = 600
21+
PLAYER_SIZE = 70
22+
PLAYER_SPEED = 35
23+
FRUIT_SIZE = 45
24+
UPDATE_DELAY = 30
25+
MAX_FRUITS = 4
26+
STARTING_LIVES = 3
27+
28+
# --- Asset File Names (using the helper function) ---
29+
INTRO_GIF_FILE = resource_path("intro.gif")
30+
MUSIC_FILE = resource_path("1.mp3")
31+
CATCH_SOUND_FILE = resource_path("1.mp3") # Make sure you have a file named "1.mp3"
32+
HIGHSCORE_FILE = resource_path("highscore.txt")
33+
34+
# --- UI Customization ---
35+
BG_COLOR = "#a2d2ff"
36+
PLAYER_EMOJI = "🧺"
37+
FRUITS_EMOJI = ["🍎", "🍓", "🍊", "🍇", "🍌", "🍒", "🍑"]
38+
HEART_EMOJI = "❤️"
39+
PUNCHLINES = [
40+
"Looks like you couldn't 'ketchup'!",
41+
"That was the 'apple' of my eye!",
42+
"You're 'berry' bad at this!",
43+
"'Orange' you glad you tried?",
44+
"That slip-up was 'bananas'!",
45+
]
46+
47+
class FruityFrenzyGame:
48+
def __init__(self, master):
49+
self.master = master
50+
self.master.title("Fruity Frenzy")
51+
self.master.geometry(f"{WINDOW_WIDTH}x{WINDOW_HEIGHT}")
52+
self.master.resizable(False, False)
53+
54+
# --- IMPORTANT: Handle window close event gracefully ---
55+
self.master.protocol("WM_DELETE_WINDOW", self.on_close)
56+
57+
pygame.mixer.init()
58+
self.load_music()
59+
self.load_sounds()
60+
61+
self.high_score = self.load_high_score()
62+
self.canvas = tk.Canvas(master, bg=BG_COLOR, width=WINDOW_WIDTH, height=WINDOW_HEIGHT, highlightthickness=0)
63+
self.canvas.pack()
64+
65+
self.score = 0
66+
self.lives = STARTING_LIVES
67+
self.game_running = False
68+
self.fruits = []
69+
self.gif_frames = []
70+
self.gif_frame_index = 0
71+
72+
self.setup_intro_screen()
73+
self.setup_game_elements()
74+
self.setup_game_over_screen()
75+
76+
self.show_intro_screen()
77+
78+
def on_close(self):
79+
"""Handles the window closing event to prevent crashes."""
80+
print("Closing game safely...")
81+
self.game_running = False # Stop the game loop
82+
pygame.quit() # Cleanly shut down pygame
83+
self.master.destroy() # Safely close the Tkinter window
84+
85+
def setup_intro_screen(self):
86+
try:
87+
self.load_gif_frames()
88+
self.intro_gif_label = tk.Label(self.master, bg=BG_COLOR)
89+
self.intro_title = self.canvas.create_text(
90+
WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 - 100,
91+
text="Fruity Frenzy", font=("Goudy Stout", 50),
92+
fill="white", state=tk.HIDDEN
93+
)
94+
self.start_button = tk.Button(
95+
self.master, text="Start Game", font=("Helvetica", 25, "bold"),
96+
command=self.start_game, relief="raised", borderwidth=5,
97+
bg="#4CAF50", fg="white"
98+
)
99+
except (FileNotFoundError, tk.TclError):
100+
self.intro_gif_label = None
101+
print(f"Error: '{INTRO_GIF_FILE}' not found or is invalid. The intro screen will be static.")
102+
self.start_button = tk.Button(self.master, text="Start Game (intro.gif not found)", command=self.start_game)
103+
104+
105+
def setup_game_elements(self):
106+
self.player = self.canvas.create_text(0, 0, text=PLAYER_EMOJI, font=("Arial", PLAYER_SIZE), state=tk.HIDDEN)
107+
for _ in range(MAX_FRUITS):
108+
fruit_item = self.canvas.create_text(0, 0, text="", font=("Arial", FRUIT_SIZE), state=tk.HIDDEN)
109+
self.fruits.append({'item': fruit_item, 'speed': 1})
110+
self.score_label = self.canvas.create_text(15, 15, anchor="nw", text="", font=("Helvetica", 20, "bold"), fill="white", state=tk.HIDDEN)
111+
self.lives_label = self.canvas.create_text(WINDOW_WIDTH / 2, 28, anchor="center", text="", font=("Helvetica", 22, "bold"), fill="#ff4d4d", state=tk.HIDDEN)
112+
self.highscore_label = self.canvas.create_text(WINDOW_WIDTH - 15, 15, anchor="ne", text="", font=("Helvetica", 20, "bold"), fill="white", state=tk.HIDDEN)
113+
114+
def setup_game_over_screen(self):
115+
self.game_over_text = self.canvas.create_text(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2 - 50, text="GAME OVER", font=("Helvetica", 50, "bold"), fill="#ff5733", state=tk.HIDDEN)
116+
self.punchline_text = self.canvas.create_text(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2, text="", font=("Helvetica", 20, "italic"), fill="black", state=tk.HIDDEN)
117+
self.restart_button = tk.Button(self.master, text="Restart", font=("Helvetica", 20), command=self.start_game, relief="raised", borderwidth=3, bg="#4CAF50", fg="white")
118+
119+
def show_intro_screen(self):
120+
if self.intro_gif_label and self.gif_frames:
121+
self.intro_gif_label.place(x=0, y=0, relwidth=1, relheight=1)
122+
self.update_gif(0)
123+
self.canvas.itemconfig(self.intro_title, state=tk.NORMAL)
124+
self.start_button.place(relx=0.5, rely=0.5, y=50, anchor="center")
125+
self.master.bind("<KeyPress>", lambda e: None)
126+
self.play_music()
127+
128+
def start_game(self):
129+
self.start_button.place_forget()
130+
if self.intro_gif_label: self.intro_gif_label.place_forget()
131+
self.canvas.itemconfig(self.intro_title, state=tk.HIDDEN)
132+
self.restart_button.place_forget()
133+
self.canvas.itemconfig(self.game_over_text, state=tk.HIDDEN)
134+
self.canvas.itemconfig(self.punchline_text, state=tk.HIDDEN)
135+
136+
self.game_running = True
137+
self.score = 0
138+
self.lives = STARTING_LIVES
139+
self.update_score_label()
140+
self.update_lives_label()
141+
self.canvas.itemconfig(self.highscore_label, text=f"High Score: {self.high_score}", state=tk.NORMAL)
142+
self.canvas.itemconfig(self.score_label, state=tk.NORMAL)
143+
self.canvas.itemconfig(self.lives_label, state=tk.NORMAL)
144+
self.canvas.itemconfig(self.player, state=tk.NORMAL)
145+
self.canvas.coords(self.player, WINDOW_WIDTH / 2, WINDOW_HEIGHT - PLAYER_SIZE)
146+
147+
for fruit in self.fruits:
148+
self.canvas.itemconfig(fruit['item'], state=tk.NORMAL)
149+
self.reset_fruit(fruit)
150+
151+
self.master.bind("<KeyPress>", self.move_player)
152+
self.update_game()
153+
154+
def load_gif_frames(self):
155+
gif = Image.open(INTRO_GIF_FILE)
156+
for i in range(gif.n_frames):
157+
gif.seek(i)
158+
frame = gif.resize((WINDOW_WIDTH, WINDOW_HEIGHT), Image.Resampling.LANCZOS)
159+
self.gif_frames.append(ImageTk.PhotoImage(frame))
160+
161+
def update_gif(self, frame_index):
162+
if self.game_running or not self.gif_frames: return
163+
frame = self.gif_frames[frame_index]
164+
self.intro_gif_label.config(image=frame)
165+
next_frame_index = (frame_index + 1) % len(self.gif_frames)
166+
self.master.after(50, self.update_gif, next_frame_index)
167+
168+
def load_music(self):
169+
try:
170+
pygame.mixer.music.load(MUSIC_FILE)
171+
except pygame.error:
172+
print(f"Error: '{MUSIC_FILE}' not found. Music will not be played.")
173+
174+
def load_sounds(self):
175+
try:
176+
self.catch_sound = pygame.mixer.Sound(CATCH_SOUND_FILE)
177+
except pygame.error:
178+
self.catch_sound = None
179+
print(f"Error: '{CATCH_SOUND_FILE}' not found. Catch sound will not be played.")
180+
181+
def play_catch_sound(self):
182+
if self.catch_sound:
183+
self.catch_sound.play()
184+
185+
def play_music(self):
186+
try:
187+
pygame.mixer.music.play(loops=-1)
188+
except pygame.error:
189+
pass
190+
191+
def update_game(self):
192+
if not self.game_running: return
193+
player_bbox = self.canvas.bbox(self.player)
194+
for fruit in self.fruits:
195+
self.canvas.move(fruit['item'], 0, fruit['speed'])
196+
fruit_bbox = self.canvas.bbox(fruit['item'])
197+
if not fruit_bbox: continue
198+
if player_bbox and (player_bbox[0] < fruit_bbox[2] and player_bbox[2] > fruit_bbox[0] and player_bbox[1] < fruit_bbox[3] and player_bbox[3] > fruit_bbox[1]):
199+
self.score += 1
200+
self.play_catch_sound()
201+
self.update_score_label()
202+
self.reset_fruit(fruit)
203+
elif self.canvas.coords(fruit['item'])[1] > WINDOW_HEIGHT:
204+
self.lives -= 1
205+
self.update_lives_label()
206+
self.reset_fruit(fruit)
207+
if self.lives <= 0:
208+
self.end_game()
209+
return
210+
self.master.after(UPDATE_DELAY, self.update_game)
211+
212+
def end_game(self):
213+
self.game_running = False
214+
if self.score > self.high_score:
215+
self.high_score = self.score
216+
self.save_high_score()
217+
self.canvas.itemconfig(self.highscore_label, text=f"High Score: {self.high_score}")
218+
self.canvas.itemconfig(self.game_over_text, state=tk.NORMAL)
219+
self.canvas.itemconfig(self.punchline_text, text=random.choice(PUNCHLINES), state=tk.NORMAL)
220+
self.restart_button.place(relx=0.5, rely=0.5, y=60, anchor="center")
221+
222+
def reset_fruit(self, fruit):
223+
fruit['speed'] = random.uniform(4.0, 9.0)
224+
x_start = random.randint(FRUIT_SIZE, WINDOW_WIDTH - FRUIT_SIZE)
225+
y_start = -random.randint(FRUIT_SIZE, WINDOW_HEIGHT // 2)
226+
self.canvas.itemconfig(fruit['item'], text=random.choice(FRUITS_EMOJI))
227+
self.canvas.coords(fruit['item'], x_start, y_start)
228+
229+
def move_player(self, event):
230+
if not self.game_running: return
231+
x, y = self.canvas.coords(self.player)
232+
if event.keysym == "Left" and x > PLAYER_SIZE / 2: self.canvas.move(self.player, -PLAYER_SPEED, 0)
233+
elif event.keysym == "Right" and x < WINDOW_WIDTH - PLAYER_SIZE / 2: self.canvas.move(self.player, PLAYER_SPEED, 0)
234+
elif event.keysym == "Up" and y > WINDOW_HEIGHT / 2: self.canvas.move(self.player, 0, -PLAYER_SPEED)
235+
elif event.keysym == "Down" and y < WINDOW_HEIGHT - PLAYER_SIZE / 2: self.canvas.move(self.player, 0, PLAYER_SPEED)
236+
237+
def update_score_label(self): self.canvas.itemconfig(self.score_label, text=f"Score: {self.score}")
238+
def update_lives_label(self): self.canvas.itemconfig(self.lives_label, text=HEART_EMOJI * self.lives)
239+
def load_high_score(self):
240+
try:
241+
with open(HIGHSCORE_FILE, "r") as f: return int(f.read())
242+
except (FileNotFoundError, ValueError): return 0
243+
def save_high_score(self):
244+
with open(HIGHSCORE_FILE, "w") as f: f.write(str(self.high_score))
245+
246+
247+
if __name__ == "__main__":
248+
root = tk.Tk()
249+
game = FruityFrenzyGame(root)
250+
root.mainloop()

Fruit Frenzy/FruitFrenzy.spec

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# -*- mode: python ; coding: utf-8 -*-
2+
3+
4+
a = Analysis(
5+
['FruitFrenzy.py'],
6+
pathex=[],
7+
binaries=[],
8+
datas=[('intro.gif', '.'), ('1.mp3', '.'), ('1.mp3', '.')],
9+
hiddenimports=[],
10+
hookspath=[],
11+
hooksconfig={},
12+
runtime_hooks=[],
13+
excludes=[],
14+
noarchive=False,
15+
optimize=0,
16+
)
17+
pyz = PYZ(a.pure)
18+
19+
exe = EXE(
20+
pyz,
21+
a.scripts,
22+
a.binaries,
23+
a.datas,
24+
[],
25+
name='FruitFrenzy',
26+
debug=False,
27+
bootloader_ignore_signals=False,
28+
strip=False,
29+
upx=True,
30+
upx_exclude=[],
31+
runtime_tmpdir=None,
32+
console=False,
33+
disable_windowed_traceback=False,
34+
argv_emulation=False,
35+
target_arch=None,
36+
codesign_identity=None,
37+
entitlements_file=None,
38+
icon=['intro.ico'],
39+
)

Fruit Frenzy/highscore.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
40

Fruit Frenzy/intro.gif

4.85 MB
Loading

Fruit Frenzy/intro.ico

281 KB
Binary file not shown.

Fruit Frenzy/intro.png

4.85 MB
Loading

0 commit comments

Comments
 (0)