From dc1600fdc6f04c733d25a30d2cbb7addc098d5d2 Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Fri, 4 Nov 2022 22:27:13 -0400 Subject: [PATCH 01/11] Began refactoring code Extracting common code into functions and putting some stuff in respective classes. --- .gitignore | 7 ++ background.py | 5 +- bean.py | 3 +- button.py | 13 ++- main.py | 247 +++++++++++++++++++++----------------------------- player.py | 21 ++++- 6 files changed, 143 insertions(+), 153 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb9c72a --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ + +__pycache__/background.cpython-310.pyc +__pycache__/bean.cpython-310.pyc +__pycache__/button.cpython-310.pyc +__pycache__/player.cpython-310.pyc +__pycache__/utils.cpython-310.pyc +*.pyc diff --git a/background.py b/background.py index 097a092..765aeaa 100644 --- a/background.py +++ b/background.py @@ -1,9 +1,10 @@ -import pygame +import pygame, colorsys class Background: def __init__(self): self.sprite = pygame.image.load('data/gfx/bg.png') self.position = 0 - self.uncoloredSprite = pygame.image.load('data/gfx/bg.png') + self.uncoloredSprite = pygame.image.load('data/gfx/bg.png') + def setSprite(self, tint): copy = self.uncoloredSprite.copy() color = colorsys.hsv_to_rgb(tint,1,1) diff --git a/bean.py b/bean.py index 5b212bb..46c1708 100644 --- a/bean.py +++ b/bean.py @@ -1,6 +1,7 @@ import pygame class Bean: + sprite = pygame.image.load('data/gfx/bean.png') + def __init__(self): - self.sprite = pygame.image.load('data/gfx/bean.png') self.position = pygame.Vector2() self.position.xy \ No newline at end of file diff --git a/button.py b/button.py index ef92dfb..cfcd1ad 100644 --- a/button.py +++ b/button.py @@ -1,7 +1,14 @@ import pygame class Button: - def __init__(self): - self.price = 3 - self.level = 1 sprite = pygame.image.load('data/gfx/button.png') typeIndicatorSprite = pygame.image.load('data/gfx/null_indicator.png') + + def __init__(self): + self.price = 3 + self.level = 1 + + def set_price(self, newPrice): + self.price = newPrice + + def set_indicator(self, indicator): + self.typeIndicatorSprite = pygame.image.load(indicator) \ No newline at end of file diff --git a/main.py b/main.py index a4256fa..fe486cd 100644 --- a/main.py +++ b/main.py @@ -1,94 +1,109 @@ import pygame, sys, time, random, colorsys, math -from pygame.math import Vector2 from pygame.locals import * -from .player import Player -from .background import Background -from .button import Button -from .bean import Bean -from .utils import clamp -from .utils import checkCollisions +from player import Player +from background import Background +from button import Button +from bean import Bean +from utils import * +pygame.init() +# set the display +pygame.display.set_caption('Flappuccino') +pygame.display.set_icon(Bean().sprite) +DISPLAY=pygame.display.set_mode((640,480),0,32) +player = Player() +# get fonts +font = pygame.font.Font('data/fonts/font.otf', 100) +font_small = pygame.font.Font('data/fonts/font.otf', 32) +font_20 = pygame.font.Font('data/fonts/font.otf', 20) +# get some images +shop = pygame.image.load('data/gfx/shop.png') +shop_bg = pygame.image.load('data/gfx/shop_bg.png') +retry_button = pygame.image.load('data/gfx/retry_button.png') +logo = pygame.image.load('data/gfx/logo.png') +title_bg = pygame.image.load('data/gfx/bg.png') +title_bg.fill((255, 30.599999999999998, 0.0), special_flags=pygame.BLEND_ADD) +shadow = pygame.image.load('data/gfx/shadow.png') +# get sounds +flapfx = pygame.mixer.Sound("data/sfx/flap.wav") +upgradefx = pygame.mixer.Sound("data/sfx/upgrade.wav") +beanfx = pygame.mixer.Sound("data/sfx/bean.wav") +deadfx = pygame.mixer.Sound("data/sfx/dead.wav") +# colors +WHITE=(255,255,255) # constant -def main(): - pygame.init() - # set the display - DISPLAY=pygame.display.set_mode((640,480),0,32) - pygame.display.set_caption('Flappuccino') - pygame.display.set_icon(Bean().sprite) - # get fonts - font = pygame.font.Font('data/fonts/font.otf', 100) - font_small = pygame.font.Font('data/fonts/font.otf', 32) - font_20 = pygame.font.Font('data/fonts/font.otf', 20) - # get some images - shop = pygame.image.load('data/gfx/shop.png') - shop_bg = pygame.image.load('data/gfx/shop_bg.png') - retry_button = pygame.image.load('data/gfx/retry_button.png') - logo = pygame.image.load('data/gfx/logo.png') - title_bg = pygame.image.load('data/gfx/bg.png') - title_bg.fill((255, 30.599999999999998, 0.0), special_flags=pygame.BLEND_ADD) - shadow = pygame.image.load('data/gfx/shadow.png') - # get sounds - flapfx = pygame.mixer.Sound("data/sfx/flap.wav") - upgradefx = pygame.mixer.Sound("data/sfx/upgrade.wav") - beanfx = pygame.mixer.Sound("data/sfx/bean.wav") - deadfx = pygame.mixer.Sound("data/sfx/dead.wav") - # colors - WHITE=(255,255,255) # constant - # variables - rotOffset = -5 - # creating a new object player - player = Player() +def start(): + global height, beanMultiplier, beans, buttons, last_time, clicked, jump, dt, mouseX, mouseY + last_time = time.time() + clicked = jump = False + height = dt = 0 + beanMultiplier = 5 beans = [] buttons = [] + mouseX,mouseY = pygame.mouse.get_pos() + player.reset() # adding three buttons - for i in range(3): buttons.append(Button()) + for _ in range(3): + buttons.append(Button()) # now simply loading images based off of indexes in the list - buttons[0].typeIndicatorSprite = pygame.image.load('data/gfx/flap_indicator.png') - buttons[0].price = 5 - buttons[1].typeIndicatorSprite = pygame.image.load('data/gfx/speed_indicator.png') - buttons[1].price = 5 - buttons[2].typeIndicatorSprite = pygame.image.load('data/gfx/beanup_indicator.png') - buttons[2].price = 30 + buttons[0].set_indicator('data/gfx/flap_indicator.png') + buttons[0].set_price(5) + buttons[1].set_indicator('data/gfx/speed_indicator.png') + buttons[1].set_price(5) + buttons[2].set_indicator('data/gfx/beanup_indicator.png') + buttons[2].set_price(30) # getting 5 beans - for i in range(5): beans.append(Bean()) + for _ in range(5): + beans.append(Bean()) # now looping through the beans list for bean in beans: bean.position.xy = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()), beans.index(bean)*-200 - player.position.y + pygame.mixer.Sound.play(flapfx) + +def funcOne(toggle = True): + global dt, last_time, mouseX, mouseY, clicked, keys, jump + dt = (time.time() - last_time) * 60 + last_time = time.time() + # get the position of the mouse + if(toggle): + mouseX,mouseY = pygame.mouse.get_pos() + # getting the keys pressed + clicked = jump = False + keys = pygame.key.get_pressed() + eventHandler() + +def eventHandler(): + global jump, clicked + for event in pygame.event.get(): + if event.type==pygame.KEYDOWN and event.key==K_SPACE: + jump = True + if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: + clicked = True + if clicked and mouseY < DISPLAY.get_height() - 90: + jump = True + if event.type==QUIT: + pygame.quit() + sys.exit() + +def main(): + global player, clicked, jump, height, mouseY, dt, mouseX, keys, beanMultiplier, beans, buttons + # variables + rotOffset = -5 + # creating a new object player + start() # creating a list of backgrounds, with each index being an object bg = [Background(), Background(), Background()] # some variables that we need - beanCount = 0 startingHeight = player.position.y - height = 0 - health = 100 - flapForce = 3 - beanMultiplier = 5 - dead = False - # we need the framerate and then the time - framerate = 60 - last_time = time.time() splashScreenTimer = 0 #splash screen - # playing a sound - pygame.mixer.Sound.play(flapfx) while splashScreenTimer < 100: - dt = time.time() - last_time - dt *= 60 - last_time = time.time() - + funcOne(False) splashScreenTimer += dt - - for event in pygame.event.get(): - # if the user clicks the button - if event.type==QUIT: - pygame.quit() - sys.exit() - DISPLAY.fill((231, 205, 183)) # fill the start message on the top of the game startMessage = font_small.render("POLYMARS", True, (171, 145, 123)) DISPLAY.blit(startMessage, (DISPLAY.get_width()/2 - startMessage.get_width()/2, DISPLAY.get_height()/2 - startMessage.get_height()/2)) - # update display pygame.display.update() # wait for 10 seconds @@ -98,22 +113,7 @@ def main(): # title screen pygame.mixer.Sound.play(flapfx) while titleScreen: - dt = time.time() - last_time - dt *= 60 - last_time = time.time() - # get the position of the mouse - mouseX,mouseY = pygame.mouse.get_pos() - # getting the keys pressed - clicked = False - keys = pygame.key.get_pressed() - # checking events - for event in pygame.event.get(): - if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: - clicked = True - # if the player quits - if event.type==QUIT: - pygame.quit() - sys.exit() + funcOne() # so the user clicked, and by any change the mouse's position was on the buttons if (clicked and checkCollisions(mouseX, mouseY, 3, 3, DISPLAY.get_width()/2 - retry_button.get_width()/2, 288, retry_button.get_width(), retry_button.get_height())): clicked = False @@ -133,26 +133,7 @@ def main(): # the main game loop while True: - dt = time.time() - last_time - dt *= 60 - last_time = time.time() - # again, get the position - mouseX,mouseY = pygame.mouse.get_pos() - - jump = False - clicked = False - keys = pygame.key.get_pressed() - # get events - for event in pygame.event.get(): - if event.type==pygame.KEYDOWN and event.key==K_SPACE: - jump = True - if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: - clicked = True - if clicked and mouseY < DISPLAY.get_height() - 90: - jump = True - if event.type==QUIT: - pygame.quit() - sys.exit() + funcOne() camOffset = -player.position.y + DISPLAY.get_height()/2 - player.currentSprite.get_size()[1]/2 @@ -170,7 +151,7 @@ def main(): DISPLAY.blit(pygame.transform.rotate(player.currentSprite, clamp(player.velocity.y, -10, 5)*rotOffset), (player.position.x,player.position.y + camOffset)) DISPLAY.blit(shop_bg, (0, 0)) - pygame.draw.rect(DISPLAY,(81,48,20),(21,437,150*(health/100),25)) + pygame.draw.rect(DISPLAY,(81,48,20),(21,437,150*(player.health/100),25)) DISPLAY.blit(shop, (0, 0)) for button in buttons: @@ -180,9 +161,9 @@ def main(): levelDisplay = font_20.render('Lvl. ' + str(button.level), True, (200,200,200)) DISPLAY.blit(levelDisplay, (234 + (buttons.index(button)*125), 441)) DISPLAY.blit(button.typeIndicatorSprite, (202 + (buttons.index(button)*125), 377)) - beanCountDisplay = font_small.render(str(beanCount).zfill(7), True, (0,0,0)) + beanCountDisplay = font_small.render(str(player.beanCount).zfill(7), True, (0,0,0)) DISPLAY.blit(beanCountDisplay, (72, 394)) - if dead: + if player.dead: DISPLAY.blit(retry_button, (4, 4)) deathMessage = font_small.render("RETRY", True, (0, 0, 0)) DISPLAY.blit(deathMessage, (24, 8)) @@ -198,15 +179,15 @@ def main(): player.velocity.x = abs(player.velocity.x) player.currentSprite = player.rightSprite rotOffset = -5 - if jump and not dead: - player.velocity.y = -flapForce + if jump and not player.dead: + player.velocity.y = -player.flapForce pygame.mixer.Sound.play(flapfx) player.position.y += player.velocity.y*dt player.velocity.y = clamp(player.velocity.y + player.acceleration*dt, -99999999999, 50) - health -= 0.2*dt - if health <= 0 and not dead: - dead = True + player.health -= 0.2*dt + if player.health <= 0 and not player.dead: + player.invert_death() pygame.mixer.Sound.play(deadfx) @@ -215,57 +196,33 @@ def main(): bean.position.y -= DISPLAY.get_height()*2 bean.position.x = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()) if (checkCollisions(player.position.x, player.position.y, player.currentSprite.get_width(), player.currentSprite.get_height(), bean.position.x, bean.position.y, bean.sprite.get_width(), bean.sprite.get_height())): - dead = False pygame.mixer.Sound.play(beanfx) - beanCount += 1 - health = 100 + player.beanCount += 1 + player.health = 100 bean.position.y -= DISPLAY.get_height() - random.randrange(0, 200) bean.position.x = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()) for button in buttons: buttonX,buttonY = 220 + (buttons.index(button)*125), 393 - if clicked and not dead and checkCollisions(mouseX, mouseY, 3, 3, buttonX, buttonY, button.sprite.get_width(), button.sprite.get_height()): - if (beanCount >= button.price): + if clicked and not player.dead and checkCollisions(mouseX, mouseY, 3, 3, buttonX, buttonY, button.sprite.get_width(), button.sprite.get_height()): + if (player.beanCount >= button.price): pygame.mixer.Sound.play(upgradefx) button.level += 1 - beanCount -= button.price + player.beanCount -= button.price button.price = round(button.price*2.5) if (buttons.index(button) == 0): - flapForce *= 1.5 + player.flapForce *= 1.5 if (buttons.index(button) == 1): player.velocity.x *= 1.5 if (buttons.index(button) == 2): - oldBeanMultipler = beanMultiplier beanMultiplier += 10 - for i in range(beanMultiplier): + for _ in range(beanMultiplier): beans.append(Bean()) beans[-1].position.xy = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()), player.position.y - DISPLAY.get_height() - random.randrange(0, 200) - if dead and clicked and checkCollisions(mouseX, mouseY, 3, 3, 4, 4, retry_button.get_width(), retry_button.get_height()): - health = 100 - player.velocity.xy = 3, 0 - player.position.xy = 295, 100 - player.currentSprite = player.rightSprite - beanCount = 0 - height = 0 - flapForce = 3 - beanMultiplier = 5 - buttons = [] - for i in range(3): buttons.append(Button()) - buttons[0].typeIndicatorSprite = pygame.image.load('data/gfx/flap_indicator.png') - buttons[0].price = 5 - buttons[1].typeIndicatorSprite = pygame.image.load('data/gfx/speed_indicator.png') - buttons[1].price = 5 - buttons[2].typeIndicatorSprite = pygame.image.load('data/gfx/beanup_indicator.png') - buttons[2].price = 30 - beans = [] - for i in range(5): beans.append(Bean()) - for bean in beans: - bean.position.xy = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()), beans.index(bean)*-200 - player.position.y - pygame.mixer.Sound.play(upgradefx) - dead = False + if player.dead and clicked and checkCollisions(mouseX, mouseY, 3, 3, 4, 4, retry_button.get_width(), retry_button.get_height()): + start() - bg[0].position = camOffset + round(player.position.y/DISPLAY.get_height())*DISPLAY.get_height() bg[1].position = bg[0].position + DISPLAY.get_height() bg[2].position = bg[0].position - DISPLAY.get_height() @@ -274,4 +231,4 @@ def main(): pygame.time.delay(10) if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/player.py b/player.py index 3f4f819..126b6f4 100644 --- a/player.py +++ b/player.py @@ -2,10 +2,27 @@ class Player: position = pygame.Vector2() - position.xy = 295, 100 velocity = pygame.Vector2() + dead = False + health = 100 + position.xy = 295, 100 velocity.xy = 3, 0 acceleration = 0.1 + flapForce = 3 + beanCount = 0 rightSprite = pygame.image.load('data/gfx/player.png') + currentSprite = rightSprite leftSprite = pygame.transform.flip(rightSprite, True, False) - currentSprite = rightSprite \ No newline at end of file + + def reset(self): + self.position.xy = 295, 100 + self.velocity.xy = 3, 0 + self.acceleration = 0.1 + self.currentSprite = self.rightSprite + self.dead = False + self.health = 100 + self.beanCount = 0 + self.flapForce = 3 + + def invert_death(self): + self.dead = not self.dead \ No newline at end of file From ae4130e3a767bb138263f3f70e79ba91b974f38c Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Sat, 5 Nov 2022 00:20:27 -0400 Subject: [PATCH 02/11] Further refactoring Continued working on reducing length of main file, moving some functionality to their respective classes, and overall making the code more succinct. --- bean.py | 4 +-- button.py | 18 +++++----- main.py | 101 ++++++++++++++++++++++-------------------------------- player.py | 39 +++++++++++++-------- 4 files changed, 77 insertions(+), 85 deletions(-) diff --git a/bean.py b/bean.py index 46c1708..5cda771 100644 --- a/bean.py +++ b/bean.py @@ -2,6 +2,6 @@ class Bean: sprite = pygame.image.load('data/gfx/bean.png') - def __init__(self): + def __init__(self, x_pos = 0, y_pos = 0): self.position = pygame.Vector2() - self.position.xy \ No newline at end of file + self.position.xy = x_pos, y_pos \ No newline at end of file diff --git a/button.py b/button.py index cfcd1ad..73cde0d 100644 --- a/button.py +++ b/button.py @@ -1,14 +1,16 @@ import pygame +from pygame.image import load class Button: - sprite = pygame.image.load('data/gfx/button.png') - typeIndicatorSprite = pygame.image.load('data/gfx/null_indicator.png') + sprite = load('data/gfx/button.png') + typeIndicatorSprite = load('data/gfx/null_indicator.png') - def __init__(self): - self.price = 3 + def __init__(self, index, indicator): + self.price = 5 self.level = 1 + self.index = index + self.typeIndicatorSprite = load(indicator) + self.position = pygame.Vector2() + self.position.xy = 220 + (self.index*125), 393 def set_price(self, newPrice): - self.price = newPrice - - def set_indicator(self, indicator): - self.typeIndicatorSprite = pygame.image.load(indicator) \ No newline at end of file + self.price = newPrice \ No newline at end of file diff --git a/main.py b/main.py index fe486cd..3bef19c 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ -import pygame, sys, time, random, colorsys, math +import pygame, sys, time, random, colorsys, math, pygame.display as Display from pygame.locals import * +from pygame.mixer import Sound from player import Player from background import Background from button import Button @@ -8,9 +9,9 @@ pygame.init() # set the display -pygame.display.set_caption('Flappuccino') -pygame.display.set_icon(Bean().sprite) -DISPLAY=pygame.display.set_mode((640,480),0,32) +Display.set_caption('Flappuccino') +Display.set_icon(Bean().sprite) +DISPLAY=Display.set_mode((640,480),0,32) player = Player() # get fonts font = pygame.font.Font('data/fonts/font.otf', 100) @@ -25,40 +26,32 @@ title_bg.fill((255, 30.599999999999998, 0.0), special_flags=pygame.BLEND_ADD) shadow = pygame.image.load('data/gfx/shadow.png') # get sounds -flapfx = pygame.mixer.Sound("data/sfx/flap.wav") -upgradefx = pygame.mixer.Sound("data/sfx/upgrade.wav") -beanfx = pygame.mixer.Sound("data/sfx/bean.wav") -deadfx = pygame.mixer.Sound("data/sfx/dead.wav") +flapfx = Sound("data/sfx/flap.wav") +upgradefx = Sound("data/sfx/upgrade.wav") +beanfx = Sound("data/sfx/bean.wav") +deadfx = Sound("data/sfx/dead.wav") +indicators = ['data/gfx/flap_indicator.png', 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] # colors WHITE=(255,255,255) # constant def start(): - global height, beanMultiplier, beans, buttons, last_time, clicked, jump, dt, mouseX, mouseY + global beanMultiplier, beans, buttons, last_time, clicked, jump, dt, mouseX, mouseY last_time = time.time() clicked = jump = False - height = dt = 0 + dt = 0 beanMultiplier = 5 beans = [] buttons = [] mouseX,mouseY = pygame.mouse.get_pos() player.reset() # adding three buttons - for _ in range(3): - buttons.append(Button()) - # now simply loading images based off of indexes in the list - buttons[0].set_indicator('data/gfx/flap_indicator.png') - buttons[0].set_price(5) - buttons[1].set_indicator('data/gfx/speed_indicator.png') - buttons[1].set_price(5) - buttons[2].set_indicator('data/gfx/beanup_indicator.png') + for i in range(3): + buttons.append(Button(i, indicators[i])) buttons[2].set_price(30) # getting 5 beans - for _ in range(5): - beans.append(Bean()) - # now looping through the beans list - for bean in beans: - bean.position.xy = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()), beans.index(bean)*-200 - player.position.y - pygame.mixer.Sound.play(flapfx) + for i in range(5): + beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()) ,i*-200 - player.position.y)) + Sound.play(flapfx) def funcOne(toggle = True): global dt, last_time, mouseX, mouseY, clicked, keys, jump @@ -86,10 +79,7 @@ def eventHandler(): sys.exit() def main(): - global player, clicked, jump, height, mouseY, dt, mouseX, keys, beanMultiplier, beans, buttons - # variables - rotOffset = -5 - # creating a new object player + global clicked, jump, mouseY, dt, mouseX, keys, beanMultiplier, beans, buttons start() # creating a list of backgrounds, with each index being an object bg = [Background(), Background(), Background()] @@ -105,19 +95,19 @@ def main(): startMessage = font_small.render("POLYMARS", True, (171, 145, 123)) DISPLAY.blit(startMessage, (DISPLAY.get_width()/2 - startMessage.get_width()/2, DISPLAY.get_height()/2 - startMessage.get_height()/2)) # update display - pygame.display.update() + Display.update() # wait for 10 seconds pygame.time.delay(10) titleScreen = True # title screen - pygame.mixer.Sound.play(flapfx) + Sound.play(flapfx) while titleScreen: funcOne() # so the user clicked, and by any change the mouse's position was on the buttons if (clicked and checkCollisions(mouseX, mouseY, 3, 3, DISPLAY.get_width()/2 - retry_button.get_width()/2, 288, retry_button.get_width(), retry_button.get_height())): clicked = False - pygame.mixer.Sound.play(upgradefx) + Sound.play(upgradefx) titleScreen = False DISPLAY.fill(WHITE) @@ -128,7 +118,7 @@ def main(): startMessage = font_small.render("START", True, (0, 0, 0)) DISPLAY.blit(startMessage, (DISPLAY.get_width()/2 - startMessage.get_width()/2, 292)) - pygame.display.update() + Display.update() pygame.time.delay(10) # the main game loop @@ -143,24 +133,24 @@ def main(): DISPLAY.blit(o.sprite, (0, o.position)) color = colorsys.hsv_to_rgb(((player.position.y/50) % 100) / 100,0.5,0.5) - currentHeightMarker = font.render(str(height), True, (color[0]*255, color[1]*255, color[2]*255, 50 )) + currentHeightMarker = font.render(str(player.height), True, (color[0]*255, color[1]*255, color[2]*255, 50 )) DISPLAY.blit(currentHeightMarker, (DISPLAY.get_width()/2 - currentHeightMarker.get_width()/2, camOffset + round((player.position.y - startingHeight)/DISPLAY.get_height())*DISPLAY.get_height() + player.currentSprite.get_height() - 40)) for bean in beans: DISPLAY.blit(bean.sprite, (bean.position.x, bean.position.y + camOffset)) - DISPLAY.blit(pygame.transform.rotate(player.currentSprite, clamp(player.velocity.y, -10, 5)*rotOffset), (player.position.x,player.position.y + camOffset)) + DISPLAY.blit(pygame.transform.rotate(player.currentSprite, clamp(player.velocity.y, -10, 5)*player.rot_offset), (player.position.x,player.position.y + camOffset)) DISPLAY.blit(shop_bg, (0, 0)) pygame.draw.rect(DISPLAY,(81,48,20),(21,437,150*(player.health/100),25)) DISPLAY.blit(shop, (0, 0)) for button in buttons: - DISPLAY.blit(button.sprite, (220 + (buttons.index(button)*125), 393)) + DISPLAY.blit(button.sprite, (220 + (button.index*125), 393)) priceDisplay = font_small.render(str(button.price), True, (0,0,0)) - DISPLAY.blit(priceDisplay, (262 + (buttons.index(button)*125), 408)) + DISPLAY.blit(priceDisplay, (262 + (button.index*125), 408)) levelDisplay = font_20.render('Lvl. ' + str(button.level), True, (200,200,200)) - DISPLAY.blit(levelDisplay, (234 + (buttons.index(button)*125), 441)) - DISPLAY.blit(button.typeIndicatorSprite, (202 + (buttons.index(button)*125), 377)) + DISPLAY.blit(levelDisplay, (234 + (button.index*125), 441)) + DISPLAY.blit(button.typeIndicatorSprite, (202 + (button.index*125), 377)) beanCountDisplay = font_small.render(str(player.beanCount).zfill(7), True, (0,0,0)) DISPLAY.blit(beanCountDisplay, (72, 394)) if player.dead: @@ -168,27 +158,20 @@ def main(): deathMessage = font_small.render("RETRY", True, (0, 0, 0)) DISPLAY.blit(deathMessage, (24, 8)) - height = round(-(player.position.y - startingHeight)/DISPLAY.get_height()) + player.set_height(round(-(player.position.y - startingHeight)/DISPLAY.get_height())) player.position.x += player.velocity.x*dt - if player.position.x + player.currentSprite.get_size()[0] > 640: - player.velocity.x = -abs(player.velocity.x) - player.currentSprite = player.leftSprite - rotOffset = 5 - if player.position.x < 0: - player.velocity.x = abs(player.velocity.x) - player.currentSprite = player.rightSprite - rotOffset = -5 + if player.position.x < 0 or player.position.x + player.currentSprite.get_size()[0] > 640: + player.flip() if jump and not player.dead: player.velocity.y = -player.flapForce - pygame.mixer.Sound.play(flapfx) + Sound.play(flapfx) player.position.y += player.velocity.y*dt player.velocity.y = clamp(player.velocity.y + player.acceleration*dt, -99999999999, 50) player.health -= 0.2*dt if player.health <= 0 and not player.dead: - player.invert_death() - pygame.mixer.Sound.play(deadfx) + player.kill(deadfx) for bean in beans: @@ -196,29 +179,27 @@ def main(): bean.position.y -= DISPLAY.get_height()*2 bean.position.x = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()) if (checkCollisions(player.position.x, player.position.y, player.currentSprite.get_width(), player.currentSprite.get_height(), bean.position.x, bean.position.y, bean.sprite.get_width(), bean.sprite.get_height())): - pygame.mixer.Sound.play(beanfx) + Sound.play(beanfx) player.beanCount += 1 player.health = 100 bean.position.y -= DISPLAY.get_height() - random.randrange(0, 200) bean.position.x = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()) for button in buttons: - buttonX,buttonY = 220 + (buttons.index(button)*125), 393 - if clicked and not player.dead and checkCollisions(mouseX, mouseY, 3, 3, buttonX, buttonY, button.sprite.get_width(), button.sprite.get_height()): + if clicked and not player.dead and checkCollisions(mouseX, mouseY, 3, 3, button.position.x, button.position.y, button.sprite.get_width(), button.sprite.get_height()): if (player.beanCount >= button.price): - pygame.mixer.Sound.play(upgradefx) + Sound.play(upgradefx) button.level += 1 player.beanCount -= button.price button.price = round(button.price*2.5) - if (buttons.index(button) == 0): + if (button.index == 0): player.flapForce *= 1.5 - if (buttons.index(button) == 1): + if (button.index == 1): player.velocity.x *= 1.5 - if (buttons.index(button) == 2): + if (button.index == 2): beanMultiplier += 10 for _ in range(beanMultiplier): - beans.append(Bean()) - beans[-1].position.xy = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()), player.position.y - DISPLAY.get_height() - random.randrange(0, 200) + beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()), player.position.y - DISPLAY.get_height() - random.randrange(0, 200))) if player.dead and clicked and checkCollisions(mouseX, mouseY, 3, 3, 4, 4, retry_button.get_width(), retry_button.get_height()): start() @@ -227,7 +208,7 @@ def main(): bg[1].position = bg[0].position + DISPLAY.get_height() bg[2].position = bg[0].position - DISPLAY.get_height() - pygame.display.update() + Display.update() pygame.time.delay(10) if __name__ == "__main__": diff --git a/player.py b/player.py index 126b6f4..a0ba821 100644 --- a/player.py +++ b/player.py @@ -3,26 +3,35 @@ class Player: position = pygame.Vector2() velocity = pygame.Vector2() - dead = False - health = 100 - position.xy = 295, 100 - velocity.xy = 3, 0 - acceleration = 0.1 - flapForce = 3 - beanCount = 0 rightSprite = pygame.image.load('data/gfx/player.png') - currentSprite = rightSprite leftSprite = pygame.transform.flip(rightSprite, True, False) - def reset(self): + def __init__(self): + self.dead = False + self.health = 100 + self.height = 0 self.position.xy = 295, 100 self.velocity.xy = 3, 0 self.acceleration = 0.1 - self.currentSprite = self.rightSprite - self.dead = False - self.health = 100 - self.beanCount = 0 self.flapForce = 3 + self.beanCount = 0 + self.rot_offset = -5 + self.currentSprite = self.rightSprite + + def reset(self): + self.__init__() - def invert_death(self): - self.dead = not self.dead \ No newline at end of file + def kill(self, sound): + self.dead = True + pygame.mixer.Sound.play(sound) + + def set_height(self, new_height): + self.height = new_height + + def flip(self): + self.velocity.x *= -1 + self.rot_offset *= -1 + if self.currentSprite == self.rightSprite: + self.currentSprite = self.leftSprite + else: + self.currentSprite = self.rightSprite \ No newline at end of file From 601c338c909f00b4c6d72f8a0888ff8971565ab5 Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Sat, 5 Nov 2022 14:29:35 -0400 Subject: [PATCH 03/11] Made window resizable Made it to where the window can change sizes. Now need to make it to where the game changes size accordingly. --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index 3bef19c..7357372 100644 --- a/main.py +++ b/main.py @@ -11,7 +11,7 @@ # set the display Display.set_caption('Flappuccino') Display.set_icon(Bean().sprite) -DISPLAY=Display.set_mode((640,480),0,32) +DISPLAY=Display.set_mode((640,480),pygame.RESIZABLE | pygame.SCALED,32) player = Player() # get fonts font = pygame.font.Font('data/fonts/font.otf', 100) From 7458315d3bafe9f1adbd037729129901e64c3e7d Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Sat, 5 Nov 2022 21:34:04 -0400 Subject: [PATCH 04/11] No more negative height Now if the camera offset reaches 0, the screen will stop scrolling and kill the player if they are not already dead. Oh, and I changed the bean multiplier so purchasing the upgrade once or twice doesn't COMPLETELY make the game pointless. --- main.py | 55 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/main.py b/main.py index 7357372..6bace46 100644 --- a/main.py +++ b/main.py @@ -35,9 +35,10 @@ WHITE=(255,255,255) # constant def start(): - global beanMultiplier, beans, buttons, last_time, clicked, jump, dt, mouseX, mouseY + global beanMultiplier, beans, buttons, last_time, clicked, jump, dt, mouseX, mouseY, scroll last_time = time.time() clicked = jump = False + scroll = True dt = 0 beanMultiplier = 5 beans = [] @@ -55,13 +56,16 @@ def start(): def funcOne(toggle = True): global dt, last_time, mouseX, mouseY, clicked, keys, jump + # calculate the change in time (dt) dt = (time.time() - last_time) * 60 + # save the current time last_time = time.time() - # get the position of the mouse if(toggle): + # resetting clicked and jump flags to false + clicked = jump = False + # get the position of the mouse mouseX,mouseY = pygame.mouse.get_pos() # getting the keys pressed - clicked = jump = False keys = pygame.key.get_pressed() eventHandler() @@ -79,11 +83,11 @@ def eventHandler(): sys.exit() def main(): - global clicked, jump, mouseY, dt, mouseX, keys, beanMultiplier, beans, buttons + global clicked, jump, mouseY, dt, mouseX, keys, beanMultiplier, beans, buttons, scroll start() # creating a list of backgrounds, with each index being an object bg = [Background(), Background(), Background()] - # some variables that we need + # startingHeight = 100 (the initial y position of the player) startingHeight = player.position.y splashScreenTimer = 0 #splash screen @@ -107,8 +111,8 @@ def main(): # so the user clicked, and by any change the mouse's position was on the buttons if (clicked and checkCollisions(mouseX, mouseY, 3, 3, DISPLAY.get_width()/2 - retry_button.get_width()/2, 288, retry_button.get_width(), retry_button.get_height())): clicked = False - Sound.play(upgradefx) titleScreen = False + Sound.play(upgradefx) DISPLAY.fill(WHITE) DISPLAY.blit(title_bg, (0,0)) @@ -125,17 +129,22 @@ def main(): while True: funcOne() - camOffset = -player.position.y + DISPLAY.get_height()/2 - player.currentSprite.get_size()[1]/2 + camOffset = -player.position.y + (DISPLAY.get_height() - player.currentSprite.get_size()[1])/2 + if(camOffset <= 0): + if(not player.dead): + player.kill(deadfx) + scroll = False + camOffset = 0 DISPLAY.fill(WHITE) for o in bg: o.setSprite(((player.position.y/50) % 100) / 100) DISPLAY.blit(o.sprite, (0, o.position)) - color = colorsys.hsv_to_rgb(((player.position.y/50) % 100) / 100,0.5,0.5) currentHeightMarker = font.render(str(player.height), True, (color[0]*255, color[1]*255, color[2]*255, 50 )) DISPLAY.blit(currentHeightMarker, (DISPLAY.get_width()/2 - currentHeightMarker.get_width()/2, camOffset + round((player.position.y - startingHeight)/DISPLAY.get_height())*DISPLAY.get_height() + player.currentSprite.get_height() - 40)) + for bean in beans: DISPLAY.blit(bean.sprite, (bean.position.x, bean.position.y + camOffset)) @@ -158,21 +167,21 @@ def main(): deathMessage = font_small.render("RETRY", True, (0, 0, 0)) DISPLAY.blit(deathMessage, (24, 8)) - player.set_height(round(-(player.position.y - startingHeight)/DISPLAY.get_height())) - - player.position.x += player.velocity.x*dt - if player.position.x < 0 or player.position.x + player.currentSprite.get_size()[0] > 640: - player.flip() - if jump and not player.dead: - player.velocity.y = -player.flapForce - Sound.play(flapfx) - player.position.y += player.velocity.y*dt - player.velocity.y = clamp(player.velocity.y + player.acceleration*dt, -99999999999, 50) + if(scroll): + player.set_height(round(-(player.position.y - startingHeight)/DISPLAY.get_height())) + player.position.x += player.velocity.x*dt + if player.position.x < 0 or player.position.x + player.currentSprite.get_size()[0] > 640: + player.flip() + if jump and not player.dead: + player.velocity.y = -player.flapForce + Sound.play(flapfx) + player.position.y += player.velocity.y*dt + player.velocity.y = clamp(player.velocity.y + player.acceleration*dt, -99999999999, 50) - player.health -= 0.2*dt - if player.health <= 0 and not player.dead: - player.kill(deadfx) - + if not player.dead: + player.health -= 0.2*dt + if player.health <= 0: + player.kill(deadfx) for bean in beans: if bean.position.y + camOffset + 90 > DISPLAY.get_height(): @@ -197,7 +206,7 @@ def main(): if (button.index == 1): player.velocity.x *= 1.5 if (button.index == 2): - beanMultiplier += 10 + beanMultiplier += 5 for _ in range(beanMultiplier): beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()), player.position.y - DISPLAY.get_height() - random.randrange(0, 200))) From 7ee77152144042e43af8622fda94135fbdc5a386 Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Tue, 22 Nov 2022 00:17:23 -0500 Subject: [PATCH 05/11] Changed placement of certain variables --- main.py | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/main.py b/main.py index 6bace46..d17092f 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,8 @@ import pygame, sys, time, random, colorsys, math, pygame.display as Display from pygame.locals import * from pygame.mixer import Sound +from pygame.font import Font +from pygame.image import load as Image from player import Player from background import Background from button import Button @@ -11,31 +13,14 @@ # set the display Display.set_caption('Flappuccino') Display.set_icon(Bean().sprite) -DISPLAY=Display.set_mode((640,480),pygame.RESIZABLE | pygame.SCALED,32) +DISPLAY = Display.set_mode((640,480),pygame.RESIZABLE | pygame.SCALED,32) player = Player() -# get fonts -font = pygame.font.Font('data/fonts/font.otf', 100) -font_small = pygame.font.Font('data/fonts/font.otf', 32) -font_20 = pygame.font.Font('data/fonts/font.otf', 20) -# get some images -shop = pygame.image.load('data/gfx/shop.png') -shop_bg = pygame.image.load('data/gfx/shop_bg.png') -retry_button = pygame.image.load('data/gfx/retry_button.png') -logo = pygame.image.load('data/gfx/logo.png') -title_bg = pygame.image.load('data/gfx/bg.png') -title_bg.fill((255, 30.599999999999998, 0.0), special_flags=pygame.BLEND_ADD) -shadow = pygame.image.load('data/gfx/shadow.png') # get sounds flapfx = Sound("data/sfx/flap.wav") -upgradefx = Sound("data/sfx/upgrade.wav") -beanfx = Sound("data/sfx/bean.wav") -deadfx = Sound("data/sfx/dead.wav") -indicators = ['data/gfx/flap_indicator.png', 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] -# colors -WHITE=(255,255,255) # constant def start(): global beanMultiplier, beans, buttons, last_time, clicked, jump, dt, mouseX, mouseY, scroll + indicators = ['data/gfx/flap_indicator.png', 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] last_time = time.time() clicked = jump = False scroll = True @@ -85,6 +70,23 @@ def eventHandler(): def main(): global clicked, jump, mouseY, dt, mouseX, keys, beanMultiplier, beans, buttons, scroll start() + # get fonts + font = Font('data/fonts/font.otf', 100) + font_small = Font('data/fonts/font.otf', 32) + font_20 = Font('data/fonts/font.otf', 20) + # get some images + shop = Image('data/gfx/shop.png') + shop_bg = Image('data/gfx/shop_bg.png') + retry_button = Image('data/gfx/retry_button.png') + logo = Image('data/gfx/logo.png') + title_bg = Image('data/gfx/bg.png') + title_bg.fill((255, 30.599999999999998, 0.0), special_flags=pygame.BLEND_ADD) + shadow = Image('data/gfx/shadow.png') + upgradefx = Sound("data/sfx/upgrade.wav") + beanfx = Sound("data/sfx/bean.wav") + deadfx = Sound("data/sfx/dead.wav") + # colors + WHITE=(255,255,255) # constant # creating a list of backgrounds, with each index being an object bg = [Background(), Background(), Background()] # startingHeight = 100 (the initial y position of the player) @@ -157,7 +159,7 @@ def main(): DISPLAY.blit(button.sprite, (220 + (button.index*125), 393)) priceDisplay = font_small.render(str(button.price), True, (0,0,0)) DISPLAY.blit(priceDisplay, (262 + (button.index*125), 408)) - levelDisplay = font_20.render('Lvl. ' + str(button.level), True, (200,200,200)) + levelDisplay = font_20.render(f'Lvl. {button.level}', True, (200,200,200)) DISPLAY.blit(levelDisplay, (234 + (button.index*125), 441)) DISPLAY.blit(button.typeIndicatorSprite, (202 + (button.index*125), 377)) beanCountDisplay = font_small.render(str(player.beanCount).zfill(7), True, (0,0,0)) From 01308833c7595773ffdb4a521d12da26a7836498 Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Sat, 21 Jan 2023 20:16:55 -0500 Subject: [PATCH 06/11] Updating importing and naming conventions --- background.py | 8 ++-- button.py | 8 ++-- main.py | 121 ++++++++++++++++++++++++++------------------------ player.py | 16 +++---- utils.py | 12 ++--- 5 files changed, 87 insertions(+), 78 deletions(-) diff --git a/background.py b/background.py index 765aeaa..c3f7318 100644 --- a/background.py +++ b/background.py @@ -1,12 +1,14 @@ -import pygame, colorsys +import pygame +import colorsys + class Background: def __init__(self): self.sprite = pygame.image.load('data/gfx/bg.png') self.position = 0 - self.uncoloredSprite = pygame.image.load('data/gfx/bg.png') + self.uncolored_sprite = pygame.image.load('data/gfx/bg.png') def setSprite(self, tint): - copy = self.uncoloredSprite.copy() + copy = self.uncolored_sprite.copy() color = colorsys.hsv_to_rgb(tint,1,1) copy.fill((color[0]*255, color[1]*255, color[2]*255), special_flags=pygame.BLEND_ADD) self.sprite = copy \ No newline at end of file diff --git a/button.py b/button.py index 73cde0d..465ad96 100644 --- a/button.py +++ b/button.py @@ -2,15 +2,15 @@ from pygame.image import load class Button: sprite = load('data/gfx/button.png') - typeIndicatorSprite = load('data/gfx/null_indicator.png') + type_indicator_sprite = load('data/gfx/null_indicator.png') def __init__(self, index, indicator): self.price = 5 self.level = 1 self.index = index - self.typeIndicatorSprite = load(indicator) + self.type_indicator_sprite = load(indicator) self.position = pygame.Vector2() self.position.xy = 220 + (self.index*125), 393 - def set_price(self, newPrice): - self.price = newPrice \ No newline at end of file + def set_price(self, new_price): + self.price = new_price \ No newline at end of file diff --git a/main.py b/main.py index d17092f..3ca833c 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,10 @@ -import pygame, sys, time, random, colorsys, math, pygame.display as Display +import pygame +import sys +import time +import random +import colorsys +import math +import pygame.display as Display from pygame.locals import * from pygame.mixer import Sound from pygame.font import Font @@ -19,16 +25,17 @@ flapfx = Sound("data/sfx/flap.wav") def start(): - global beanMultiplier, beans, buttons, last_time, clicked, jump, dt, mouseX, mouseY, scroll + global bean_multiplier, beans, buttons, last_time, clicked, jump, dt, mouse_x, mouse_y, scroll indicators = ['data/gfx/flap_indicator.png', 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] last_time = time.time() - clicked = jump = False + clicked = False + jump = False scroll = True dt = 0 - beanMultiplier = 5 + bean_multiplier = 5 beans = [] buttons = [] - mouseX,mouseY = pygame.mouse.get_pos() + mouse_x, mouse_y = pygame.mouse.get_pos() player.reset() # adding three buttons for i in range(3): @@ -39,8 +46,8 @@ def start(): beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()) ,i*-200 - player.position.y)) Sound.play(flapfx) -def funcOne(toggle = True): - global dt, last_time, mouseX, mouseY, clicked, keys, jump +def func_one(toggle = True): + global dt, last_time, mouse_x, mouse_y, clicked, keys, jump # calculate the change in time (dt) dt = (time.time() - last_time) * 60 # save the current time @@ -49,26 +56,26 @@ def funcOne(toggle = True): # resetting clicked and jump flags to false clicked = jump = False # get the position of the mouse - mouseX,mouseY = pygame.mouse.get_pos() + mouse_x, mouse_y = pygame.mouse.get_pos() # getting the keys pressed keys = pygame.key.get_pressed() - eventHandler() + event_handler() -def eventHandler(): +def event_handler(): global jump, clicked for event in pygame.event.get(): if event.type==pygame.KEYDOWN and event.key==K_SPACE: jump = True if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: clicked = True - if clicked and mouseY < DISPLAY.get_height() - 90: + if clicked and mouse_y < DISPLAY.get_height() - 90: jump = True if event.type==QUIT: pygame.quit() sys.exit() def main(): - global clicked, jump, mouseY, dt, mouseX, keys, beanMultiplier, beans, buttons, scroll + global clicked, jump, mouse_y, dt, mouse_x, keys, bean_multiplier, beans, buttons, scroll start() # get fonts font = Font('data/fonts/font.otf', 100) @@ -90,30 +97,30 @@ def main(): # creating a list of backgrounds, with each index being an object bg = [Background(), Background(), Background()] # startingHeight = 100 (the initial y position of the player) - startingHeight = player.position.y - splashScreenTimer = 0 + starting_height = player.position.y + splash_screen_timer = 0 #splash screen - while splashScreenTimer < 100: - funcOne(False) - splashScreenTimer += dt + while splash_screen_timer < 100: + func_one(False) + splash_screen_timer += dt DISPLAY.fill((231, 205, 183)) # fill the start message on the top of the game - startMessage = font_small.render("POLYMARS", True, (171, 145, 123)) - DISPLAY.blit(startMessage, (DISPLAY.get_width()/2 - startMessage.get_width()/2, DISPLAY.get_height()/2 - startMessage.get_height()/2)) + start_message = font_small.render("POLYMARS", True, (171, 145, 123)) + DISPLAY.blit(start_message, (DISPLAY.get_width()/2 - start_message.get_width()/2, DISPLAY.get_height()/2 - start_message.get_height()/2)) # update display Display.update() # wait for 10 seconds pygame.time.delay(10) - titleScreen = True + title_screen = True # title screen Sound.play(flapfx) - while titleScreen: - funcOne() + while title_screen: + func_one() # so the user clicked, and by any change the mouse's position was on the buttons - if (clicked and checkCollisions(mouseX, mouseY, 3, 3, DISPLAY.get_width()/2 - retry_button.get_width()/2, 288, retry_button.get_width(), retry_button.get_height())): + if (clicked and check_collisions(mouse_x, mouse_y, 3, 3, DISPLAY.get_width()/2 - retry_button.get_width()/2, 288, retry_button.get_width(), retry_button.get_height())): clicked = False - titleScreen = False + title_screen = False Sound.play(upgradefx) DISPLAY.fill(WHITE) @@ -121,61 +128,61 @@ def main(): DISPLAY.blit(shadow, (0,0)) DISPLAY.blit(logo, (DISPLAY.get_width()/2 - logo.get_width()/2, DISPLAY.get_height()/2 - logo.get_height()/2 + math.sin(time.time()*5)*5 - 25)) DISPLAY.blit(retry_button, (DISPLAY.get_width()/2 - retry_button.get_width()/2, 288)) - startMessage = font_small.render("START", True, (0, 0, 0)) - DISPLAY.blit(startMessage, (DISPLAY.get_width()/2 - startMessage.get_width()/2, 292)) + start_message = font_small.render("START", True, (0, 0, 0)) + DISPLAY.blit(start_message, (DISPLAY.get_width()/2 - start_message.get_width()/2, 292)) Display.update() pygame.time.delay(10) # the main game loop while True: - funcOne() + func_one() - camOffset = -player.position.y + (DISPLAY.get_height() - player.currentSprite.get_size()[1])/2 - if(camOffset <= 0): + cam_offset = -player.position.y + (DISPLAY.get_height() - player.current_sprite.get_size()[1])/2 + if(cam_offset <= 0): if(not player.dead): player.kill(deadfx) scroll = False - camOffset = 0 + cam_offset = 0 DISPLAY.fill(WHITE) for o in bg: o.setSprite(((player.position.y/50) % 100) / 100) DISPLAY.blit(o.sprite, (0, o.position)) color = colorsys.hsv_to_rgb(((player.position.y/50) % 100) / 100,0.5,0.5) - currentHeightMarker = font.render(str(player.height), True, (color[0]*255, color[1]*255, color[2]*255, 50 )) - DISPLAY.blit(currentHeightMarker, (DISPLAY.get_width()/2 - currentHeightMarker.get_width()/2, camOffset + round((player.position.y - startingHeight)/DISPLAY.get_height())*DISPLAY.get_height() + player.currentSprite.get_height() - 40)) + current_height_marker = font.render(str(player.height), True, (color[0]*255, color[1]*255, color[2]*255, 50 )) + DISPLAY.blit(current_height_marker, (DISPLAY.get_width()/2 - current_height_marker.get_width()/2, cam_offset + round((player.position.y - starting_height)/DISPLAY.get_height())*DISPLAY.get_height() + player.current_sprite.get_height() - 40)) for bean in beans: - DISPLAY.blit(bean.sprite, (bean.position.x, bean.position.y + camOffset)) + DISPLAY.blit(bean.sprite, (bean.position.x, bean.position.y + cam_offset)) - DISPLAY.blit(pygame.transform.rotate(player.currentSprite, clamp(player.velocity.y, -10, 5)*player.rot_offset), (player.position.x,player.position.y + camOffset)) + DISPLAY.blit(pygame.transform.rotate(player.current_sprite, clamp(player.velocity.y, -10, 5)*player.rot_offset), (player.position.x,player.position.y + cam_offset)) DISPLAY.blit(shop_bg, (0, 0)) pygame.draw.rect(DISPLAY,(81,48,20),(21,437,150*(player.health/100),25)) DISPLAY.blit(shop, (0, 0)) for button in buttons: DISPLAY.blit(button.sprite, (220 + (button.index*125), 393)) - priceDisplay = font_small.render(str(button.price), True, (0,0,0)) - DISPLAY.blit(priceDisplay, (262 + (button.index*125), 408)) - levelDisplay = font_20.render(f'Lvl. {button.level}', True, (200,200,200)) - DISPLAY.blit(levelDisplay, (234 + (button.index*125), 441)) - DISPLAY.blit(button.typeIndicatorSprite, (202 + (button.index*125), 377)) - beanCountDisplay = font_small.render(str(player.beanCount).zfill(7), True, (0,0,0)) - DISPLAY.blit(beanCountDisplay, (72, 394)) + price_display = font_small.render(str(button.price), True, (0,0,0)) + DISPLAY.blit(price_display, (262 + (button.index*125), 408)) + level_display = font_20.render(f'Lvl. {button.level}', True, (200,200,200)) + DISPLAY.blit(level_display, (234 + (button.index*125), 441)) + DISPLAY.blit(button.type_indicator_sprite, (202 + (button.index*125), 377)) + bean_count_display = font_small.render(str(player.bean_count).zfill(7), True, (0,0,0)) + DISPLAY.blit(bean_count_display, (72, 394)) if player.dead: DISPLAY.blit(retry_button, (4, 4)) - deathMessage = font_small.render("RETRY", True, (0, 0, 0)) - DISPLAY.blit(deathMessage, (24, 8)) + death_message = font_small.render("RETRY", True, (0, 0, 0)) + DISPLAY.blit(death_message, (24, 8)) if(scroll): - player.set_height(round(-(player.position.y - startingHeight)/DISPLAY.get_height())) + player.set_height(round(-(player.position.y - starting_height)/DISPLAY.get_height())) player.position.x += player.velocity.x*dt - if player.position.x < 0 or player.position.x + player.currentSprite.get_size()[0] > 640: + if player.position.x < 0 or player.position.x + player.current_sprite.get_size()[0] > 640: player.flip() if jump and not player.dead: - player.velocity.y = -player.flapForce + player.velocity.y = -player.flap_force Sound.play(flapfx) player.position.y += player.velocity.y*dt player.velocity.y = clamp(player.velocity.y + player.acceleration*dt, -99999999999, 50) @@ -186,36 +193,36 @@ def main(): player.kill(deadfx) for bean in beans: - if bean.position.y + camOffset + 90 > DISPLAY.get_height(): + if bean.position.y + cam_offset + 90 > DISPLAY.get_height(): bean.position.y -= DISPLAY.get_height()*2 bean.position.x = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()) - if (checkCollisions(player.position.x, player.position.y, player.currentSprite.get_width(), player.currentSprite.get_height(), bean.position.x, bean.position.y, bean.sprite.get_width(), bean.sprite.get_height())): + if (check_collisions(player.position.x, player.position.y, player.current_sprite.get_width(), player.current_sprite.get_height(), bean.position.x, bean.position.y, bean.sprite.get_width(), bean.sprite.get_height())): Sound.play(beanfx) - player.beanCount += 1 + player.bean_count += 1 player.health = 100 bean.position.y -= DISPLAY.get_height() - random.randrange(0, 200) bean.position.x = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()) for button in buttons: - if clicked and not player.dead and checkCollisions(mouseX, mouseY, 3, 3, button.position.x, button.position.y, button.sprite.get_width(), button.sprite.get_height()): - if (player.beanCount >= button.price): + if clicked and not player.dead and check_collisions(mouse_x, mouse_y, 3, 3, button.position.x, button.position.y, button.sprite.get_width(), button.sprite.get_height()): + if (player.bean_count >= button.price): Sound.play(upgradefx) button.level += 1 - player.beanCount -= button.price + player.bean_count -= button.price button.price = round(button.price*2.5) if (button.index == 0): - player.flapForce *= 1.5 + player.flap_force *= 1.5 if (button.index == 1): player.velocity.x *= 1.5 if (button.index == 2): - beanMultiplier += 5 - for _ in range(beanMultiplier): + bean_multiplier += 5 + for _ in range(bean_multiplier): beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()), player.position.y - DISPLAY.get_height() - random.randrange(0, 200))) - if player.dead and clicked and checkCollisions(mouseX, mouseY, 3, 3, 4, 4, retry_button.get_width(), retry_button.get_height()): + if player.dead and clicked and check_collisions(mouse_x, mouse_y, 3, 3, 4, 4, retry_button.get_width(), retry_button.get_height()): start() - bg[0].position = camOffset + round(player.position.y/DISPLAY.get_height())*DISPLAY.get_height() + bg[0].position = cam_offset + round(player.position.y/DISPLAY.get_height())*DISPLAY.get_height() bg[1].position = bg[0].position + DISPLAY.get_height() bg[2].position = bg[0].position - DISPLAY.get_height() diff --git a/player.py b/player.py index a0ba821..b0265c2 100644 --- a/player.py +++ b/player.py @@ -3,8 +3,8 @@ class Player: position = pygame.Vector2() velocity = pygame.Vector2() - rightSprite = pygame.image.load('data/gfx/player.png') - leftSprite = pygame.transform.flip(rightSprite, True, False) + right_sprite = pygame.image.load('data/gfx/player.png') + left_sprite = pygame.transform.flip(right_sprite, True, False) def __init__(self): self.dead = False @@ -13,10 +13,10 @@ def __init__(self): self.position.xy = 295, 100 self.velocity.xy = 3, 0 self.acceleration = 0.1 - self.flapForce = 3 - self.beanCount = 0 + self.flap_force = 3 + self.bean_count = 0 self.rot_offset = -5 - self.currentSprite = self.rightSprite + self.current_sprite = self.right_sprite def reset(self): self.__init__() @@ -31,7 +31,7 @@ def set_height(self, new_height): def flip(self): self.velocity.x *= -1 self.rot_offset *= -1 - if self.currentSprite == self.rightSprite: - self.currentSprite = self.leftSprite + if self.current_sprite == self.right_sprite: + self.current_sprite = self.left_sprite else: - self.currentSprite = self.rightSprite \ No newline at end of file + self.current_sprite = self.right_sprite \ No newline at end of file diff --git a/utils.py b/utils.py index dad03a7..2913e5f 100644 --- a/utils.py +++ b/utils.py @@ -1,9 +1,9 @@ -def clamp(value, min, max): - if value < min: - return min - if value > max: - return max +def clamp(value, min_, max_): + if value < min_: + return min_ + if value > max_: + return max_ return value -def checkCollisions(a_x, a_y, a_width, a_height, b_x, b_y, b_width, b_height): +def check_collisions(a_x, a_y, a_width, a_height, b_x, b_y, b_width, b_height): return (a_x + a_width > b_x) and (a_x < b_x + b_width) and (a_y + a_height > b_y) and (a_y < b_y + b_height) From 29e42105f9cddc499419411cd437d5ebeeb45b53 Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Sat, 21 Jan 2023 20:35:24 -0500 Subject: [PATCH 07/11] Minor changes --- background.py | 5 +++-- bean.py | 3 ++- button.py | 5 +++-- main.py | 21 +++++++++++---------- player.py | 8 ++++---- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/background.py b/background.py index c3f7318..36ef605 100644 --- a/background.py +++ b/background.py @@ -2,12 +2,13 @@ import colorsys class Background: + uncolored_sprite = pygame.image.load('data/gfx/bg.png') + def __init__(self): self.sprite = pygame.image.load('data/gfx/bg.png') self.position = 0 - self.uncolored_sprite = pygame.image.load('data/gfx/bg.png') - def setSprite(self, tint): + def set_sprite(self, tint: float) -> None: copy = self.uncolored_sprite.copy() color = colorsys.hsv_to_rgb(tint,1,1) copy.fill((color[0]*255, color[1]*255, color[2]*255), special_flags=pygame.BLEND_ADD) diff --git a/bean.py b/bean.py index 5cda771..202e03a 100644 --- a/bean.py +++ b/bean.py @@ -1,7 +1,8 @@ import pygame + class Bean: sprite = pygame.image.load('data/gfx/bean.png') - def __init__(self, x_pos = 0, y_pos = 0): + def __init__(self, x_pos: float = 0, y_pos: float = 0): self.position = pygame.Vector2() self.position.xy = x_pos, y_pos \ No newline at end of file diff --git a/button.py b/button.py index 465ad96..d628d32 100644 --- a/button.py +++ b/button.py @@ -1,10 +1,11 @@ import pygame from pygame.image import load + class Button: sprite = load('data/gfx/button.png') type_indicator_sprite = load('data/gfx/null_indicator.png') - def __init__(self, index, indicator): + def __init__(self, index: int, indicator: str) -> None: self.price = 5 self.level = 1 self.index = index @@ -12,5 +13,5 @@ def __init__(self, index, indicator): self.position = pygame.Vector2() self.position.xy = 220 + (self.index*125), 393 - def set_price(self, new_price): + def set_price(self, new_price: int) -> None: self.price = new_price \ No newline at end of file diff --git a/main.py b/main.py index 3ca833c..c2c0dfc 100644 --- a/main.py +++ b/main.py @@ -18,35 +18,35 @@ pygame.init() # set the display Display.set_caption('Flappuccino') -Display.set_icon(Bean().sprite) +Display.set_icon(Bean.sprite) DISPLAY = Display.set_mode((640,480),pygame.RESIZABLE | pygame.SCALED,32) player = Player() # get sounds flapfx = Sound("data/sfx/flap.wav") +indicators = ['data/gfx/flap_indicator.png', 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] def start(): global bean_multiplier, beans, buttons, last_time, clicked, jump, dt, mouse_x, mouse_y, scroll - indicators = ['data/gfx/flap_indicator.png', 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] last_time = time.time() clicked = False jump = False scroll = True dt = 0 bean_multiplier = 5 - beans = [] - buttons = [] + beans = list[Bean] + buttons = list[Button] mouse_x, mouse_y = pygame.mouse.get_pos() player.reset() # adding three buttons for i in range(3): buttons.append(Button(i, indicators[i])) - buttons[2].set_price(30) + buttons[2].set_price(30) # getting 5 beans for i in range(5): beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()) ,i*-200 - player.position.y)) Sound.play(flapfx) -def func_one(toggle = True): +def func_one(toggle: bool = True) -> None: global dt, last_time, mouse_x, mouse_y, clicked, keys, jump # calculate the change in time (dt) dt = (time.time() - last_time) * 60 @@ -54,14 +54,15 @@ def func_one(toggle = True): last_time = time.time() if(toggle): # resetting clicked and jump flags to false - clicked = jump = False + clicked = False + jump = False # get the position of the mouse mouse_x, mouse_y = pygame.mouse.get_pos() # getting the keys pressed keys = pygame.key.get_pressed() event_handler() -def event_handler(): +def event_handler() -> None: global jump, clicked for event in pygame.event.get(): if event.type==pygame.KEYDOWN and event.key==K_SPACE: @@ -74,8 +75,8 @@ def event_handler(): pygame.quit() sys.exit() -def main(): - global clicked, jump, mouse_y, dt, mouse_x, keys, bean_multiplier, beans, buttons, scroll +def main() -> None: + global clicked, bean_multiplier, beans, scroll start() # get fonts font = Font('data/fonts/font.otf', 100) diff --git a/player.py b/player.py index b0265c2..d950a93 100644 --- a/player.py +++ b/player.py @@ -18,17 +18,17 @@ def __init__(self): self.rot_offset = -5 self.current_sprite = self.right_sprite - def reset(self): + def reset(self) -> None: self.__init__() - def kill(self, sound): + def kill(self, sound: str) -> None: self.dead = True pygame.mixer.Sound.play(sound) - def set_height(self, new_height): + def set_height(self, new_height: float) -> None: self.height = new_height - def flip(self): + def flip(self) -> None: self.velocity.x *= -1 self.rot_offset *= -1 if self.current_sprite == self.right_sprite: From 68f91819c201411d32e98a5bcc5851c27b9334cf Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Sat, 21 Jan 2023 20:58:07 -0500 Subject: [PATCH 08/11] Moving stuff from main() and adding spaces --- main.py | 60 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/main.py b/main.py index c2c0dfc..599996a 100644 --- a/main.py +++ b/main.py @@ -15,16 +15,40 @@ from bean import Bean from utils import * +# initialize the game pygame.init() + # set the display Display.set_caption('Flappuccino') Display.set_icon(Bean.sprite) -DISPLAY = Display.set_mode((640,480),pygame.RESIZABLE | pygame.SCALED,32) +DISPLAY = Display.set_mode((640, 480), pygame.RESIZABLE | pygame.SCALED,32) + player = Player() -# get sounds -flapfx = Sound("data/sfx/flap.wav") + +# get fonts +font = Font('data/fonts/font.otf', 100) +font_small = Font('data/fonts/font.otf', 32) +font_20 = Font('data/fonts/font.otf', 20) + +# get some images +shop = Image('data/gfx/shop.png') +shop_bg = Image('data/gfx/shop_bg.png') +retry_button = Image('data/gfx/retry_button.png') +logo = Image('data/gfx/logo.png') +title_bg = Image('data/gfx/bg.png') +title_bg.fill((255, 30.599999999999998, 0.0), special_flags=pygame.BLEND_ADD) +shadow = Image('data/gfx/shadow.png') indicators = ['data/gfx/flap_indicator.png', 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] +# get some sounds +upgradefx = Sound("data/sfx/upgrade.wav") +beanfx = Sound("data/sfx/bean.wav") +deadfx = Sound("data/sfx/dead.wav") +flapfx = Sound("data/sfx/flap.wav") + +# colors +WHITE=(255,255,255) # constant + def start(): global bean_multiplier, beans, buttons, last_time, clicked, jump, dt, mouse_x, mouse_y, scroll last_time = time.time() @@ -43,7 +67,7 @@ def start(): buttons[2].set_price(30) # getting 5 beans for i in range(5): - beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()) ,i*-200 - player.position.y)) + beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()) ,i * -200 - player.position.y)) Sound.play(flapfx) def func_one(toggle: bool = True) -> None: @@ -65,7 +89,7 @@ def func_one(toggle: bool = True) -> None: def event_handler() -> None: global jump, clicked for event in pygame.event.get(): - if event.type==pygame.KEYDOWN and event.key==K_SPACE: + if event.type==pygame.KEYDOWN and event.key == K_SPACE: jump = True if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: clicked = True @@ -78,29 +102,14 @@ def event_handler() -> None: def main() -> None: global clicked, bean_multiplier, beans, scroll start() - # get fonts - font = Font('data/fonts/font.otf', 100) - font_small = Font('data/fonts/font.otf', 32) - font_20 = Font('data/fonts/font.otf', 20) - # get some images - shop = Image('data/gfx/shop.png') - shop_bg = Image('data/gfx/shop_bg.png') - retry_button = Image('data/gfx/retry_button.png') - logo = Image('data/gfx/logo.png') - title_bg = Image('data/gfx/bg.png') - title_bg.fill((255, 30.599999999999998, 0.0), special_flags=pygame.BLEND_ADD) - shadow = Image('data/gfx/shadow.png') - upgradefx = Sound("data/sfx/upgrade.wav") - beanfx = Sound("data/sfx/bean.wav") - deadfx = Sound("data/sfx/dead.wav") - # colors - WHITE=(255,255,255) # constant + # creating a list of backgrounds, with each index being an object bg = [Background(), Background(), Background()] # startingHeight = 100 (the initial y position of the player) starting_height = player.position.y + + # splash screen splash_screen_timer = 0 - #splash screen while splash_screen_timer < 100: func_one(False) splash_screen_timer += dt @@ -113,8 +122,8 @@ def main() -> None: # wait for 10 seconds pygame.time.delay(10) - title_screen = True # title screen + title_screen = True Sound.play(flapfx) while title_screen: func_one() @@ -154,7 +163,6 @@ def main() -> None: current_height_marker = font.render(str(player.height), True, (color[0]*255, color[1]*255, color[2]*255, 50 )) DISPLAY.blit(current_height_marker, (DISPLAY.get_width()/2 - current_height_marker.get_width()/2, cam_offset + round((player.position.y - starting_height)/DISPLAY.get_height())*DISPLAY.get_height() + player.current_sprite.get_height() - 40)) - for bean in beans: DISPLAY.blit(bean.sprite, (bean.position.x, bean.position.y + cam_offset)) @@ -170,8 +178,10 @@ def main() -> None: level_display = font_20.render(f'Lvl. {button.level}', True, (200,200,200)) DISPLAY.blit(level_display, (234 + (button.index*125), 441)) DISPLAY.blit(button.type_indicator_sprite, (202 + (button.index*125), 377)) + bean_count_display = font_small.render(str(player.bean_count).zfill(7), True, (0,0,0)) DISPLAY.blit(bean_count_display, (72, 394)) + if player.dead: DISPLAY.blit(retry_button, (4, 4)) death_message = font_small.render("RETRY", True, (0, 0, 0)) From 3c60325f3b383b8253229adc58d0ef543e6c7f75 Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Sat, 21 Jan 2023 21:53:44 -0500 Subject: [PATCH 09/11] Implementing some features from other PRs Created a requirements text file, updated the README, added support for Unix operating systems, made it so the game can be played in browser. --- .gitignore | 9 ++------- README.md | 12 +++++++++--- data/sfx/bean-pygbag.ogg | Bin 0 -> 4094 bytes data/sfx/dead-pygbag.ogg | Bin 0 -> 4340 bytes data/sfx/flap-pygbag.ogg | Bin 0 -> 4524 bytes data/sfx/upgrade-pygbag.ogg | Bin 0 -> 7161 bytes main.py | 37 ++++++++++++++++++++++-------------- requirements.txt | 1 + 8 files changed, 35 insertions(+), 24 deletions(-) create mode 100644 data/sfx/bean-pygbag.ogg create mode 100644 data/sfx/dead-pygbag.ogg create mode 100644 data/sfx/flap-pygbag.ogg create mode 100644 data/sfx/upgrade-pygbag.ogg create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index fb9c72a..99e4b84 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,2 @@ - -__pycache__/background.cpython-310.pyc -__pycache__/bean.cpython-310.pyc -__pycache__/button.cpython-310.pyc -__pycache__/player.cpython-310.pyc -__pycache__/utils.cpython-310.pyc -*.pyc +__pycache__ +build \ No newline at end of file diff --git a/README.md b/README.md index 022bf1f..b87aae2 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,18 @@ A Windows build of the game is available [here](https://polymars.itch.io/flappuc Grab the latest release of Python from [here](https://www.python.org/downloads/) **and** install Pygame by executing ``pip install pygame``. **Note:** If the ``pip install pygame`` did not work for you, then try this: -1. Windows: +1. Windows or Linux: ``python -m pip install pygame`` 2. Mac: ``python3 -m pip install pygame`` -3. Linux: -Same as windows. +3. Browser +```sh +pip install pygbag +cd .. +pygbag Flappuccino +``` +Then +http://localhost:8000 Ensure ``main.py`` is in the same directory as ``./data`` and execute ``python main.py``. diff --git a/data/sfx/bean-pygbag.ogg b/data/sfx/bean-pygbag.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a3efbf170c2f24279c64928455ab7220887a32dd GIT binary patch literal 4094 zcmahsZ9r2;wgUtRNHIV_z}SMDNP-aw1|bSA2_PYm0ykVC$!1kB6^%h8#A=@?k_0IN z4?_q_gAbG_C|E;q}kz+nGTtZ6-A%*f@K6)HIf-7ABu=mFsTU{SC7%=&FTP1pl=;@xa0
    ZJN9^bJWJ z%}OOe+Ki8SKIeRus*weS$-&%2l^tt_q`pe07Ug#Yp7&7Wf~m#%KL&Q+Q_bTPR;glx z-*~Gxvv+yS%|T{!%T#vkZcp`EHe7)n>pW3?lU?tv_GjTgQTs4Axq~tQYK~Ehj!_*6 z-p!7n8vsH?67l*D(v3r;8z#~`{6|7tcn|;&<+w$4+|nPpTCz|}v9zf#Ptk8STUwAs zoeMx>l2h~!qP<0L69D*{&>~}Mkujray08?lE@-p{c>v(xG|WgrSd1>}PBJ>wDj)q_ z6YHg37Io-D!rd*OHP{sf+IZPn&H*kX&!s4^Bk#SF^E`RZ#~hki6Nbqep>q|_#9CzF zw(Qn^Rn*3sHYj>;Oc@xx5IbfNI#ofrX+uYi&~Xm)GwtrH^2ca9dLL~txO72mNz?AK zs*)Cn**0w{t%@^2jN7&w`6>>hDKJx(?s4ZMlEDod)?aGVf7RCsv4pNiKNtufL@aU^ zC&T?l5DH2*j?wUUr!#!kx}JB-%x+7IOrz*n_HG{)zijroL4(BItYrAIJa{lw_KY=M zr8>7xBx`Cxcr>F9akTi)2l}34=e4OU3A3D5NIPlBcJ!~GbEgk>Gyo+0OzL-8^zZhP zbjO8~?5y(*A*_T};zXhL)0JBQm=EL4+Nakwp)wrIVpr za;%oJMZ0;ozWzwnqa#QCPgz6&0TaQX=)|s~hFwMVyGmyYwHZhB^$k@^drmyPaOTN> zYx67tP6i-{9Ft9sLCDbvL@eITbHcn!y2c!ft(P`khV-zeNNGi^ zlZNzO7PVT}!}6;xccmHOkTz}5^~O#a%J0TfVSKb(!G}X-Zi)s3KX5;b#4l&^i4?wD zbOKQ_b4H3Aw>ZIg%t)DukAIN`ymb%3viG z+)-4Ij+mvWUb#L89bYFI8A64Fxub)c^@F)r>rY+C>^XDhbaUgc%>ln&`0Ep0>_9xW zAahg_%1>#L3zTxPTlA1SYSu>!l+a4jaEppDJ!Is&!s8fLKQi>Gj}3K zBB@kLQa=;VY6g@_NriMGMJk+?O0EwoCuZXZTKPj}{6N!CNP1)1wZzQ3Fq_O(2HbWQWue{hPqe3mX5U3uX$|FCj=W?|%m zkOJnwIXSd9o+DXbsT|LEav?Dpm83{VX3><_xo{B=Ugu7DqC>OL#4j(G)b|!9yJIR2w4W z*@Z+Eyb5UQGNi*(eTzl&QXm{!g9bqkdaBA;ODKv@dDL2CA}_91J;B+hletQC zFj#$8L^ZY~@(wl_y~VQNwZ-giL%EjaXVh63w^;twDtLv$i%vwRb*8fXD5_GPy{}Qr zi>DYpBmGSkx-`fb7HwGDWF z)70V}Nt>J8?2+Dd37eeKrR9}ilb5u?>+n<4PgSDEw$5RhyzQ4NMPEaUND$wKt*Xsd zsCafs)dzRpnaC?{Y7vQxSqI)tUep3j$xN>y1DcBC1-E+2N`qfliB3a?Y^!OiO7WaA zH7t+?f9olObBLg+sljwu{n$9e>tTs*Kg@e;Ebno?JceB@yO1$m$HX(H47wu5v`-zv zm?Ei>plKhS7QryY(O9QNWVJd3+1dp2-WtpMg-nWvJxp5)D02iGvPd_74ohO9BRlCg zUPbjYVP-9|P+<1SZ_ZJa%5jSfs+34(qmqJQ0K)(ehgy&#e4RUxY@xJj)-%x*NYP6t zQYDy7t5WQ_&Wusy;*bLIkaB!hvyrvx+sr2yp8tCFoYrViB_h10PVaOWQ-h*L(_qzV7`Gm>M%FNiw`EyZs-pMOY#AbB42l%bFI5hv zH3mCr`^@}U^ z8v*!SWdow}OI9?JtKCcO7GS%@I{+U-8a!YF%tN?sC{2PdXDS7;(40AV%BJ@;qpo;P z&cUeDzLSG>M9_2%)P*#JXVJxD*rN|L8dlj_xHQTK%%~>tsF)n|ErA2OcV2!^(|({K z$a@+*s&{faBo>ySq)-^Do@_ra)MMjuhXo(!S>iVW0Aj~F!I#zSTa3*OzIaA`1BXW| zU_|!#oS+FDeKo#{B46v;&UJB}@WoER0X%d;U_@e|4RCTMtg&bNMP!|W)h%aJ0hdX~ z9k8zeE(~`-UPArRIzrPK{e7oxj@SMCfM=@+96~;!;~{Y5wqJ1w342-KH+COaeGIY3 zJ}3Y@{rLb~wUw-u+>L6hsAD|wpiU95Mv?ket-)z1MEXh8O z!r!_MDaTa_%YFaA(+4G zRgz}brh*>RSLOq1mY>`qx#DK@*npqKk)By^iwMX%&*#{T#dq=#=lx(9*u8utwl(XE z6LGCBj^KZnGmd`kiWr5p&gZ{$4Y=obam;4>eg*yB>I*N^tj?{Wnz(sc1D~I88x~Ty z510?H*X~)Ur(KNNUq1ELH z_|vfORvnq%ef0VI+pogzz?SE!i15O@`ryIiroTV@BW`OrXAFMTU4NN7kx`QP_E_c5 z$e($VQ)Y*_^FpS_R@>2WtPSaP4F$0oC?xB3@} CjBT#~ literal 0 HcmV?d00001 diff --git a/data/sfx/dead-pygbag.ogg b/data/sfx/dead-pygbag.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1cb55401e5e12079fd8554b864cee52796fcc1e9 GIT binary patch literal 4340 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%0A=;xDo^a4@whq^ZN zZi}NA+*IfGTu|ONS~*>HH{Urx4GVZO(0pEIDPE|U9P{xSH^BMa0Y1E%c1 zkDBv_hCXQA+>_N}S#4gk^mP8|(uhXxs^vtdjCZ#eLeJSX`f7Q dtPGN0O6~133@|2{&2+pWonK@SaAs}Le*oD`3F80& literal 0 HcmV?d00001 diff --git a/data/sfx/flap-pygbag.ogg b/data/sfx/flap-pygbag.ogg new file mode 100644 index 0000000000000000000000000000000000000000..da10b3e289a0db66c3e851ab061fbb4d5272b823 GIT binary patch literal 4524 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 MR`{-+?Ney^|0B4F1poj5 literal 0 HcmV?d00001 diff --git a/data/sfx/upgrade-pygbag.ogg b/data/sfx/upgrade-pygbag.ogg new file mode 100644 index 0000000000000000000000000000000000000000..289c7c5faac0ba81846138a868e48ef1955b998c GIT binary patch literal 7161 zcmahtc|25K``0c>M4Bu`S!RTcC5Ege3=@X2O_OXzlEO@stt?5BT``uHv1N%YQB<;I z-x^~ZlOy=-}kTI`J6fTxzBdad6sjZGp1LrSOCnx-^TrZ)R_Us-Xw%G z9bqDPdO5mzGZ0K?^BE5S2v%d-eZFNfWk~+p7?KQ%lvGm{kM7QYwYw~T)a(PPCJuzl zDr)kor{v)Z3Ji8J@aJ;f$)<_jP>*LL+rK z#X}`EZQ??tH9;r>0pi>kI9|Pf27QDpNY&*O4INWZ;|}?*_FE)WA7R4_;wHsH_v^h) z3CTx*%n~YwW+Ci|Ns-W6S!m?FI)%4_p{y#kuMFS#|`5oY~v(%`^1Ah*_M*suDC012mog0 z-1;{KICkYguX1LpMUreHNv@Ifh-l8x@O)+<7ywwoX_U`coHj@}+hK{JlzR;RSH~u~ z9NrZNZOGg0b~%?lLV@Kl`>r3rWd!p@D%1u4W8`26lIQuJ0tAgXmTAkAf-FXe5)I4z z;!-0k5p<$=d(#9F-VQ>~iMHG+ARnDrmubuO2a+!K>r9bh;BK~0T_W-|fRI#yUrfrQ zG7w@baEnecE(RgPNe!8p6=u43o-9EB98bXO-8_6UU#^`^TfU0)`sb4n)OL?fmD7@Qf<;S>)O zKpXxuI7WzvL%f<{*_ro{GPya=qZC_Y-?Z)y>Ob<|@Mv(u>v+$cD5yhQc&PN+xX&W! zDIuj+cJ2jbXe5l3facn@pBQL+J@&)SG3E@-juEhIq8FD;&L4A%FaWz ztO4TPikOs0;QeQtphJNh0tUPBW>g|!+%3`8Eo-`{Y|5``E}-9|jOjXvGgtL6KjqS+ zg0nbYk`(75!3-mGFlE}AxB2*lPxg+UqkgMqxeC??qMWsr=53eL2|V2WPb7& z=*vvXdBns^N-Ojpkz2X%DT+M0`Gz4*QXrBkdyQ+@Sv6ed%R0OOjr)(?uRmgIXm; z$GHt^Ud!SJPgT{Rp5UpI!e>TQ!3$)`$04Li3A=<= zgiKlpc!Yunot-SK-UcBp84``;5GTbUO(aQ>Gcv`A363D4&+b}f{S$8}sXh*QO_F4T zH9?d^yrUVDOYcrjDnp~)6TQ)(Di&4%DbzS9N9&mz6HV8Tu7L*B{f&H1BEa+5F&6r%WArAS7G5MoP z@HjkQ{5{1kzp}p1-J^0j#k(`N%+A83lCi2vHe2u6>X1%w=k;dDsDd&(Y!u@D-^nA( zKvnL=DWsFoQhqyjeyf%Ds#dohzXH!y4XuJd_p7?twQYh_w7VZLW;zC&)G}p6yZwGfQ+A17@E`%O4CL zPu=Cg;BmOsv*s#b0D}Rp2}*$&+m(PG%Uw))n7uN_8pI^I&}?uFo^m`EVnt?PJg}mdued%_HMdc_pwS2b^Q;^|CbO`Wff`I`uk7xsz`_mmt*)VX2ru|4CGnz> z;MoYd0hT2S&$tDIN)7-KV61Y+f}hAo35@R~10p3H__sFuPnGsR5F7B@R1Ns8-Ioa~ zR?~SVeu60&RQeG@dg8^cz6YifgV=%ZnCi95FYZmz0OMBBJs;60f^?H>u<>rMUX4M!!+Y(#=cV zLXn;c%7QpFa#xm<0ZsjjgE1=GT`ElSUx*aSi-a=xK-==_fx}-b|AUMB7l%gwg9Bal zmoEWr1eTy8YG9~Bbfpht1RY-NIdmj=H-2>hK%mab;z62jEBs2XI43+OR}Tpbho5N{ z%Ys>OiHC`MM~X8)tG6<)2S4n*tN<0H6ISj#S7;ImFj~u{9aptpUmG8$sEB@3qvcPlzEK>e9 zR#w(s2#iC3m38-e!z!Trhse0zFz`@E-5P!wnTDPoTJPZWG@br!>f1!``wSoJec~$> z%>%W}Xb4s0WIp{q?3sPnL@${@UPu^S z(!9o^T^4-3LB{tqAtfYuZSi`2+Uunp4=vMMB296p>E5dLj`MCr^wXgihn2O=r{(aaQUk6tIriG6DtXdzm8!pjpH1^1()b@F6KIX; zi`NcmrPCrV@NGHW--#ZFmAeiM72Ulle1+Lq%vhYQ>-|+Za!@)_>$^wCDXewi*2quC zY7dRb2vnQ<`=+Ox&+xIg9|$rHPqy{*$a0A0OcbyIlc_x#!AAy5&c{y?CCms(AAM3; z&b!yKGVN#|ZO}Q+B-W6K_?pUhN$P6o6mXA@2PKS}tF#ZoLH?Sg2Fqf0O>{PDz*tZxh5@)w&5NtqT` z`!*4Ifs>1L^*frE8v3(msyH&tKP#i6eu(Ksu!pTD5BQAmPWUL7&K)678=n_rqK<^8#RQ1;F1F%PXv`QM`Ll8T`z3GMgfdACplUd}JR&d9kFSj_u| zeY2Nko@$AQpUXdZyeoRSC(c8z{qwM*J?qHxCDrt%?|z@C;Zr*Sd+NzP3rfb-V9e#* z{S7uh#%7VMjU-W$~P8#?bPq?v|qN?|XZ745gtfo_b9~WFu`VGo`Q8>)1)Esc@2#UdyQh zKKKiZTzDWA<-6i)lqQW`UcNC=-y&x)Ta*Q%P_?bt>W>rhq?DABbJY5hE(hjP#ROMW zFIREQzY)FtA?w;F91}46gcFGR2}dQ^$eIz-fhUA^Hw~cmMG}rudWoG+prP>6nOXaF zA%hB`;BkKnGMRrCzA;VH${OtdmE&z+kn=`ndE@b8QcWUDs|{uQ?QoDoNb>x2weksr z#H|KebDBWqKuw^tEeyKhbYlTl@WAfs)8v)H9ZQ*m;woSCvufNU$JD;hZ2p+L`K8WB z#w$H9(a?ppzO5=h{*|#@RBHR?p19vZ(_{Bp=Ix)w?B93y11 z20qo7e(t%LzGI(q028>dLJzpb21M8g4W8W>%-7@WY{cv$4SdWvR5b+zQ-YMZ+%9ij z_cC_YC)_yuVZ-VDnzb~N4qsk}k1%a<}TWvjgnjZ8!7Cgu(_taE)UoPAv zW8H|AY)-5Dc{wafwrgN>=HY-F61Fw!kTv_eE{AaGxIK1%l)7*UyYZ8KJ^pG}?zGiL z=WNpJPCjp{#*L@tuxJ_W%dqR@IJO=jThy|IoJQ-5o&XbV&FcgZ)oPigC;-*q0G3QC zuiI5%!J|bJZ90xOY2?CR@6H{@2B+UwFK7@BaA5+fF7AwAd#64pZgn08WaKtCB)4kW z_dm{BBDWp2E^74}uWJi@XNTCDG^>w2eqhf@`pSM0Gj+}7w`J!>=l@o#e3JG`j>vK{nNVfwR2LJQBPKm4LiDW9f48nI^@4W>bh1} zg=t#yL2o>eqXz+C>C4)ZAvCoe?ltSdp=fcKjjj1S0DN+P3IA=Qg^yV)%3vLgUXg=s zN>{^P#LQLOpHWmAR=Up1$+hK|yNQBF63tX_pH%`ua9?3Xucj1U?Fu zLV9DnLeC%O8MNx&d8IyE5Ym5Dhi!>KGe4hC@s~JO7O?)~yS@7e%3NhU_H@nash_Pcy*1R$5xv<#R+oQ@l3?W~+s1R(gyg@&twAMJ&LGAE~sbU6xaQE2~MC%+BE#e>v zX)FM7lBD8M@)@$_t5N+RvGQKCaZ`&*-t1>c+l7qfb!QeA&pFS{PY>MRfPZmK-MUra zkCg=|g1~4YjD!CT)RF;?H*sxh`M(Fu&Be92j`q z_Wn~#$Kqxkr94v;bDa!S_4=?#xiqhFP`63GkXtJ;Em!7Rg(y&GB|cH~QapBVR4 z7d`o8H!Hk9DO*7verP;Rz_+|z6~RG z?*HCQJ72-)9IAz80?u8w%#yfU!Vi4wSdtQdLcXJa{lt09^mKE>Twp-aeUrw1Aos zcz}qhpj$Z(`>pxz{u-0n?ihcF+Dchs7WaA)mW3UJ%|EBndu|0qRT#qz?995ay~>w~ zm(s5UfN4Sbl;)xBld49k^!94$E;gHs7t1{ZU+46eThWc~vHSb`x4H+Mq^PL0#NKf= zPZos9U_0p?LF;4d_pH-s(wDUZ?`r*OCKq3|uM<|8aVyQSN~wDo?JU|diyH z@)kEpjWF!G^`yT6{ zB`t5gB01w#<-q;3d#d$2ALi}%42-U+^?2XPY}jW0!s$hcSsgQAS+kZ+n{947apX}o zEo5-(SJhZHpaA66xPMipv)+8Z2!z=p?|u`!2679c`NRq)mah7-)4U?p~Zu{~qA= z`MgW^uGw$>l|A$2pOO_@&-u;FAT=)6qTF6(e$}k*`_U(pGgC@X228!OB8+oM~ot{=oW!y!U>??RY)AO@xwgY-Lrmif_ zKHe!dZJo{c^l?%#IhydW+PJ0ZalFXRN|?JM%DSjCal~b2Bk7Ic?~Q)e?Q{8!H+WHaD=dT0<99~CtS7aR@r z`EZ%4J#Xa%_zK3+=Iqiw&&*?ImIu^oRtAp_j^Eu`yFS|W;+FqQmXG~j!|mt`4JSP> zI;d@}JL|DjzG2UNGB@M%(EnxA9+wPz;~ut~eyaPrf@^=Zmy8oSh?`$~fj}vuRr-9v z4ZD@fx=_L6OFi13uLMOVo##Q@O9L8fpOD%o87;^{IYq6)KB4r? zc^3{Tz(#AJWNmvvJc*)}v?)>~iMqn1Mc5qnT31$iJHvO!hb9R`**HX}4uW?asB|Zy zvF)cW5X>FXj<`L3e!?%E1qf!6{MLW9x~2hg94MqEzDdkl*)U*neV0w`QzE|>3*4kp zgvh|~&fHR3=Bp#zpNVtoCLNT0AM>RKJ{u2kZ8`Ol#_7jLZYHNSB>~j5*HiB;lM`Idh}rc literal 0 HcmV?d00001 diff --git a/main.py b/main.py index 599996a..4417fcf 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python3 +# Tells Unix operating systems to run with Python3 when it gets executed + import pygame import sys import time @@ -5,6 +8,7 @@ import colorsys import math import pygame.display as Display +import asyncio from pygame.locals import * from pygame.mixer import Sound from pygame.font import Font @@ -40,11 +44,15 @@ shadow = Image('data/gfx/shadow.png') indicators = ['data/gfx/flap_indicator.png', 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] -# get some sounds -upgradefx = Sound("data/sfx/upgrade.wav") -beanfx = Sound("data/sfx/bean.wav") -deadfx = Sound("data/sfx/dead.wav") -flapfx = Sound("data/sfx/flap.wav") +# sounds +if ['win64','win32','win','linux'].__contains__(sys.platform): + sound_ext = '.wav' +else: + sound_ext = '-pybag.ogg' +flapfx = pygame.mixer.Sound("data/sfx/flap" + sound_ext) +upgradefx = pygame.mixer.Sound("data/sfx/upgrade" + sound_ext) +beanfx = pygame.mixer.Sound("data/sfx/bean" + sound_ext) +deadfx = pygame.mixer.Sound("data/sfx/dead" + sound_ext) # colors WHITE=(255,255,255) # constant @@ -57,8 +65,8 @@ def start(): scroll = True dt = 0 bean_multiplier = 5 - beans = list[Bean] - buttons = list[Button] + beans = [] + buttons = [] mouse_x, mouse_y = pygame.mouse.get_pos() player.reset() # adding three buttons @@ -71,7 +79,7 @@ def start(): Sound.play(flapfx) def func_one(toggle: bool = True) -> None: - global dt, last_time, mouse_x, mouse_y, clicked, keys, jump + global dt, last_time, mouse_x, mouse_y, clicked, jump # calculate the change in time (dt) dt = (time.time() - last_time) * 60 # save the current time @@ -81,9 +89,7 @@ def func_one(toggle: bool = True) -> None: clicked = False jump = False # get the position of the mouse - mouse_x, mouse_y = pygame.mouse.get_pos() - # getting the keys pressed - keys = pygame.key.get_pressed() + mouse_x, mouse_y = pygame.mouse.get_pos() event_handler() def event_handler() -> None: @@ -99,7 +105,7 @@ def event_handler() -> None: pygame.quit() sys.exit() -def main() -> None: +async def main() -> None: global clicked, bean_multiplier, beans, scroll start() @@ -119,6 +125,7 @@ def main() -> None: DISPLAY.blit(start_message, (DISPLAY.get_width()/2 - start_message.get_width()/2, DISPLAY.get_height()/2 - start_message.get_height()/2)) # update display Display.update() + await asyncio.sleep(0) # wait for 10 seconds pygame.time.delay(10) @@ -142,6 +149,7 @@ def main() -> None: DISPLAY.blit(start_message, (DISPLAY.get_width()/2 - start_message.get_width()/2, 292)) Display.update() + await asyncio.sleep(0) pygame.time.delay(10) # the main game loop @@ -157,7 +165,7 @@ def main() -> None: DISPLAY.fill(WHITE) for o in bg: - o.setSprite(((player.position.y/50) % 100) / 100) + o.set_sprite(((player.position.y/50) % 100) / 100) DISPLAY.blit(o.sprite, (0, o.position)) color = colorsys.hsv_to_rgb(((player.position.y/50) % 100) / 100,0.5,0.5) current_height_marker = font.render(str(player.height), True, (color[0]*255, color[1]*255, color[2]*255, 50 )) @@ -238,7 +246,8 @@ def main() -> None: bg[2].position = bg[0].position - DISPLAY.get_height() Display.update() + await asyncio.sleep(0) pygame.time.delay(10) if __name__ == "__main__": - main() \ No newline at end of file + asyncio.run(main()) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..231dd17 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pygame \ No newline at end of file From 4b1476cc49669d85f5198a1d7865c7db78ead0d0 Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Sat, 21 Jan 2023 23:28:12 -0500 Subject: [PATCH 10/11] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b87aae2..56ea033 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Then http://localhost:8000 Ensure ``main.py`` is in the same directory as ``./data`` and execute ``python main.py``. +**Note:** If python does not work, try python3, py, or py3. ## Contributing Pull requests are welcome! For major refactors, please open an issue first to discuss what you would like to improve. Feel free to create a fork of this repository and use the code for any noncommercial purposes. From f0071a4a664c96ba7ad008bb2537fa0dea4a4b65 Mon Sep 17 00:00:00 2001 From: Jacob Knox Date: Thu, 12 Oct 2023 15:36:07 -0400 Subject: [PATCH 11/11] Autoformat to PEP8 --- background.py | 14 +++--- bean.py | 7 +-- button.py | 7 +-- main.py | 125 ++++++++++++++++++++++++++++++-------------------- player.py | 13 +++--- utils.py | 1 + 6 files changed, 100 insertions(+), 67 deletions(-) diff --git a/background.py b/background.py index 36ef605..b422614 100644 --- a/background.py +++ b/background.py @@ -1,15 +1,17 @@ import pygame import colorsys + class Background: uncolored_sprite = pygame.image.load('data/gfx/bg.png') - + def __init__(self): self.sprite = pygame.image.load('data/gfx/bg.png') self.position = 0 - - def set_sprite(self, tint: float) -> None: + + def set_sprite(self, tint: float) -> None: copy = self.uncolored_sprite.copy() - color = colorsys.hsv_to_rgb(tint,1,1) - copy.fill((color[0]*255, color[1]*255, color[2]*255), special_flags=pygame.BLEND_ADD) - self.sprite = copy \ No newline at end of file + color = colorsys.hsv_to_rgb(tint, 1, 1) + copy.fill((color[0]*255, color[1]*255, color[2]*255), + special_flags=pygame.BLEND_ADD) + self.sprite = copy diff --git a/bean.py b/bean.py index 202e03a..c81bf45 100644 --- a/bean.py +++ b/bean.py @@ -1,8 +1,9 @@ import pygame -class Bean: + +class Bean: sprite = pygame.image.load('data/gfx/bean.png') - + def __init__(self, x_pos: float = 0, y_pos: float = 0): self.position = pygame.Vector2() - self.position.xy = x_pos, y_pos \ No newline at end of file + self.position.xy = x_pos, y_pos diff --git a/button.py b/button.py index d628d32..45e0289 100644 --- a/button.py +++ b/button.py @@ -1,10 +1,11 @@ import pygame from pygame.image import load + class Button: sprite = load('data/gfx/button.png') type_indicator_sprite = load('data/gfx/null_indicator.png') - + def __init__(self, index: int, indicator: str) -> None: self.price = 5 self.level = 1 @@ -12,6 +13,6 @@ def __init__(self, index: int, indicator: str) -> None: self.type_indicator_sprite = load(indicator) self.position = pygame.Vector2() self.position.xy = 220 + (self.index*125), 393 - + def set_price(self, new_price: int) -> None: - self.price = new_price \ No newline at end of file + self.price = new_price diff --git a/main.py b/main.py index 4417fcf..8f84558 100644 --- a/main.py +++ b/main.py @@ -25,7 +25,7 @@ # set the display Display.set_caption('Flappuccino') Display.set_icon(Bean.sprite) -DISPLAY = Display.set_mode((640, 480), pygame.RESIZABLE | pygame.SCALED,32) +DISPLAY = Display.set_mode((640, 480), pygame.RESIZABLE | pygame.SCALED, 32) player = Player() @@ -42,10 +42,11 @@ title_bg = Image('data/gfx/bg.png') title_bg.fill((255, 30.599999999999998, 0.0), special_flags=pygame.BLEND_ADD) shadow = Image('data/gfx/shadow.png') -indicators = ['data/gfx/flap_indicator.png', 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] +indicators = ['data/gfx/flap_indicator.png', + 'data/gfx/speed_indicator.png', 'data/gfx/beanup_indicator.png'] # sounds -if ['win64','win32','win','linux'].__contains__(sys.platform): +if ['win64', 'win32', 'win', 'linux'].__contains__(sys.platform): sound_ext = '.wav' else: sound_ext = '-pybag.ogg' @@ -55,7 +56,8 @@ deadfx = pygame.mixer.Sound("data/sfx/dead" + sound_ext) # colors -WHITE=(255,255,255) # constant +WHITE = (255, 255, 255) # constant + def start(): global bean_multiplier, beans, buttons, last_time, clicked, jump, dt, mouse_x, mouse_y, scroll @@ -75,16 +77,18 @@ def start(): buttons[2].set_price(30) # getting 5 beans for i in range(5): - beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()) ,i * -200 - player.position.y)) + beans.append(Bean(random.randrange(0, DISPLAY.get_width() - + Bean().sprite.get_width()), i * -200 - player.position.y)) Sound.play(flapfx) + def func_one(toggle: bool = True) -> None: global dt, last_time, mouse_x, mouse_y, clicked, jump # calculate the change in time (dt) dt = (time.time() - last_time) * 60 # save the current time last_time = time.time() - if(toggle): + if (toggle): # resetting clicked and jump flags to false clicked = False jump = False @@ -92,28 +96,30 @@ def func_one(toggle: bool = True) -> None: mouse_x, mouse_y = pygame.mouse.get_pos() event_handler() + def event_handler() -> None: global jump, clicked for event in pygame.event.get(): - if event.type==pygame.KEYDOWN and event.key == K_SPACE: + if event.type == pygame.KEYDOWN and event.key == K_SPACE: jump = True if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: clicked = True if clicked and mouse_y < DISPLAY.get_height() - 90: jump = True - if event.type==QUIT: + if event.type == QUIT: pygame.quit() sys.exit() + async def main() -> None: global clicked, bean_multiplier, beans, scroll start() - + # creating a list of backgrounds, with each index being an object bg = [Background(), Background(), Background()] # startingHeight = 100 (the initial y position of the player) starting_height = player.position.y - + # splash screen splash_screen_timer = 0 while splash_screen_timer < 100: @@ -122,13 +128,14 @@ async def main() -> None: DISPLAY.fill((231, 205, 183)) # fill the start message on the top of the game start_message = font_small.render("POLYMARS", True, (171, 145, 123)) - DISPLAY.blit(start_message, (DISPLAY.get_width()/2 - start_message.get_width()/2, DISPLAY.get_height()/2 - start_message.get_height()/2)) + DISPLAY.blit(start_message, (DISPLAY.get_width()/2 - start_message.get_width() / + 2, DISPLAY.get_height()/2 - start_message.get_height()/2)) # update display Display.update() await asyncio.sleep(0) # wait for 10 seconds pygame.time.delay(10) - + # title screen title_screen = True Sound.play(flapfx) @@ -141,12 +148,15 @@ async def main() -> None: Sound.play(upgradefx) DISPLAY.fill(WHITE) - DISPLAY.blit(title_bg, (0,0)) - DISPLAY.blit(shadow, (0,0)) - DISPLAY.blit(logo, (DISPLAY.get_width()/2 - logo.get_width()/2, DISPLAY.get_height()/2 - logo.get_height()/2 + math.sin(time.time()*5)*5 - 25)) - DISPLAY.blit(retry_button, (DISPLAY.get_width()/2 - retry_button.get_width()/2, 288)) + DISPLAY.blit(title_bg, (0, 0)) + DISPLAY.blit(shadow, (0, 0)) + DISPLAY.blit(logo, (DISPLAY.get_width()/2 - logo.get_width()/2, + DISPLAY.get_height()/2 - logo.get_height()/2 + math.sin(time.time()*5)*5 - 25)) + DISPLAY.blit(retry_button, (DISPLAY.get_width() / + 2 - retry_button.get_width()/2, 288)) start_message = font_small.render("START", True, (0, 0, 0)) - DISPLAY.blit(start_message, (DISPLAY.get_width()/2 - start_message.get_width()/2, 292)) + DISPLAY.blit(start_message, (DISPLAY.get_width() / + 2 - start_message.get_width()/2, 292)) Display.update() await asyncio.sleep(0) @@ -155,48 +165,60 @@ async def main() -> None: # the main game loop while True: func_one() - - cam_offset = -player.position.y + (DISPLAY.get_height() - player.current_sprite.get_size()[1])/2 - if(cam_offset <= 0): - if(not player.dead): + + cam_offset = -player.position.y + \ + (DISPLAY.get_height() - player.current_sprite.get_size()[1])/2 + if (cam_offset <= 0): + if (not player.dead): player.kill(deadfx) scroll = False cam_offset = 0 - + DISPLAY.fill(WHITE) for o in bg: o.set_sprite(((player.position.y/50) % 100) / 100) DISPLAY.blit(o.sprite, (0, o.position)) - color = colorsys.hsv_to_rgb(((player.position.y/50) % 100) / 100,0.5,0.5) - current_height_marker = font.render(str(player.height), True, (color[0]*255, color[1]*255, color[2]*255, 50 )) - DISPLAY.blit(current_height_marker, (DISPLAY.get_width()/2 - current_height_marker.get_width()/2, cam_offset + round((player.position.y - starting_height)/DISPLAY.get_height())*DISPLAY.get_height() + player.current_sprite.get_height() - 40)) - + color = colorsys.hsv_to_rgb( + ((player.position.y/50) % 100) / 100, 0.5, 0.5) + current_height_marker = font.render( + str(player.height), True, (color[0]*255, color[1]*255, color[2]*255, 50)) + DISPLAY.blit(current_height_marker, (DISPLAY.get_width()/2 - current_height_marker.get_width()/2, cam_offset + round( + (player.position.y - starting_height)/DISPLAY.get_height())*DISPLAY.get_height() + player.current_sprite.get_height() - 40)) + for bean in beans: - DISPLAY.blit(bean.sprite, (bean.position.x, bean.position.y + cam_offset)) - - DISPLAY.blit(pygame.transform.rotate(player.current_sprite, clamp(player.velocity.y, -10, 5)*player.rot_offset), (player.position.x,player.position.y + cam_offset)) + DISPLAY.blit(bean.sprite, (bean.position.x, + bean.position.y + cam_offset)) + + DISPLAY.blit(pygame.transform.rotate(player.current_sprite, clamp( + player.velocity.y, -10, 5)*player.rot_offset), (player.position.x, player.position.y + cam_offset)) DISPLAY.blit(shop_bg, (0, 0)) - pygame.draw.rect(DISPLAY,(81,48,20),(21,437,150*(player.health/100),25)) + pygame.draw.rect(DISPLAY, (81, 48, 20), + (21, 437, 150*(player.health/100), 25)) DISPLAY.blit(shop, (0, 0)) - + for button in buttons: DISPLAY.blit(button.sprite, (220 + (button.index*125), 393)) - price_display = font_small.render(str(button.price), True, (0,0,0)) + price_display = font_small.render( + str(button.price), True, (0, 0, 0)) DISPLAY.blit(price_display, (262 + (button.index*125), 408)) - level_display = font_20.render(f'Lvl. {button.level}', True, (200,200,200)) + level_display = font_20.render( + f'Lvl. {button.level}', True, (200, 200, 200)) DISPLAY.blit(level_display, (234 + (button.index*125), 441)) - DISPLAY.blit(button.type_indicator_sprite, (202 + (button.index*125), 377)) - - bean_count_display = font_small.render(str(player.bean_count).zfill(7), True, (0,0,0)) + DISPLAY.blit(button.type_indicator_sprite, + (202 + (button.index*125), 377)) + + bean_count_display = font_small.render( + str(player.bean_count).zfill(7), True, (0, 0, 0)) DISPLAY.blit(bean_count_display, (72, 394)) - + if player.dead: DISPLAY.blit(retry_button, (4, 4)) death_message = font_small.render("RETRY", True, (0, 0, 0)) DISPLAY.blit(death_message, (24, 8)) - - if(scroll): - player.set_height(round(-(player.position.y - starting_height)/DISPLAY.get_height())) + + if (scroll): + player.set_height( + round(-(player.position.y - starting_height)/DISPLAY.get_height())) player.position.x += player.velocity.x*dt if player.position.x < 0 or player.position.x + player.current_sprite.get_size()[0] > 640: player.flip() @@ -204,7 +226,8 @@ async def main() -> None: player.velocity.y = -player.flap_force Sound.play(flapfx) player.position.y += player.velocity.y*dt - player.velocity.y = clamp(player.velocity.y + player.acceleration*dt, -99999999999, 50) + player.velocity.y = clamp( + player.velocity.y + player.acceleration*dt, -99999999999, 50) if not player.dead: player.health -= 0.2*dt @@ -214,13 +237,15 @@ async def main() -> None: for bean in beans: if bean.position.y + cam_offset + 90 > DISPLAY.get_height(): bean.position.y -= DISPLAY.get_height()*2 - bean.position.x = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()) + bean.position.x = random.randrange( + 0, DISPLAY.get_width() - bean.sprite.get_width()) if (check_collisions(player.position.x, player.position.y, player.current_sprite.get_width(), player.current_sprite.get_height(), bean.position.x, bean.position.y, bean.sprite.get_width(), bean.sprite.get_height())): Sound.play(beanfx) player.bean_count += 1 player.health = 100 bean.position.y -= DISPLAY.get_height() - random.randrange(0, 200) - bean.position.x = random.randrange(0, DISPLAY.get_width() - bean.sprite.get_width()) + bean.position.x = random.randrange( + 0, DISPLAY.get_width() - bean.sprite.get_width()) for button in buttons: if clicked and not player.dead and check_collisions(mouse_x, mouse_y, 3, 3, button.position.x, button.position.y, button.sprite.get_width(), button.sprite.get_height()): @@ -236,18 +261,20 @@ async def main() -> None: if (button.index == 2): bean_multiplier += 5 for _ in range(bean_multiplier): - beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width()), player.position.y - DISPLAY.get_height() - random.randrange(0, 200))) - + beans.append(Bean(random.randrange(0, DISPLAY.get_width() - Bean().sprite.get_width( + )), player.position.y - DISPLAY.get_height() - random.randrange(0, 200))) + if player.dead and clicked and check_collisions(mouse_x, mouse_y, 3, 3, 4, 4, retry_button.get_width(), retry_button.get_height()): start() - bg[0].position = cam_offset + round(player.position.y/DISPLAY.get_height())*DISPLAY.get_height() - bg[1].position = bg[0].position + DISPLAY.get_height() + bg[0].position = cam_offset + \ + round(player.position.y/DISPLAY.get_height())*DISPLAY.get_height() + bg[1].position = bg[0].position + DISPLAY.get_height() bg[2].position = bg[0].position - DISPLAY.get_height() - + Display.update() await asyncio.sleep(0) pygame.time.delay(10) if __name__ == "__main__": - asyncio.run(main()) \ No newline at end of file + asyncio.run(main()) diff --git a/player.py b/player.py index d950a93..b82ca63 100644 --- a/player.py +++ b/player.py @@ -1,11 +1,12 @@ import pygame + class Player: position = pygame.Vector2() velocity = pygame.Vector2() right_sprite = pygame.image.load('data/gfx/player.png') left_sprite = pygame.transform.flip(right_sprite, True, False) - + def __init__(self): self.dead = False self.health = 100 @@ -17,21 +18,21 @@ def __init__(self): self.bean_count = 0 self.rot_offset = -5 self.current_sprite = self.right_sprite - + def reset(self) -> None: self.__init__() - + def kill(self, sound: str) -> None: self.dead = True pygame.mixer.Sound.play(sound) - + def set_height(self, new_height: float) -> None: self.height = new_height - + def flip(self) -> None: self.velocity.x *= -1 self.rot_offset *= -1 if self.current_sprite == self.right_sprite: self.current_sprite = self.left_sprite else: - self.current_sprite = self.right_sprite \ No newline at end of file + self.current_sprite = self.right_sprite diff --git a/utils.py b/utils.py index 2913e5f..4967998 100644 --- a/utils.py +++ b/utils.py @@ -5,5 +5,6 @@ def clamp(value, min_, max_): return max_ return value + def check_collisions(a_x, a_y, a_width, a_height, b_x, b_y, b_width, b_height): return (a_x + a_width > b_x) and (a_x < b_x + b_width) and (a_y + a_height > b_y) and (a_y < b_y + b_height)