Skip to content

Commit

Permalink
Just patched a bug where the played time would continue when you were…
Browse files Browse the repository at this point in the history
… in the keybindings screen and also created a decorator for screens that pause the game, will implement it next time.
  • Loading branch information
Spacexplorer11 committed Oct 21, 2024
1 parent a4a2e28 commit 59c1c12
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 75 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ The game should start, but if you have **any** trouble, [create an issue with th
- The mini-explosion gif when a bullet hits the ground, you can find it [here](https://en.picmix.com/stamp/Explode-Digital-Art-2334354)
- The mute symbol can be found [here](https://www.freepik.com/icon/mute_7971700)
- The unmute symbol can be found [here](https://lh3.googleusercontent.com/7mt9pf2gQYwXeU8d9y8Uow4p9lpVTMy0VJxoUA1jFNQuFB_G_UlLSGYq62D9Hs2bqFrqizUWtBMiViObGGIf5LREmA=s60)
- The pause button, settings gear symbol & filled circle(circle.png) can be found in the SF Symbols app on Mac (It can be downloaded here: [SF Symbols](https://developer.apple.com/sf-symbols/))
- The pause button & settings gear symbol can be found in the SF Symbols app on Mac (It can be downloaded here: [SF Symbols](https://developer.apple.com/sf-symbols/))
- All sounds were sourced from [Pixabay](https://pixabay.com) and/or [Uppbeat](https://uppbeat.io)
Binary file removed space_dodge/assets/slider/circle.png
Binary file not shown.
61 changes: 35 additions & 26 deletions space_dodge/classes/slider.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,38 @@


class Slider:
def __init__(self, x, y, width, height, min_value, max_value, value, line_image, circle_image):
self.x = x
self.y = y
self.width = width
self.height = height
self.min_value = min_value
self.max_value = max_value
self.value = value
self.line_image = line_image
self.circle_image = circle_image
self.line_rect = line_image.get_rect(topleft=(x, y))
self.circle_rect = circle_image.get_rect(
center=(x + (value - min_value) / (max_value - min_value) * width, y + height // 2))

def update_slider(self):
pos = pygame.mouse.get_pos()
if self.line_rect.collidepoint(pos) and pygame.mouse.get_pressed()[0]:
self.value = (pos[0] - self.x) / self.width * (self.max_value - self.min_value) + self.min_value
self.value = max(self.min_value, min(self.max_value, self.value))
self.circle_rect.centerx = self.x + (self.value - self.min_value) / (
self.max_value - self.min_value) * self.width
return self.value

def draw(self, surface):
surface.blit(self.line_image, self.line_rect.topleft)
surface.blit(self.circle_image, self.circle_rect.topleft)
def __init__(self, pos: list, size: tuple, initial_val: float, min: int, max: int, title):
self.pos = pos
self.size = size

self.slider_left_pos = self.pos[0] - (size[0] // 2)
self.slider_right_pos = self.pos[0] + (size[0] // 2)
self.slider_top_pos = self.pos[1] - (size[1] // 2)

self.min = min
self.max = max

# Calculate the initial position of the button based on the initial value percentage
self.initial_val = initial_val
self.button_x = int((self.slider_left_pos + self.initial_val * 100))

self.container_rect = pygame.Rect(self.slider_left_pos, self.slider_top_pos, size[0], size[1])
self.button_rect = pygame.Rect(self.button_x - 5, self.slider_top_pos, 10, size[1])

self.title = title
self.pos[0] = self.title.get_width() + self.pos[0]

def move_slider(self, mouse_pos):
self.button_rect.x = mouse_pos[0] - 5

def render(self, window):
pygame.draw.rect(window, (255, 255, 255), self.container_rect)
pygame.draw.rect(window, (0, 0, 0), self.button_rect)
window.blit(self.title, (self.slider_left_pos - self.title.get_width() - 10, self.pos[1] - self.title.get_height() / 2))
window.blit(pygame.font.SysFont("comicsans", 20).render(str(int(self.get_value())), 1, (255, 255, 255)), (self.slider_right_pos + 10, self.pos[1] - 10))

def get_value(self):
val_range = self.slider_right_pos - self.slider_left_pos - 1
button_val = self.button_rect.x - self.slider_left_pos

return (button_val / val_range) * (self.max - self.min) + self.min + 5
9 changes: 7 additions & 2 deletions space_dodge/drawing/draw.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import pygame

from space_dodge.classes.animation import Animation
from space_dodge.classes.button import Button
from space_dodge.drawing.tutorial_and_information.settings import settings_menu
from space_dodge.file_handling.constants_and_file_loading import (
WINDOW, WIDTH, HEIGHT, FONT, BULLET_HEIGHT,
threeLives, twoLives, oneLife, background, bullet_texture, bullet_explosion_frames,
pauseButtonImage, muteImage, unmuteImage
pauseButtonImage, muteImage, unmuteImage, settingsIcon
)

# Create a mask for the bullet
bullet_mask = pygame.mask.from_surface(bullet_texture)


def draw(player, bullets, direction, highscore, highscoreBreak, mute, lives, timeText, scoreText, explosions, dt):
def draw(player, bullets, direction, highscore, highscoreBreak, mute, lives, timeText, scoreText, explosions, dt, settingsButton):
WINDOW.blit(background, (0, 0))

# Draw settings icon
WINDOW.blit(settingsButton.image, (settingsButton.x, settingsButton.y))

# Draw bullets and add explosions
for bullet in bullets:
WINDOW.blit(bullet_texture, (bullet.x, bullet.y))
Expand Down
24 changes: 8 additions & 16 deletions space_dodge/drawing/pause_menu/pause_function.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import time

import pygame

from space_dodge.classes.button import Button
from space_dodge.file_handling.constants_and_file_loading import (
WINDOW, PAUSE_FONT, PAUSE_FONT_SMALL, pause_background, muteImage, unmuteImage)
WINDOW, PAUSE_FONT, PAUSE_FONT_SMALL, pause_background, muteImage, unmuteImage, pause_time)
from space_dodge.file_handling.utility import ref

mutePauseSymbol = Button(pygame.transform.scale(muteImage, (120, 80)), 180, 430)
unmutePauseSymbol = Button(pygame.transform.scale(unmuteImage, (120, 80)), 180, 430)


def pause_menu(score, elapsedTime, highscore, highscoreBreak, mute, pausedTimes):
@pause_time
def pause_menu(score, elapsedTime, highscore, highscoreBreak, mute):
pygame.mixer.music.load(ref("sounds/background_music/pause_screen/pause_music.mp3"))
pygame.mixer.music.play(-1)
pauseStartTime = time.time()
pause = True

while pause:
Expand All @@ -23,29 +21,23 @@ def pause_menu(score, elapsedTime, highscore, highscoreBreak, mute, pausedTimes)
WINDOW.blit(PAUSE_FONT.render(f"Time played: {round(elapsedTime)} secs", 1, "white"), (180, 250))
WINDOW.blit(PAUSE_FONT.render(f"Score: {score}", 1, "white"), (180, 310))
WINDOW.blit(PAUSE_FONT_SMALL.render("Your high score", 1, "white"), (180, 370))
highScoreText = PAUSE_FONT_SMALL.render(f" is {highscore}" if highscoreBreak else f" was {highscore}", 1,
"white")
highScoreText = PAUSE_FONT_SMALL.render(f" is {highscore}" if highscoreBreak else f" was {highscore}", 1, "white")
WINDOW.blit(highScoreText, (490, 370))
WINDOW.blit(mutePauseSymbol.image if mute else unmutePauseSymbol.image, (180, 430))
pygame.mixer.music.pause() if mute else pygame.mixer.music.unpause()

pausedTime = time.time() - pauseStartTime

for event in pygame.event.get():
if event.type == pygame.QUIT:
return False, pause, 0.0
return False, pause
elif event.type in [pygame.KEYDOWN, pygame.MOUSEBUTTONDOWN]:
keys = pygame.key.get_pressed()
if keys[pygame.K_m] or (unmutePauseSymbol.rect.collidepoint(pygame.mouse.get_pos())
or mutePauseSymbol.rect.collidepoint(pygame.mouse.get_pos())):
if keys[pygame.K_m] or (unmutePauseSymbol.rect.collidepoint(pygame.mouse.get_pos()) or mutePauseSymbol.rect.collidepoint(pygame.mouse.get_pos())):
mute = not mute
elif keys[pygame.K_p] or keys[pygame.K_ESCAPE]:
pausedTimes.append(round(pausedTime))
totalPausedTime = sum(pausedTimes)
pygame.mixer.music.stop()
pygame.mixer.music.unload()
pygame.mixer.music.load(ref("sounds/background_music/background_music.mp3"))
pygame.mixer.music.play(-1)
return True, pause, totalPausedTime
return True, pause

pygame.display.update()
pygame.display.update()
4 changes: 2 additions & 2 deletions space_dodge/drawing/title_screen/draw_title_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ def draw_title():
if event.type == pygame.QUIT:
return False
elif event.type == pygame.KEYDOWN:
startTime, info_screen_active, keyPress = keybindings_screen(None)
return startTime, info_screen_active, keyPress
startTime = keybindings_screen(None)
return startTime
welcome_screen()
18 changes: 5 additions & 13 deletions space_dodge/drawing/tutorial_and_information/keybindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,18 @@ def keybindings_screen(pausedTimes):
get_height() - keybindText4.get_height() - 160) / 2))
WINDOW.blit(resumeText, (WIDTH / 2 - resumeText.get_width() / 2, 740))
pygame.display.update()
info_screen_active = True
pauseStartTime = time.time()
keyPress = True
while info_screen_active:
pausedTime = time.time() - pauseStartTime
while True:
pausedTime = int(time.time() - pauseStartTime)
for event in pygame.event.get():
if event.type == pygame.KEYUP:
keyPress = False
if event.type == pygame.QUIT:
running = False
info_screen_active = False
return running, info_screen_active
return running, False, 0.0
if event.type == pygame.KEYDOWN and not keyPress:
keyPress = True
info_screen_active = False
if pausedTimes is not None:
totalPausedTime = 0.0
pausedTimes.append(round(pausedTime))
for num in pausedTimes:
totalPausedTime += num
return totalPausedTime, pausedTime, keyPress, info_screen_active
return True, False, pausedTime
startTime = time.time()
return startTime, info_screen_active, keyPress
return startTime
28 changes: 25 additions & 3 deletions space_dodge/drawing/tutorial_and_information/settings.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
import time

import pygame
import pygame_widgets
import threading

from space_dodge.classes.button import Button
from pygame_widgets.slider import Slider
from pygame_widgets.textbox import TextBox
from space_dodge.file_handling.constants_and_file_loading import (
WINDOW, pause_background, muteImage, unmuteImage)
WINDOW, pause_background, muteImage, unmuteImage, PAUSE_FONT)
from space_dodge.file_handling.utility import ref

mutePauseSymbol = Button(pygame.transform.scale(muteImage, (120, 80)), 180, 430)
unmutePauseSymbol = Button(pygame.transform.scale(unmuteImage, (120, 80)), 180, 430)
slider_title = pygame.font.SysFont("comicsans", 30).render("Volume", 1, (255, 255, 255))


def settings_menu(mute, pausedTimes):
pygame.mixer.music.load(ref("sounds/background_music/pause_screen/pause_music.mp3"))
pygame.mixer.music.play(-1)
slider = Slider(WINDOW, 350, 400, 100, 30, min=0, max=100, initial=pygame.mixer.music.get_volume() * 100)
output = TextBox(WINDOW, 500, 395, 75, 50, fontSize=30)

output.disable() # Act as label instead of textbox
pauseStartTime = time.time()
pause = True

while pause:
WINDOW.blit(pause_background, (0, 0))
WINDOW.blit(PAUSE_FONT.render("SETTINGS MENU", 1, "white"), (250, 176))
WINDOW.blit(mutePauseSymbol.image if mute else unmutePauseSymbol.image, (180, 430))
pygame.mixer.music.pause() if mute else pygame.mixer.music.unpause()
WINDOW.blit(slider_title, (200, 390))

pausedTime = time.time() - pauseStartTime

for event in pygame.event.get():
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
return False, pause, 0.0
elif event.type in [pygame.KEYDOWN, pygame.MOUSEBUTTONDOWN]:
keys = pygame.key.get_pressed()
if keys[pygame.K_m] or (unmutePauseSymbol.rect.collidepoint(pygame.mouse.get_pos())
or mutePauseSymbol.rect.collidepoint(pygame.mouse.get_pos())):
mute = not mute
elif keys[pygame.K_p] or keys[pygame.K_ESCAPE]:
elif keys[pygame.K_ESCAPE]:
pausedTimes.append(round(pausedTime))
totalPausedTime = sum(pausedTimes)
pygame.mixer.music.stop()
Expand All @@ -41,4 +53,14 @@ def settings_menu(mute, pausedTimes):
pygame.mixer.music.play(-1)
return True, pause, totalPausedTime

output.setText(slider.getValue())

pygame_widgets.update(events)

pygame.display.update()
update_music = threading.Thread(target=update_volume, args=(slider.getValue() / 100,))
update_music.start()


def update_volume(volume):
pygame.mixer.music.set_volume(volume)
14 changes: 14 additions & 0 deletions space_dodge/file_handling/constants_and_file_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ def draw_loading_bar(screen, progress, width=392, height=30):
p.display.update()


# Decorator to calculate the pause time
def pause_time(func):
def wrapper(*args, **kwargs):
import time
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
pausedTime = int(end_time - start_time)
if isinstance(result, tuple):
return result + (pausedTime,)
return result, pausedTime
return wrapper


# Load all the files/variables with loading bar updates
total_assets = 27 # Total number of assets to load
loaded_assets = 0
Expand Down
28 changes: 16 additions & 12 deletions space_dodge/__main__.py → space_dodge/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# Import all constant variables
from file_handling.constants_and_file_loading import (FONT,
FONT_MEDIUM, FONT_BIG, WIDTH, HEIGHT, WINDOW)
FONT_MEDIUM, FONT_BIG, WIDTH, HEIGHT, WINDOW, settingsIcon)
# Import all the files( images, sounds, etc. )
from file_handling.constants_and_file_loading import (muteImage, unmuteImage, pauseButtonImage, background,
sadSound, GameOverSound, highscoreSound)
Expand All @@ -17,6 +17,7 @@
from space_dodge.drawing.pause_menu.pause_function import pause_menu
from space_dodge.drawing.title_screen.draw_title_screen import draw_title
from space_dodge.drawing.tutorial_and_information.keybindings import keybindings_screen
from space_dodge.drawing.tutorial_and_information.settings import settings_menu
from space_dodge.file_handling.loading_func import load_highscore
from space_dodge.file_handling.saving import save_object
from space_dodge.file_handling.utility import ref
Expand All @@ -32,15 +33,16 @@ def main():
mute = False # Is the game muted or not
lives = 3 # Self-explanatory
highscoreSoundPlayed = False # Has the highscore sound been played?
pausedTimes = [] # All the pause time
totalPausedTime = 0.0 # The total pause time
pausedTimes = [] # The total pause time
highscore_file_not_found = False # Is the highscore file not found?
last_time = time.time()
explosions = [] # The list of explosions
player = Player() # Create the player object
muteButton = Button(muteImage, 132, 10) # Create the mute symbol object
unmuteButton = Button(unmuteImage, 132, 10) # Create the unmute symbol object
pauseButton = Button(pauseButtonImage, 900, 10) # Create the pause symbol object
settingsButton = Button(settingsIcon, WIDTH - settingsIcon.get_width() - 10, HEIGHT - settingsIcon.get_height()) # Create the settings symbol object

clock = pygame.time.Clock() # The clock for the game

Expand All @@ -57,11 +59,11 @@ def main():

# Load the high score from file
highscore = load_highscore(ref("file_handling/highscore.pickle"))
if highscore == 0:
if highscore is 0:
highscore_file_not_found = True

# Draw the title screen
draw_title()
startTime = draw_title()

# The text for when the player loses a life
lostLivesText = FONT_MEDIUM.render("You lost a life, you are now on 2 lives!", 1, "red")
Expand All @@ -77,7 +79,7 @@ def main():

# The time the game was paused & playing
elapsedTime = time.time() - startTime
elapsedTime -= totalPausedTime
elapsedTime -= sum(pausedTimes)

# These variables are used to calculate the time between frames for the explosion animation
current_time = time.time()
Expand Down Expand Up @@ -119,17 +121,19 @@ def main():
if keys[pygame.K_m]:
mute = not mute
if keys[pygame.K_k] or keys[pygame.K_i]:
keybindings_screen(pausedTimes)
running, pause, pausedTime = keybindings_screen(pausedTimes)
pausedTimes.append(pausedTime)
if ((muteButton.rect.collidepoint(pygame.mouse.get_pos()) or unmuteButton.rect.collidepoint(
pygame.mouse.get_pos()))
and event.type == pygame.MOUSEBUTTONDOWN):
and pygame.mouse.get_pressed()[0]):
mute = not mute
if (pauseButton.rect.collidepoint(pygame.mouse.get_pos()) and event.type == pygame.MOUSEBUTTONDOWN) or (
if (pauseButton.rect.collidepoint(pygame.mouse.get_pos()) and pygame.mouse.get_pressed()[0]) or (
keys[pygame.K_p]
or keys[pygame.K_ESCAPE]):
running, pause, totalPausedTime = pause_menu(score, elapsedTime, highscore, highscoreBreak, mute,
pausedTimes)
break
running, pause, pausedTime = pause_menu(score, elapsedTime, highscore, highscoreBreak, mute)
pausedTimes.append(pausedTime)
if settingsButton.rect.collidepoint(pygame.mouse.get_pos()) and pygame.mouse.get_pressed()[0]:
running, pause = settings_menu(mute)

score += 1
if score > highscore:
Expand Down Expand Up @@ -205,7 +209,7 @@ def main():
save_object(highscore) if score >= highscore else None
continue

draw(player, bullets, direction, highscore, highscoreBreak, mute, lives, timeText, scoreText, explosions, dt)
draw(player, bullets, direction, highscore, highscoreBreak, mute, lives, timeText, scoreText, explosions, dt, settingsButton)

pygame.quit()

Expand Down

0 comments on commit 59c1c12

Please sign in to comment.