diff --git a/.gitignore b/.gitignore index 2ab793b..b6e4761 100644 --- a/.gitignore +++ b/.gitignore @@ -127,4 +127,3 @@ dmypy.json # Pyre type checker .pyre/ -.vscode diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..16f3447 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "python.analysis.extraPaths": [ + "./src/gravity", + "./src/platformer", + "./src/platformer/level_creator", + "./src/tictactoe" + ], + "python.linting.pylintArgs": [ + "--disable=all", + "--enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode", + "--extension-pkg-whitelist=pygame" + ], + "python.formatting.provider": "black" +} \ No newline at end of file diff --git a/Flappy_Bird/04B_19.TTF b/Flappy_Bird/04B_19.TTF new file mode 100644 index 0000000..6338c19 Binary files /dev/null and b/Flappy_Bird/04B_19.TTF differ diff --git a/Flappy_Bird/assets/background-day.png b/Flappy_Bird/assets/background-day.png new file mode 100644 index 0000000..afcb5ec Binary files /dev/null and b/Flappy_Bird/assets/background-day.png differ diff --git a/Flappy_Bird/assets/background-night.png b/Flappy_Bird/assets/background-night.png new file mode 100644 index 0000000..e2a2b89 Binary files /dev/null and b/Flappy_Bird/assets/background-night.png differ diff --git a/Flappy_Bird/assets/base.png b/Flappy_Bird/assets/base.png new file mode 100644 index 0000000..c374f2b Binary files /dev/null and b/Flappy_Bird/assets/base.png differ diff --git a/Flappy_Bird/assets/bluebird-downflap.png b/Flappy_Bird/assets/bluebird-downflap.png new file mode 100644 index 0000000..d82802a Binary files /dev/null and b/Flappy_Bird/assets/bluebird-downflap.png differ diff --git a/Flappy_Bird/assets/bluebird-midflap.png b/Flappy_Bird/assets/bluebird-midflap.png new file mode 100644 index 0000000..034b76c Binary files /dev/null and b/Flappy_Bird/assets/bluebird-midflap.png differ diff --git a/Flappy_Bird/assets/bluebird-upflap.png b/Flappy_Bird/assets/bluebird-upflap.png new file mode 100644 index 0000000..900d012 Binary files /dev/null and b/Flappy_Bird/assets/bluebird-upflap.png differ diff --git a/Flappy_Bird/assets/gameover.png b/Flappy_Bird/assets/gameover.png new file mode 100644 index 0000000..b1df7f5 Binary files /dev/null and b/Flappy_Bird/assets/gameover.png differ diff --git a/Flappy_Bird/assets/message.png b/Flappy_Bird/assets/message.png new file mode 100644 index 0000000..9243ab5 Binary files /dev/null and b/Flappy_Bird/assets/message.png differ diff --git a/Flappy_Bird/assets/pipe-green.png b/Flappy_Bird/assets/pipe-green.png new file mode 100644 index 0000000..4664401 Binary files /dev/null and b/Flappy_Bird/assets/pipe-green.png differ diff --git a/Flappy_Bird/assets/pipe-red.png b/Flappy_Bird/assets/pipe-red.png new file mode 100644 index 0000000..ab6e065 Binary files /dev/null and b/Flappy_Bird/assets/pipe-red.png differ diff --git a/Flappy_Bird/assets/redbird-downflap.png b/Flappy_Bird/assets/redbird-downflap.png new file mode 100644 index 0000000..e853b95 Binary files /dev/null and b/Flappy_Bird/assets/redbird-downflap.png differ diff --git a/Flappy_Bird/assets/redbird-midflap.png b/Flappy_Bird/assets/redbird-midflap.png new file mode 100644 index 0000000..a915f7e Binary files /dev/null and b/Flappy_Bird/assets/redbird-midflap.png differ diff --git a/Flappy_Bird/assets/redbird-upflap.png b/Flappy_Bird/assets/redbird-upflap.png new file mode 100644 index 0000000..f9ed856 Binary files /dev/null and b/Flappy_Bird/assets/redbird-upflap.png differ diff --git a/Flappy_Bird/assets/yellowbird-downflap.png b/Flappy_Bird/assets/yellowbird-downflap.png new file mode 100644 index 0000000..e9e1c77 Binary files /dev/null and b/Flappy_Bird/assets/yellowbird-downflap.png differ diff --git a/Flappy_Bird/assets/yellowbird-midflap.png b/Flappy_Bird/assets/yellowbird-midflap.png new file mode 100644 index 0000000..2ca3c2d Binary files /dev/null and b/Flappy_Bird/assets/yellowbird-midflap.png differ diff --git a/Flappy_Bird/assets/yellowbird-upflap.png b/Flappy_Bird/assets/yellowbird-upflap.png new file mode 100644 index 0000000..2f693da Binary files /dev/null and b/Flappy_Bird/assets/yellowbird-upflap.png differ diff --git a/Flappy_Bird/game.py b/Flappy_Bird/game.py new file mode 100644 index 0000000..e7e729d --- /dev/null +++ b/Flappy_Bird/game.py @@ -0,0 +1,176 @@ +import pygame +import sys +import random + + +def draw_floor(): + screen.blit(floor_surface, (floor_x_pos, 900)) + screen.blit(floor_surface, (floor_x_pos + 576, 900)) + + +def create_pipe(): + random_pipe_pos = random.choice(pipe_height) + + bottom_pipe = pipe_surface.get_rect(midtop=(700, random_pipe_pos)) + top_pipe = pipe_surface.get_rect(midbottom=(700, random_pipe_pos-300)) + return bottom_pipe, top_pipe + + +def move_pipes(pipes): + for pipe in pipes: + pipe.centerx -= 5 + return pipes + + +def draw_pipes(pipes): + for pipe in pipes: + if pipe.bottom >= 1024: + screen.blit(pipe_surface, pipe) + else: + flip_pipe = pygame.transform.flip(pipe_surface, False, True) + screen.blit(flip_pipe, pipe) + + +def check_collision(pipes): + for pipe in pipes: + if bird_rect.colliderect(pipe): + return False + if bird_rect.top <= -100 or bird_rect.bottom >= 900: + return False + return True + + +def rotate_bird(bird): + new_bird = pygame.transform.rotozoom(bird, -bird_movement*3, 1) + return new_bird + + +def bird_animation(): + new_bird = bird_frames[bird_index] + new_bird_rect = new_bird.get_rect(center=(100, bird_rect.centery)) + return new_bird, new_bird_rect + + +def score_display(game_state): + if game_state == 'main_game': + + score_surface = game_font.render( + f'Score:{int(score)}', True, (255, 255, 255)) + score_rect = score_surface.get_rect(center=(288, 100)) + screen.blit(score_surface, score_rect) + if game_state == 'game_over': + score_surface = game_font.render( + f'Score:{int(score)}', True, (255, 255, 255)) + score_rect = score_surface.get_rect(center=(288, 100)) + screen.blit(score_surface, score_rect) + + high_score_surface = game_font.render( + f'High Score:{int(high_score)}', True, (255, 255, 255)) + high_score_rect = high_score_surface.get_rect(center=(288, 850)) + screen.blit(high_score_surface, high_score_rect) + + +def update_score(score, high_score): + if score > high_score: + high_score = score + return high_score + + +pygame.init() +screen = pygame.display.set_mode((576, 1024)) +clock = pygame.time.Clock() +game_font = pygame.font.Font('04B_19.ttf', 40) + +# game variables +gravity = 0.25 +bird_movement = 0 +game_active = True +score = 0 +high_score = 0 + +bg_surface = pygame.image.load('assets/background-day.png').convert() +bg_surface = pygame.transform.scale2x(bg_surface) + +floor_surface = pygame.image.load('assets/base.png').convert() +floor_surface = pygame.transform.scale2x(floor_surface) +floor_x_pos = 0 + +bird_downflap = pygame.transform.scale2x(pygame.image.load( + 'assets/bluebird-downflap.png')).convert_alpha() +bird_midflap = pygame.transform.scale2x(pygame.image.load( + 'assets/bluebird-midflap.png')).convert_alpha() +bird_upflap = pygame.transform.scale2x(pygame.image.load( + 'assets/bluebird-upflap.png')).convert_alpha() +bird_frames = [bird_downflap, bird_midflap, bird_upflap] +bird_index = 0 +bird_surface = bird_frames[bird_index] +bird_rect = bird_surface.get_rect(center=(100, 512)) + + +BIRDFLAP = pygame.USEREVENT + 1 +pygame.time.set_timer(BIRDFLAP, 200) + + + +pipe_surface = pygame.image.load('assets/pipe-green.png') +pipe_surface = pygame.transform.scale2x(pipe_surface) +pipe_list = [] +pipe_height = [400, 600, 800] +SPAWNPIPE = pygame.USEREVENT +pygame.time.set_timer(SPAWNPIPE, 1200) + +game_over_surface = pygame.transform.scale2x( + pygame.image.load('assets/message.png').convert_alpha()) +game_over_rect = game_over_surface.get_rect(center=(288, 512)) + +while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_SPACE and game_active: + bird_movement = 0 + bird_movement -= 12 + if event.key == pygame.K_SPACE and game_active == False: + game_active = True + pipe_list.clear() + bird_rect.center = (100, 512) + bird_movement = 0 + score = 0 + if event.type == SPAWNPIPE: + pipe_list.extend(create_pipe()) + if event.type == BIRDFLAP: + if bird_index < 2: + bird_index += 1 + else: + bird_index = 0 + bird_surface, bird_rect = bird_animation() + screen.blit(bg_surface, (0, 0)) + + if game_active: + + bird_movement += gravity + rotated_bird = rotate_bird(bird_surface) + bird_rect.centery += bird_movement + screen.blit(rotated_bird, bird_rect) + + game_active = check_collision(pipe_list) + + pipe_list = move_pipes(pipe_list) + draw_pipes(pipe_list) + score += 0.01 + score_display('main_game') + else: + screen.blit(game_over_surface, game_over_rect) + high_score = update_score(score, high_score) + score_display('game_over') + + floor_x_pos -= 1 + draw_floor() + + if floor_x_pos <= -576: + floor_x_pos = 0 + + pygame.display.update() + clock.tick(120) diff --git a/Flappy_Bird/readme.md b/Flappy_Bird/readme.md new file mode 100644 index 0000000..f6af77f --- /dev/null +++ b/Flappy_Bird/readme.md @@ -0,0 +1,8 @@ +Created at : 3rd August 2020 + +Flappy bird made using pygame . + +![image](https://user-images.githubusercontent.com/53135035/193448320-63c9befb-845a-48bd-a7c2-dfcdace2623d.png) + + +run game.py to start the game! diff --git a/src/gravity/constants.py b/src/gravity/constants.py new file mode 100644 index 0000000..12dd174 --- /dev/null +++ b/src/gravity/constants.py @@ -0,0 +1,6 @@ +WIDTH, HEIGHT = (1248, 702) +FPS = 60 +BLACK = "#000000" +GREY = "#808080" +WHITE = "#FFFFFF" +G = 100000 # Gravitational constant diff --git a/src/gravity/main.py b/src/gravity/main.py new file mode 100644 index 0000000..332769d --- /dev/null +++ b/src/gravity/main.py @@ -0,0 +1,54 @@ +#!/usr/bin/python +""" +Github repo can be found here: +https://github.com/sparshg/py-games +""" + +import pygame as pg +import sys +from universe import Universe +from constants import * + + +# The main controller +class Main: + def __init__(self): + pg.init() + pg.display.set_caption("gravity") + self.win = pg.display.set_mode((WIDTH, HEIGHT)) + self.clock = pg.time.Clock() + self.running = True + + self.universe = Universe() + + # Key press and close button functionality + def checkEvents(self): + for event in pg.event.get(): + if event.type == pg.QUIT: + self.running = False + + # Update things + def update(self, dt): + self.universe.update(dt) + + # Draw things + def render(self): + self.win.fill(BLACK) + self.universe.render(self.win) + pg.display.update() + + # The main loop + def loop(self): + while self.running: + dt = self.clock.tick(FPS) / 1000 + self.checkEvents() + self.update(dt) + self.render() + pg.quit() + sys.exit() + + +# Test if the script is directly ran +if __name__ == "__main__": + main = Main() + main.loop() diff --git a/src/gravity/planet.py b/src/gravity/planet.py new file mode 100644 index 0000000..2d8657b --- /dev/null +++ b/src/gravity/planet.py @@ -0,0 +1,32 @@ +import pygame as pg +from constants import * + + +class Planet: + def __init__(self, mass, radius, pos=(WIDTH / 2, HEIGHT / 2), vel=(0, 0)): + self.mass = mass + self.radius = radius + self.pos = pg.Vector2(pos) + self.vel = pg.Vector2(vel) + self.prevPositions = [] + + def calcUpdate(self, planets): + self.field = pg.Vector2(0, 0) + for planet in planets: + r = planet.pos - self.pos + mag = r.magnitude() + if mag != 0: + self.field += G * planet.mass * r * mag ** -3 + + def applyUpdate(self, dt): + self.prevPositions.append((self.pos.x, self.pos.y)) + if len(self.prevPositions) > 100: + self.prevPositions.pop(0) + + self.vel += self.field * dt + self.pos += self.vel * dt + + def render(self, surf): + for i in range(len(self.prevPositions)): + pg.draw.circle(surf, GREY, self.prevPositions[len(self.prevPositions) - i - 1], self.radius - i/self.radius) + pg.draw.circle(surf, WHITE, self.pos, self.radius) \ No newline at end of file diff --git a/src/gravity/universe.py b/src/gravity/universe.py new file mode 100644 index 0000000..cfa173c --- /dev/null +++ b/src/gravity/universe.py @@ -0,0 +1,21 @@ +import pygame as pg +from planet import Planet +from constants import * + + +class Universe: + def __init__(self): + self.planets = [ + Planet(10, 10, (WIDTH / 2 - 100, HEIGHT / 2), (0, 50)), + Planet(10, 10, (WIDTH / 2 + 100, HEIGHT / 2), (0, -50)), + ] + + def update(self, dt): + for planet in self.planets: + planet.calcUpdate(self.planets) + for planet in self.planets: + planet.applyUpdate(dt) + + def render(self, surf): + for planet in self.planets: + planet.render(surf) diff --git a/src/platformer/constants.py b/src/platformer/constants.py new file mode 100644 index 0000000..76b1435 --- /dev/null +++ b/src/platformer/constants.py @@ -0,0 +1,13 @@ +# Declare some constants and variables + +WIDTH, HEIGHT = (600, 400) +FPS = 60 +BLACK = "#000000" +DARKGRAY = "#404040" +GRAY = "#808080" +LIGHTGRAY = "#d3d3d3" +WHITE = "#FFFFFF" +ORANGE = "#FF6600" +RED = "#FF1F00" +PURPLE = "#800080" +DARKPURPLE = "#301934" diff --git a/src/platformer/level.json b/src/platformer/level.json new file mode 100644 index 0000000..9593b89 --- /dev/null +++ b/src/platformer/level.json @@ -0,0 +1 @@ +{"level":[["ground",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"ground","ground"],["ground",null,null,null,"ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground",null,null,null,null,null,null,"ground",null,null,"ground",null,"ground",null,null,"ground","ground","ground",null,null,null,null,null,"ground"],["ground",null,null,null,"ground",null,null,null,null,null,null,null,null,null,null,null,"ground",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"ground",null,null,null,"ground"],["ground",null,null,null,"ground",null,null,null,null,null,null,null,null,null,null,null,"ground",null,null,null,null,"ground",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"ground"],["ground","ground",null,null,null,null,null,null,null,"ground","ground","ground","ground",null,null,"ground","ground",null,null,null,"ground",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"ground"],["ground",null,"ground",null,null,null,"ground","ground","ground",null,null,null,null,null,null,null,null,null,null,"ground",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"ground"],["ground",null,null,null,null,null,null,null,"ground",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"ground"],["ground",null,null,"ground","ground",null,null,null,"ground",null,null,null,null,null,null,"ground","ground","ground",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"ground"],["ground",null,null,null,"ground",null,null,null,null,null,null,null,null,null,null,null,"ground","ground",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"ground"],["ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground","ground"]]} diff --git a/src/platformer/level_creator/constants.py b/src/platformer/level_creator/constants.py new file mode 100644 index 0000000..a71c09a --- /dev/null +++ b/src/platformer/level_creator/constants.py @@ -0,0 +1,13 @@ +# Declare some constants and variables + +WIDTH, HEIGHT = (800, 600) +FPS = 60 +BLACK = "#000000" +DARKGRAY = "#404040" +GRAY = "#808080" +LIGHTGRAY = "#d3d3d3" +WHITE = "#FFFFFF" +ORANGE = "#FF6600" +RED = "#FF1F00" +PURPLE = "#800080" +DARKPURPLE = "#301934" diff --git a/src/platformer/level_creator/file_editor.py b/src/platformer/level_creator/file_editor.py new file mode 100644 index 0000000..02d953c --- /dev/null +++ b/src/platformer/level_creator/file_editor.py @@ -0,0 +1,27 @@ +# JSON level reader + +import json, os + +# Read level +def read_level(): + # Open file from full path (just in case the script is being ran from somewhere other than py-games/src/platformer/level_creator) + file = open(os.path.join(os.path.dirname(__file__), os.pardir, "level.json"), "r") + # Python dict + try: + data = json.load(file) + except Exception: + print("Couldn't read level, data could be corrupted.") + # Close file + file.close() + # Return Python list + return data["level"] + + +# Write level +def write_level(data): + # Same as above... + file = open(os.path.join(os.path.dirname(__file__), os.pardir, "level.json"), "w") + # Write over file + file.write('{"level":' + json.dumps(data, separators=(",", ":")) + "}\n") + # Close file + file.close() diff --git a/src/platformer/level_creator/main.py b/src/platformer/level_creator/main.py new file mode 100644 index 0000000..a42acda --- /dev/null +++ b/src/platformer/level_creator/main.py @@ -0,0 +1,304 @@ +#!/usr/bin/python +""" +Github repo can be found here: +https://github.com/sparshg/py-games +""" + +# Import statements +from os import environ + +# Hide pygame Hello prompt +environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "1" +import pygame as pg + +import sys +from constants import * +from file_editor import * +from scrolling import * + +mouseDown = False +scrollX = 0 +scrollY = 0 +scrollVel = 1 +blockSize = 50 + +# The main controller +class Main: + def __init__(self): + pg.init() + pg.display.set_caption("Platformer Level Creator") + self.running = True + self.win = pg.display.set_mode((WIDTH, HEIGHT)) + self.menuBar = MenuBar() + self.selectedBlock = SelectedBlock() + self.platforms = Platforms() + + # For key press and close button functionality + def check_events(self): + global mouseDown + for event in pg.event.get(): + if event.type == pg.QUIT: + self.running = False + if event.type == pg.MOUSEBUTTONUP: + mouseDown = True + + # Update things + def update(self): + global scrollX, scrollY + self.menuBar.update() + self.selectedBlock.update() + scrollX = get_scroll_pos()[0] + scrollY = get_scroll_pos()[1] + keys = pg.key.get_pressed() + # Save on CTRL + S + if keys[pg.K_s] and (keys[pg.K_LCTRL] or keys[pg.K_RCTRL]): + write_level(main.platforms.platforms) + + # Draw things + def render(self): + self.win.fill(BLACK) + self.platforms.render() + self.menuBar.render() + self.selectedBlock.render() + pg.display.update() + + # The main loop + def loop(self): + global mouseDown + while self.running: + self.check_events() + self.update() + self.render() + mouseDown = False + pg.quit() + sys.exit() + + +# Menu bar buttons +class MenuButton: + def __init__(self, renFun, side, id): + self.renFun = renFun + self.side = side + self.id = id + + +# Button 1 (ground) +def ren_btn1(x, y): + pg.draw.rect( + main.win, + DARKPURPLE, + ( + x + main.menuBar.height / 4, + y + main.menuBar.height / 4, + main.menuBar.height / 2, + main.menuBar.height / 2, + ), + ) + + +btn1 = MenuButton(ren_btn1, "lt", "ground") + + +# Button 2 (air/clear) +def ren_btn2(x, y): + # Draw red X + pg.draw.line( + main.win, + RED, + (x + main.menuBar.height / 4, y + main.menuBar.height / 4), + ( + x + main.menuBar.height - main.menuBar.height / 4, + y + main.menuBar.height - main.menuBar.height / 4, + ), + 10, + ) + pg.draw.line( + main.win, + RED, + ( + x + main.menuBar.height - main.menuBar.height / 4, + y + main.menuBar.height / 4, + ), + ( + x + main.menuBar.height / 4, + y + main.menuBar.height - main.menuBar.height / 4, + ), + 10, + ) + + +btn2 = MenuButton(ren_btn2, "lt", None) + + +# Button 3 (the save button) +def ren_btn3(x, y): + font = pg.font.SysFont("Segoe UI", 25) + surf = font.render("Save", 1, BLACK) + main.win.blit( + surf, + ( + x + main.menuBar.height / 2 - font.size("Save")[0] / 2, + y + main.menuBar.height / 2 - font.size("Save")[1] / 2, + ), + ) + + +btn3 = MenuButton(ren_btn3, "rt", "SAVE") + + +# Menu bar +class MenuBar: + def __init__(self): + global scrollY + self.width = WIDTH + self.height = 75 + + self.buttonClicked = None + self.buttons = [btn1, btn2, btn3] + + # Update bar + def update(self): + if self.buttonClicked != None: + main.selectedBlock.quit_selection() + main.selectedBlock.select_block(self.buttons[self.buttonClicked].id) + self.buttonClicked = None + + # Draw bar + def render(self): + # Current X + ltX = 0 + rtX = self.width - self.height + # Background + pg.draw.rect(main.win, LIGHTGRAY, (0, 0, self.width, self.height)) + # Buttons + for i in range(len(self.buttons)): + # If on right side + if self.buttons[i].side == "lt": + if pg.Rect(ltX, 0, self.height, self.height).collidepoint( + pg.mouse.get_pos() + ): + if pg.mouse.get_pressed()[0]: + pg.draw.rect( + main.win, DARKGRAY, (ltX, 0, self.height, self.height) + ) + else: + pg.draw.rect(main.win, GRAY, (ltX, 0, self.height, self.height)) + if mouseDown: + self.buttonClicked = i + self.buttons[i].renFun(ltX, 0) + ltX += self.height + # if on left side + elif self.buttons[i].side == "rt": + if pg.Rect(rtX, 0, self.height, self.height).collidepoint( + pg.mouse.get_pos() + ): + if pg.mouse.get_pressed()[0]: + pg.draw.rect( + main.win, DARKGRAY, (rtX, 0, self.height, self.height) + ) + else: + pg.draw.rect(main.win, GRAY, (rtX, 0, self.height, self.height)) + if mouseDown: + self.buttonClicked = i + self.buttons[i].renFun(rtX, 0) + rtX -= self.height + + +# Block in hand +class SelectedBlock: + def __init__(self): + self.shown = False + self.blockId = False + + # Begin selection + def select_block(self, id): + self.quit_selection() + if id != "SAVE": + self.blockId = id + self.shown = True + else: + # Save level + write_level(main.platforms.platforms) + + # Drop item in hand + def quit_selection(self): + self.blockId = False + self.shown = False + + # Place block in desired location + def place_block(self): + global scrollX, scrollY + # Collumn + y = (pg.mouse.get_pos()[1] + scrollY) // blockSize + # Cell + x = (pg.mouse.get_pos()[0] + scrollX) // blockSize + # Check if tile exists + def place(): + if y < len(main.platforms.platforms): + if x < len(main.platforms.platforms[y]): + main.platforms.platforms[y][x] = self.blockId + else: + for i in range(x - len(main.platforms.platforms[y])): + main.platforms.platforms[y].append(None) + main.platforms.platforms[y].insert(x, self.blockId) + else: + for i in range(y - len(main.platforms.platforms)): + main.platforms.platforms.append( + [None] * len(main.platforms.platforms) + ) + row = [None] * len(main.platforms.platforms[y - 1]) + row[x] = self.blockId + main.platforms.platforms.append(row) + + place() + # If pressing SHIFT key, don't unselect + if ( + not pg.key.get_pressed()[pg.K_LSHIFT] + and not pg.key.get_pressed()[pg.K_RSHIFT] + ): + self.quit_selection() + + # Update self + def update(self): + if self.shown and mouseDown: + self.place_block() + + # Draw self + def render(self): + if self.shown: + for i in range(len(main.menuBar.buttons)): + if main.menuBar.buttons[i].id == self.blockId: + main.menuBar.buttons[i].renFun( + pg.mouse.get_pos()[0] - main.menuBar.height / 2, + pg.mouse.get_pos()[1] - main.menuBar.height / 2, + ) + break + + +# Level to be rendered +class Platforms: + def __init__(self): + self.platforms = read_level() + + # Render + def render(self): + global scrollX, scrollY + for i in range(len(self.platforms)): + for j in range(len(self.platforms[i])): + if self.platforms[i][j] == "ground": + pg.draw.rect( + main.win, + DARKPURPLE, + ( + j * blockSize - scrollX, + i * blockSize - scrollY, + blockSize, + blockSize, + ), + ) + + +# Test if the script is directly ran +if __name__ == "__main__": + main = Main() + main.loop() diff --git a/src/platformer/level_creator/scrolling.py b/src/platformer/level_creator/scrolling.py new file mode 100644 index 0000000..c9c56a5 --- /dev/null +++ b/src/platformer/level_creator/scrolling.py @@ -0,0 +1,18 @@ +# Scrolling mechanism + +import pygame as pg +from main import scrollX, scrollY, scrollVel + + +def get_scroll_pos(): + global scrollX, scrollY, scrollVel + keys = pg.key.get_pressed() + if keys[pg.K_UP]: + scrollY -= scrollVel + if keys[pg.K_DOWN]: + scrollY += scrollVel + if keys[pg.K_RIGHT]: + scrollX += scrollVel + if keys[pg.K_LEFT]: + scrollX -= scrollVel + return (scrollX, scrollY) diff --git a/src/platformer/main.py b/src/platformer/main.py new file mode 100644 index 0000000..f56261d --- /dev/null +++ b/src/platformer/main.py @@ -0,0 +1,155 @@ +#!/usr/bin/python +""" +Github repo can be found here: +https://github.com/sparshg/py-games +""" + +# Import statements +from os import environ + +# Hide pygame Hello prompt +environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "1" +import pygame as pg +import sys, random + +import physics +from constants import * +from player import Player +from platforms import Platforms + +# The main controller +class Main: + def __init__(self): + pg.init() + pg.display.set_caption("Platformer") + + self.running = True + self.win = pg.display.set_mode((WIDTH, HEIGHT)) + self.platforms = Platforms() + self.player = Player() + self.bgEnts = BgEnts() + self.clock = pg.time.Clock() + self.clock.tick() + + # For key press and close button functionality + def check_events(self): + for event in pg.event.get(): + if event.type == pg.QUIT: + self.running = False + + # Update things + def update(self): + self.bgEnts.update() + self.player.update(self.platforms.rects) + + # Draw things + def render(self): + self.win.fill(BLACK) + self.bgEnts.render() + self.platforms.render(self.win, self.player) + self.player.render(self.win) + pg.display.update() + + # The main loop + def loop(self): + while self.running: + self.check_events() + self.update() + self.render() + physics.dt = self.clock.tick(FPS) / 1000 + pg.quit() + sys.exit() + + +# Background objects +class BgEnts: + def __init__(self): + self.waves = self.Waves() + + # Update scene + def update(self): + self.waves.gen_waves() + self.waves.update() + + # Draw scene + def render(self): + self.waves.render() + + class Waves: + def __init__(self): + # Bigger num = less waves + # Smaller num = more waves + self.waveGenRate = 75 + # Bigger num = less thickness + # Smaller num = more thickness + self.waveThickness = 4 + + # Min/max wave size + self.minWaveSize = 10 + self.maxWaveSize = 35 + + # Min/max wave max life + self.minWaveLife = 25 + self.maxWaveLife = 125 + + # Min/max wave speed + self.minWaveSpeed = 10 + self.maxWaveSpeed = 35 + + self.waves = [] + + # Wave class + class Wave: + def __init__(self, x, y, life, speed): + self.x = x + self.y = y + self.life = life + self.speed = speed + self.frame = 0 + + # Generate waves randomly + def gen_waves(self): + if random.randint(0, self.waveGenRate) == self.waveGenRate: + self.waves.append( + self.Wave( + random.randint(0, WIDTH), + random.randint(0, HEIGHT), + random.randint(self.minWaveLife, self.maxWaveLife), + random.randint(self.minWaveSpeed, self.maxWaveSpeed), + ) + ) + + # Update waves + def update(self): + for i in range(len(self.waves)): + if self.waves[i].frame >= self.waves[i].life: + self.waves[i] = None + else: + self.waves[i].frame += 1 + # Remove empty list items + self.waves = list(filter(lambda item: item != None, self.waves)) + + # Render waves + def render(self): + for i in range(len(self.waves)): + # Use surface since pg.draw.circle doesn't support transparency + surf = pg.Surface((WIDTH, HEIGHT), pg.SRCALPHA, 32) + pg.draw.circle( + surf, + ( + # Convert hex code to RGB tuple then add allpha channel + tuple(int(PURPLE.lstrip("#")[i : i + 2], 16) for i in (0, 2, 4)) + # Alpha channel, set according to frame of wave + + (255 - 255 / self.waves[i].life * self.waves[i].frame,) + ), + (self.waves[i].x, self.waves[i].y), + self.waves[i].frame, + int(self.waves[i].frame / self.waveThickness), + ) + main.win.blit(surf, (0, 0)) + + +# Test if the script is directly ran +if __name__ == "__main__": + main = Main() + main.loop() diff --git a/src/platformer/physics.py b/src/platformer/physics.py new file mode 100644 index 0000000..c2c3006 --- /dev/null +++ b/src/platformer/physics.py @@ -0,0 +1,10 @@ +# Physics settings + +from constants import FPS + +dt = 1 / FPS +gravity = 1800 +jumpHeight = -750 +friction = 1800 +xAcc = 3600 +maxXVel = 480 diff --git a/src/platformer/platformer.py b/src/platformer/platformer.py deleted file mode 100644 index 56dd980..0000000 --- a/src/platformer/platformer.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/python -""" -Github repo can be found here: -https://github.com/sparshg/pycollab -""" - -import pygame as pg -from os import environ - -# Hide pygame Hello prompt -environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "1" - -# Declare some constants and variables -WIDTH, HEIGHT = (600, 400) -FPS = 60 -BLACK = (0 , 0 , 0 ) -WHITE = (255, 255, 255) - -# The main controller -class Main: - def __init__(self): - pg.init() - pg.display.set_caption("Platformer") - - self.running = True - self.clock = pg.time.Clock() - self.win = pg.display.set_mode((WIDTH, HEIGHT)) - - def check_events(self): - for event in pg.event.get(): - if event.type == pg.QUIT: - main.running = False - - # Update things - def update(self): - player.yVel += physics.gravity - player.y += player.yVel - if player.colliding(): - while player.colliding(): - if player.yVel < 0: - pass - elif player.yVel > 0: - pass - yVel = 0 - - # Draw things - def draw(self): - self.win.fill(BLACK) - player.render() - platforms.render() - pg.display.update() - - # The main loop - def loop(self): - while self.running: - self.check_events() - self.update() - self.draw() - self.clock.tick(FPS) - pg.quit() -main = Main() - -class Physics: - def __init__(self): - self.gravity = 2 - self.jumpHeight = 18 - self.friction = 2 - self.acceleration = 4 - - def squareCollision(x1, y1, w1, h1, x2, y2, w2, h2): - return ((x1 + w1 > x2) and ( x1 < x2 + w2)) and ((y1 + h1 > y2) and ( y1 < y2 + h2)) -physics = Physics() - -class Player: - def __init__(self): - self.x = 0 - self.y = 0 - self.xVel = 0 - self.yVel = 0 - - def render(self): - pg.draw.rect(main.win, WHITE, (self.x, self.y, 50, 50)) - - def colliding(self): - pass -player = Player() - -class Platforms: - def __init__(self): - self.platforms = [] - - def render(self): - for i in range(len(self.platforms)): - pg.draw.rect(main.win, WHITE, (self.platforms[i].x, self.platforms[i].y, 75, 75)) -platforms = Platforms() - -# Test if the script is directly ran -if __name__ == "__main__": - main.loop() diff --git a/src/platformer/platforms.py b/src/platformer/platforms.py new file mode 100644 index 0000000..3e5eeca --- /dev/null +++ b/src/platformer/platforms.py @@ -0,0 +1,41 @@ +import pygame as pg +from read_level import * +from constants import * + + +class Platform: + def __init__(self, x, y, w, h, type="ground"): + self.x = x + self.y = y + self.w = w + self.h = h + self.type = type + + +# Platforms +class Platforms: + def __init__(self): + p = "ground" + _ = "_" + self.rects = [] + self.layout = read_level() + + # Convert JSON data to Python list + for i in range(len(self.layout)): + for j in range(len(self.layout[i])): + if self.layout[i][j] == p: + self.rects.append(Platform(j * 50, i * 50, 50, 50)) + + # Render platforms + def render(self, win, player): + for rect in self.rects: + pg.draw.rect( + win, + DARKPURPLE, + ( + rect.x - player.pos.x - int(player.width / 2) + WIDTH / 2, + rect.y - player.pos.y - int(player.height / 2) + HEIGHT / 2, + rect.w, + rect.h, + ), + ) diff --git a/src/platformer/player.py b/src/platformer/player.py new file mode 100644 index 0000000..d413afe --- /dev/null +++ b/src/platformer/player.py @@ -0,0 +1,123 @@ +import pygame as pg +import physics +from constants import * + + +class Player: + def __init__(self): + self.pos = pg.Vector2(250, 300) + self.vel = pg.Vector2(0, 0) + self.onGround = True + self.prevPositions = [] + self.width = 40 + self.height = 40 + self.trailPower = 2 + + # Check col with ground + def colliding(self, rects): + for platform in rects: + if pg.Rect(self.pos.x, self.pos.y, self.width, self.height).colliderect( + pg.Rect(platform.x, platform.y, platform.w, platform.h) + ): + return True + return False + + # Update player + def update(self, plats): + + # Get keys + keyDown = pg.key.get_pressed() + + if self.onGround: + if keyDown[pg.K_UP]: + self.vel.y = physics.jumpHeight + self.onGround = False + if not self.colliding(plats): + self.onGround = False + else: + self.vel.y += physics.gravity * physics.dt + self.pos.y += self.vel.y * physics.dt + + if self.colliding(plats): + if self.vel.y > 0: + while self.colliding(plats): + self.pos.y -= 0.5 + self.vel.y = 0 + self.onGround = True + else: + while self.colliding(plats): + self.pos.y += 0.5 + self.vel.y = physics.gravity * physics.dt + + # Right + if keyDown[pg.K_RIGHT]: + self.vel.x += physics.xAcc * physics.dt + if self.vel.x > physics.maxXVel: + self.vel.x = physics.maxXVel + + # Left + if keyDown[pg.K_LEFT]: + self.vel.x -= physics.xAcc * physics.dt + if -self.vel.x > physics.maxXVel: + self.vel.x = -physics.maxXVel + + # Apply friction + if self.vel.x < 0: + self.vel.x += physics.friction * physics.dt + if self.vel.x > 0: + self.vel.x = 0 + elif self.vel.x > 0: + self.vel.x -= physics.friction * physics.dt + if self.vel.x < 0: + self.vel.x = 0 + + # Wall collision + self.pos.x += self.vel.x * physics.dt + if self.colliding(plats): + while self.colliding(plats): + if self.vel.x > 0: + self.pos.x -= 0.5 + else: + self.pos.x += 0.5 + self.vel.x = 0 + + # Trail + self.prevPositions.insert(0, pg.Vector2(self.pos.x, self.pos.y)) + if len(self.prevPositions) > self.width / 2: + self.prevPositions.pop(len(self.prevPositions) - 1) + + # Render player + def render(self, win): + + # Render trail + for i in range(len(self.prevPositions)): + pg.draw.rect( + win, + ORANGE, + ( + WIDTH / 2 + - self.width / 4 + - self.pos.x + + self.prevPositions[i].x + + i * self.trailPower / 2, + HEIGHT / 2 + - self.height / 4 + - self.pos.y + + self.prevPositions[i].y + + i * self.trailPower / 2, + self.width / 2 - i * self.trailPower, + self.height / 2 - i * self.trailPower, + ), + ) + + # Render player + pg.draw.rect( + win, + RED, + ( + WIDTH / 2 - self.width / 2, + HEIGHT / 2 - self.height / 2, + self.width, + self.height, + ), + ) diff --git a/src/platformer/read_level.py b/src/platformer/read_level.py new file mode 100644 index 0000000..9cdef43 --- /dev/null +++ b/src/platformer/read_level.py @@ -0,0 +1,12 @@ +# JSON level reader + +import json, os + +# Read level +def read_level(): + # Open file from full path (just in case the script is being ran from somewhere other than py-games/src/platformer) + file = open("level.json", "r") + # Python dict + data = json.load(file) + # Return Python list + return data["level"] diff --git a/src/tictactoe/constants.py b/src/tictactoe/constants.py new file mode 100644 index 0000000..2830ea8 --- /dev/null +++ b/src/tictactoe/constants.py @@ -0,0 +1,7 @@ +# Declare some constants and variables +WIDTH, HEIGHT = (600, 400) +FPS = 60 +WHITE = "#F1F1F1" +BLACK = "#101010" +ORANGE = "#FF6600" +RED = "#FF1F00" \ No newline at end of file diff --git a/src/tictactoe/tictactoe.py b/src/tictactoe/main.py old mode 100755 new mode 100644 similarity index 79% rename from src/tictactoe/tictactoe.py rename to src/tictactoe/main.py index 21d2150..82302bd --- a/src/tictactoe/tictactoe.py +++ b/src/tictactoe/main.py @@ -1,23 +1,17 @@ #!/usr/bin/python """ Github repo can be found here: -https://github.com/sparshg/pycollab +https://github.com/sparshg/py-games """ + +# Import statements from os import environ -import math # Hide pygame Hello prompt environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "1" -import pygame -from pygame.math import Vector2 +import pygame as pg -# Declare some constants and variables -WIDTH, HEIGHT = (600, 400) -FPS = 60 -WHITE = "#F1F1F1" -BLACK = "#101010" -ORANGE = "#FF6600" -RED = "#FF1F00" +from constants import * class Frame: @@ -41,7 +35,7 @@ def __init__(self, gap=110): for i in range(3): for j in range(3): self.rects.append( - pygame.Rect((-1.5 + 1 * j) * gap, (1.5 - 1 * i) * gap, gap, gap) + pg.Rect((-1.5 + 1 * j) * gap, (1.5 - 1 * i) * gap, gap, gap) ) self.rects = self.cartesian_to_standard(self.rects) @@ -84,7 +78,7 @@ def reset(): if n is not None: n.wait_and_remove = True n.remove_time = ( - 2 * n.blink_count * n.blink_dur + pygame.time.get_ticks() + 2 * n.blink_count * n.blink_dur + pg.time.get_ticks() ) def check(sum, i, j): @@ -99,7 +93,7 @@ def check(sum, i, j): if j is None: j = t self.moves[i][j].blink = True - self.moves[i][j].blink_start = pygame.time.get_ticks() + self.moves[i][j].blink_start = pg.time.get_ticks() i, j = prev reset() @@ -123,7 +117,7 @@ def check(sum, i, j): def setup_remove(self, dur=500, animate=False): if not self.remove: self.remove = True - self.remove_time = pygame.time.get_ticks() + dur + self.remove_time = pg.time.get_ticks() + dur if animate: for i in self.animations: i.setup_remove(dur) @@ -136,7 +130,7 @@ def draw(self): if move is not None: move.draw() if self.remove: - if pygame.time.get_ticks() > self.remove_time: + if pg.time.get_ticks() > self.remove_time: main.reset() @@ -158,10 +152,10 @@ def __init__(self, _type, center): def draw(self): if self.blink: - if pygame.time.get_ticks() < self.blink_start + self.blink_dur: + if pg.time.get_ticks() < self.blink_start + self.blink_dur: self.animation.update() - elif pygame.time.get_ticks() > self.blink_start + 2 * self.blink_dur: - self.blink_start = pygame.time.get_ticks() + elif pg.time.get_ticks() > self.blink_start + 2 * self.blink_dur: + self.blink_start = pg.time.get_ticks() self.blink_count -= 1 if self.blink_count == 0: self.blink = False @@ -169,7 +163,7 @@ def draw(self): self.animation.update() if self.wait_and_remove: - if pygame.time.get_ticks() > self.remove_time: + if pg.time.get_ticks() > self.remove_time: self.animation.setup_remove() main.frame.setup_remove() self.wait_and_remove = False @@ -191,7 +185,7 @@ def __init__(self, dur=500, color=WHITE, fn=EASE_OUT_QUART): self.function = fn self.remove = False self.dur = dur - self.start_time = pygame.time.get_ticks() + self.start_time = pg.time.get_ticks() self.final_time = self.start_time + dur self.type = None self.sub_animations = None @@ -200,8 +194,8 @@ def line(self, p1, p2, width=8): self.type = "line" self.finished = False self.width = width - self.p1 = Vector2(p1) - self.p2 = Vector2(p2) + self.p1 = pg.Vector2(p1) + self.p2 = pg.Vector2(p2) self.p = self.p2 - self.p1 self.length = self.p.magnitude() return self @@ -212,9 +206,9 @@ def circle(self, center=[WIDTH / 2, HEIGHT / 2], radius=38, width=8): self.width = width self.radius = radius self.r = radius - self.center = Vector2(center) - self.rect = pygame.Rect( - (center - Vector2(radius, radius)), (2 * radius, 2 * radius) + self.center = pg.Vector2(center) + self.rect = pg.Rect( + (center - pg.Vector2(radius, radius)), (2 * radius, 2 * radius) ) return self @@ -222,12 +216,12 @@ def cross(self, center=[WIDTH / 2, HEIGHT / 2], length=40, width=10): self.type = "cross" # fmt: off points = [ - Vector2(-length, 0), Vector2(length, 0), - Vector2(0, length), Vector2(0, -length) + pg.Vector2(-length, 0), pg.Vector2(length, 0), + pg.Vector2(0, length), pg.Vector2(0, -length) ] # fmt: on for point in points: - point.update(point.rotate(45) + Vector2(center)) + point.update(point.rotate(45) + pg.Vector2(center)) self.sub_animations = [ Animate(self.dur + i * 150, self.color, self.function).line( @@ -241,7 +235,7 @@ def setup_remove(self, dur=500): self.finished = True self.remove = True self.dur = dur - self.start_time = pygame.time.get_ticks() + self.start_time = pg.time.get_ticks() self.final_time = self.start_time + self.dur if self.sub_animations is not None: for i in self.sub_animations: @@ -257,8 +251,8 @@ def update(self, skip=False): # Calculate the animation if not self.finished or self.remove: - if pygame.time.get_ticks() < self.final_time and not skip: - fraction = (pygame.time.get_ticks() - self.start_time) / self.dur + if pg.time.get_ticks() < self.final_time and not skip: + fraction = (pg.time.get_ticks() - self.start_time) / self.dur if fraction < 0.01: fraction += 0.008 @@ -283,37 +277,35 @@ def update(self, skip=False): # Draw stuff if self.type == "line": - pygame.draw.line( - main.win, self.color, self.p1, self.p + self.p1, self.width - ) + pg.draw.line(main.win, self.color, self.p1, self.p + self.p1, self.width) elif self.type == "circle": - pygame.draw.circle(main.win, self.color, self.center, self.radius) - pygame.draw.circle(main.win, BLACK, self.center, self.r) + pg.draw.circle(main.win, self.color, self.center, self.radius) + pg.draw.circle(main.win, BLACK, self.center, self.r) # The main controller class Main: def __init__(self): - pygame.init() - pygame.display.set_caption("Tic-Tac-Toe") + pg.init() + pg.display.set_caption("Tic-Tac-Toe") - self.win = pygame.display.set_mode((WIDTH, HEIGHT)) + self.win = pg.display.set_mode((WIDTH, HEIGHT)) self.running = True self.frame = Frame() - self.clock = pygame.time.Clock() + self.clock = pg.time.Clock() def check_events(self): - for event in pygame.event.get(): - if event.type == pygame.QUIT: + for event in pg.event.get(): + if event.type == pg.QUIT: main.running = False - if event.type == pygame.MOUSEBUTTONUP: - self.frame.detect_click(pygame.mouse.get_pos()) + if event.type == pg.MOUSEBUTTONUP: + self.frame.detect_click(pg.mouse.get_pos()) def draw(self): self.win.fill(BLACK) self.frame.draw() - pygame.display.update() + pg.display.update() def reset(self): self.frame = Frame() @@ -324,7 +316,7 @@ def loop(self): self.check_events() self.draw() self.clock.tick(FPS) - pygame.quit() + pg.quit() # Test if the script is directly ran