From: Skullheadx <704277@pdsb.net> Date: Sun, 10 Jul 2022 01:40:28 +0000 (-0400) Subject: Revert "Revert "Merge branch 'main' into other-computer"" X-Git-Url: http://git.skullheadx.com/nixos/static/gitweb.js?a=commitdiff_plain;h=refs%2Fheads%2Fother-computer;p=Pygame-Jam.git Revert "Revert "Merge branch 'main' into other-computer"" This reverts commit 48a0136a464c672409a9a3132d085cd592039815. --- diff --git a/.gitignore b/.gitignore index 3f26c87..68aac71 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,6 @@ ignore_* /ignore */__pycache__ +Save/SaveData.txt +/.idea .idea/Pygame-Jam-main.iml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/Assets/ARROW.png b/Assets/ARROW.png new file mode 100644 index 0000000..d79c4e0 Binary files /dev/null and b/Assets/ARROW.png differ diff --git a/Assets/BOW.png b/Assets/BOW.png new file mode 100644 index 0000000..74435e7 Binary files /dev/null and b/Assets/BOW.png differ diff --git a/Assets/BOW_PULLED.png b/Assets/BOW_PULLED.png new file mode 100644 index 0000000..0bfe625 Binary files /dev/null and b/Assets/BOW_PULLED.png differ diff --git a/Assets/FLINTLOCK_PISTOL.png b/Assets/FLINTLOCK_PISTOL.png new file mode 100644 index 0000000..4f6dafa Binary files /dev/null and b/Assets/FLINTLOCK_PISTOL.png differ diff --git a/Assets/GrassBlock.png b/Assets/GrassBlock.png deleted file mode 100644 index b4a37fc..0000000 Binary files a/Assets/GrassBlock.png and /dev/null differ diff --git a/Assets/player/idle/Idle_Animation1.png b/Assets/player/idle/Idle_Animation1.png new file mode 100644 index 0000000..1bae45a Binary files /dev/null and b/Assets/player/idle/Idle_Animation1.png differ diff --git a/Assets/player/idle/Idle_Animation10.png b/Assets/player/idle/Idle_Animation10.png new file mode 100644 index 0000000..428c4e0 Binary files /dev/null and b/Assets/player/idle/Idle_Animation10.png differ diff --git a/Assets/player/idle/Idle_Animation11.png b/Assets/player/idle/Idle_Animation11.png new file mode 100644 index 0000000..cae952a Binary files /dev/null and b/Assets/player/idle/Idle_Animation11.png differ diff --git a/Assets/player/idle/Idle_Animation12.png b/Assets/player/idle/Idle_Animation12.png new file mode 100644 index 0000000..ee56a60 Binary files /dev/null and b/Assets/player/idle/Idle_Animation12.png differ diff --git a/Assets/player/idle/Idle_Animation13.png b/Assets/player/idle/Idle_Animation13.png new file mode 100644 index 0000000..b2e1016 Binary files /dev/null and b/Assets/player/idle/Idle_Animation13.png differ diff --git a/Assets/player/idle/Idle_Animation14.png b/Assets/player/idle/Idle_Animation14.png new file mode 100644 index 0000000..b2e1016 Binary files /dev/null and b/Assets/player/idle/Idle_Animation14.png differ diff --git a/Assets/player/idle/Idle_Animation15.png b/Assets/player/idle/Idle_Animation15.png new file mode 100644 index 0000000..b378f5e Binary files /dev/null and b/Assets/player/idle/Idle_Animation15.png differ diff --git a/Assets/player/idle/Idle_Animation16.png b/Assets/player/idle/Idle_Animation16.png new file mode 100644 index 0000000..e36b0cb Binary files /dev/null and b/Assets/player/idle/Idle_Animation16.png differ diff --git a/Assets/player/idle/Idle_Animation17.png b/Assets/player/idle/Idle_Animation17.png new file mode 100644 index 0000000..24026d8 Binary files /dev/null and b/Assets/player/idle/Idle_Animation17.png differ diff --git a/Assets/player/idle/Idle_Animation18.png b/Assets/player/idle/Idle_Animation18.png new file mode 100644 index 0000000..4fa5a85 Binary files /dev/null and b/Assets/player/idle/Idle_Animation18.png differ diff --git a/Assets/player/idle/Idle_Animation19.png b/Assets/player/idle/Idle_Animation19.png new file mode 100644 index 0000000..cae952a Binary files /dev/null and b/Assets/player/idle/Idle_Animation19.png differ diff --git a/Assets/player/idle/Idle_Animation2.png b/Assets/player/idle/Idle_Animation2.png new file mode 100644 index 0000000..428c4e0 Binary files /dev/null and b/Assets/player/idle/Idle_Animation2.png differ diff --git a/Assets/player/idle/Idle_Animation20.png b/Assets/player/idle/Idle_Animation20.png new file mode 100644 index 0000000..cae952a Binary files /dev/null and b/Assets/player/idle/Idle_Animation20.png differ diff --git a/Assets/player/idle/Idle_Animation3.png b/Assets/player/idle/Idle_Animation3.png new file mode 100644 index 0000000..428c4e0 Binary files /dev/null and b/Assets/player/idle/Idle_Animation3.png differ diff --git a/Assets/player/idle/Idle_Animation4.png b/Assets/player/idle/Idle_Animation4.png new file mode 100644 index 0000000..428c4e0 Binary files /dev/null and b/Assets/player/idle/Idle_Animation4.png differ diff --git a/Assets/player/idle/Idle_Animation5.png b/Assets/player/idle/Idle_Animation5.png new file mode 100644 index 0000000..428c4e0 Binary files /dev/null and b/Assets/player/idle/Idle_Animation5.png differ diff --git a/Assets/player/idle/Idle_Animation6.png b/Assets/player/idle/Idle_Animation6.png new file mode 100644 index 0000000..428c4e0 Binary files /dev/null and b/Assets/player/idle/Idle_Animation6.png differ diff --git a/Assets/player/idle/Idle_Animation7.png b/Assets/player/idle/Idle_Animation7.png new file mode 100644 index 0000000..428c4e0 Binary files /dev/null and b/Assets/player/idle/Idle_Animation7.png differ diff --git a/Assets/player/idle/Idle_Animation8.png b/Assets/player/idle/Idle_Animation8.png new file mode 100644 index 0000000..428c4e0 Binary files /dev/null and b/Assets/player/idle/Idle_Animation8.png differ diff --git a/Assets/player/idle/Idle_Animation9.png b/Assets/player/idle/Idle_Animation9.png new file mode 100644 index 0000000..428c4e0 Binary files /dev/null and b/Assets/player/idle/Idle_Animation9.png differ diff --git a/Assets/world/blocks/DIRT.png b/Assets/world/blocks/DIRT.png new file mode 100644 index 0000000..4998792 Binary files /dev/null and b/Assets/world/blocks/DIRT.png differ diff --git a/Assets/world/blocks/ENEMY.png b/Assets/world/blocks/ENEMY.png new file mode 100644 index 0000000..7ab0889 Binary files /dev/null and b/Assets/world/blocks/ENEMY.png differ diff --git a/Assets/world/blocks/GRASS.png b/Assets/world/blocks/GRASS.png new file mode 100644 index 0000000..4ec4647 Binary files /dev/null and b/Assets/world/blocks/GRASS.png differ diff --git a/Assets/LEAFS1.png b/Assets/world/blocks/LEAF.png similarity index 100% rename from Assets/LEAFS1.png rename to Assets/world/blocks/LEAF.png diff --git a/Assets/LEAFS.png b/Assets/world/blocks/LEAFS.png similarity index 100% rename from Assets/LEAFS.png rename to Assets/world/blocks/LEAFS.png diff --git a/Assets/world/blocks/NONE.png b/Assets/world/blocks/NONE.png new file mode 100644 index 0000000..835725e Binary files /dev/null and b/Assets/world/blocks/NONE.png differ diff --git a/Assets/world/blocks/PLACEHOLDER.png b/Assets/world/blocks/PLACEHOLDER.png new file mode 100644 index 0000000..a5379e2 Binary files /dev/null and b/Assets/world/blocks/PLACEHOLDER.png differ diff --git a/Assets/world/blocks/PLAYER.png b/Assets/world/blocks/PLAYER.png new file mode 100644 index 0000000..59817c8 Binary files /dev/null and b/Assets/world/blocks/PLAYER.png differ diff --git a/Assets/world/blocks/SAND.png b/Assets/world/blocks/SAND.png new file mode 100644 index 0000000..22da885 Binary files /dev/null and b/Assets/world/blocks/SAND.png differ diff --git a/Assets/StoneBlock.png b/Assets/world/blocks/STONE.png similarity index 100% rename from Assets/StoneBlock.png rename to Assets/world/blocks/STONE.png diff --git a/Assets/world/blocks/STONEDIRT.png b/Assets/world/blocks/STONEDIRT.png new file mode 100644 index 0000000..8d253bd Binary files /dev/null and b/Assets/world/blocks/STONEDIRT.png differ diff --git a/Assets/TREEBARK.png b/Assets/world/blocks/TREEBARK.png similarity index 100% rename from Assets/TREEBARK.png rename to Assets/world/blocks/TREEBARK.png diff --git a/Assets/Water.png b/Assets/world/blocks/WATER.png similarity index 100% rename from Assets/Water.png rename to Assets/world/blocks/WATER.png diff --git a/Assets/world/decor/BLUE_CRYSTAL.png b/Assets/world/decor/BLUE_CRYSTAL.png new file mode 100644 index 0000000..3911548 Binary files /dev/null and b/Assets/world/decor/BLUE_CRYSTAL.png differ diff --git a/Assets/world/decor/PURPLE_CRYSTAL.png b/Assets/world/decor/PURPLE_CRYSTAL.png new file mode 100644 index 0000000..cb927a1 Binary files /dev/null and b/Assets/world/decor/PURPLE_CRYSTAL.png differ diff --git a/Block.py b/Block.py index 6e77b19..89bcf03 100644 --- a/Block.py +++ b/Block.py @@ -2,20 +2,27 @@ from Setup import * class Block: - width, height = SCREEN_WIDTH, 50 + textures = {file[:file.index(".")]:pg.transform.scale( + pg.image.load(path.join("Assets/world/blocks", file)), (50, 50)) for + file in listdir("Assets/world/blocks")} + width, height = textures["PLACEHOLDER"].get_size() colour = (71, 77, 97) - def __init__(self, pos, collision_layer): + def __init__(self, pos, collision_layer, texture="PLACEHOLDER"): self.position = pg.Vector2(pos) self.velocity = pg.Vector2(0,0) # So that we may have moving blocks collision_layer.add(self) + self.texture = self.textures[texture] + self.movable = False def update(self, delta): - pass # when player "moves", it's actually the blocks + pass def get_collision_rect(self): return pg.Rect(self.position, (self.width, self.height)) + def draw(self, surf): - pg.draw.rect(surf, self.colour, get_display_rect(self.get_collision_rect()), border_radius=5) + pg.draw.rect(surf, self.colour, get_display_rect(self.get_collision_rect()), border_radius=3) + surf.blit(self.texture, get_display_rect(self.get_collision_rect())) diff --git a/DevLevelSelect.py b/DevLevelSelect.py new file mode 100644 index 0000000..0aa19ae --- /dev/null +++ b/DevLevelSelect.py @@ -0,0 +1,80 @@ +from Setup import * +from CommonImports.colours import black +from Function.createText import createText + +from Game import Game +from Test import Test +from LevelCreator import LevelCreator +from MainMenu import Menu + +class DevLevelSelect: + + def __init__(self): + self.texts = [] + X = 250 + self.texts.append(createText(X, 100, 32, black, "Bold", "DEVELOPER LEVEL SELECT",)) + self.texts.append(createText(X, 250, 24, black, "Regular", "MainMenu")) + self.texts.append(createText(X, 350, 24, black, "Regular", "Game")) + self.texts.append(createText(X, 450, 24, black, "Regular", "LevelCreator")) + self.texts.append(createText(X, 550, 24, black, "Regular", "AutoLoad [-]")) + + self.autoload = False + + try: + f = open("./Save/ignore_DevAutoload.txt", "x") + except: + f = open("./Save/ignore_DevAutoload.txt", "w") + try: + lines = f.readlines() + except: + pass; + f.close() + try: + self.level = int(lines[0]) + except: + self.level = -3 + + + def update(self, delta): + for ev in pg.event.get(): + if ev.type == pg.MOUSEBUTTONDOWN: + mouseX, mouseY = pg.mouse.get_pos() + for i in range(len(self.texts)): + x1 = self.texts[i][1][0] + y1 = self.texts[i][1][1] + x2 = x1 + self.texts[i][0].get_rect()[2] + y2 = y1 + self.texts[i][0].get_rect()[3] + + if (x1 <= mouseX <= x2 and y1 <= mouseY <= y2): + self.menuFunctions(i) + return + + def draw(self, surf): + screen.fill((255, 255, 255)) + for i in self.texts: + screen.blit(i[0], i[1]) + + def menuFunctions(self, num): + match num: + case 1: + self.level = 0 + case 2: + self.level = 1 + case 3: + self.level = -2 + case 4: + if(self.autoload == False): + self.texts[4] = createText(250, 550, 24, black, "Regular", "AutoLoad [x]") + self.autoload = True + else: + self.texts[4] = createText(250, 550, 24, black, "Regular", "AutoLoad [-]") + self.autoload = False + return; + + if(self.autoload == True): + try: + f = open("./Save/ignore_DevAutoload.txt", "x") + except: + f = open("./Save/ignore_DevAutoload.txt", "w") + f.write(str(self.level)) + f.close() diff --git a/EndScreen.py b/EndScreen.py new file mode 100644 index 0000000..aaecb36 --- /dev/null +++ b/EndScreen.py @@ -0,0 +1,44 @@ +from Setup import * +from CommonImports.colours import black +from Function.createText import createText + +class EndScreen: + + def __init__(self): + self.texts = [] + X = 250 + self.texts.append(createText(X, 100, 32, black, "Bold", "You Died",)) + self.texts.append(createText(X, 250, 24, black, "Regular", "Respawn")) + self.texts.append(createText(X, 350, 24, black, "Regular", "Options")) + self.texts.append(createText(X, 450, 24, black, "Regular", "Quit")) + + self.level = -1 + + + def update(self): + for ev in pg.event.get(): + if ev.type == pg.MOUSEBUTTONDOWN: + mouseX, mouseY = pg.mouse.get_pos() + for i in range(len(self.texts)): + x1 = self.texts[i][1][0] + y1 = self.texts[i][1][1] + x2 = x1 + self.texts[i][0].get_rect()[2] + y2 = y1 + self.texts[i][0].get_rect()[3] + + if (x1 <= mouseX <= x2 and y1 <= mouseY <= y2): + self.menuFunctions(i) + return + + def draw(self): + screen.fill((255, 255, 255)) + for i in self.texts: + screen.blit(i[0], i[1]) + + def menuFunctions(self, num): + match num: + case 1: + self.level = -1 + case 2: + print("Options") + case 3: + pg.quit(); diff --git a/LevelCreator.py b/LevelCreator.py new file mode 100644 index 0000000..920f9ed --- /dev/null +++ b/LevelCreator.py @@ -0,0 +1,404 @@ +import os +import numpy as np + +from Function.createText import createText +from Setup import * + +import tkinter as tk +from tkinter import filedialog + + +class LevelCreator: + canvas_layers = 5 + textures = [file[:file.index(".")] for file in listdir("Assets/world/blocks")] + textures.append("NONE") + + def __init__(self): + self.blocks = {"none": [[] for _ in range(self.canvas_layers)], + "world": [[] for _ in range(self.canvas_layers)]} + + self.grid = Grid() + + self.zoom = 1 + self.total_offset = pg.Vector2(0, 0) + self.world_transform = np.identity(3) + self.inv_world_transform = np.linalg.inv(self.world_transform) + + self.translation_matrix = np.array([[1, 0, self.total_offset.x], + [0, 1, self.total_offset.y], + [0, 0, 1]]) + self.translation_back_matrix = np.array([[1, 0, -self.total_offset.x], + [0, 1, -self.total_offset.y], + [0, 0, 1]]) + + self.current_texture = self.textures.index("PLACEHOLDER") + self.current_layer = 0 + self.show_grid = True + self.show_hitboxes = False + self.collision_layer = "world" + + self.buttons = [Button((0, 0), "Toggle Grid", self.toggle_grid), + Button((0, 0), "-Layer", self.decrease_layer), + Button((0, 0), f"{self.current_layer=}", self.upd_layer), + Button((0, 0), "+Layer", self.increase_layer), + Button((0, 0), f"{self.collision_layer=}", self.toggle_collidable), + Button((0, 0), "Toggle Hitboxes", self.toggle_show_hitboxes), + Button((0, 0), "Import", self.import_level), + Button((0, 0), "Export", self.export), + ] + + self.level = -2 + + def export(self): + # for layer in out: + # for i,block in enumerate(layer): + # layer[i] = Block(block.position,block.collision_layer,block.texture_name) + + counter = 1 + + def get_key(mask): + for key, value in self.blocks.items(): + if mask == value: + return key + + while True: + try: + with open(os.path.join("Levels", f'Level{counter}.txt'), 'x') as f: + out = "" + for layer in self.get_canvas_layers(): + t = "" + pos = "" + texture = "" + for block in layer: + t += f"{get_key(block.collision_layer)}|" + pos += f"{block.position.x},{block.position.y}|" + texture += f"{block.texture_name}|" + out += f"{t[:-1]}\n{pos[:-1]}\n{texture[:-1]}\n" + f.write(out) + + print(f"File saved as Level{counter} in folder Levels") + break + except FileExistsError: + counter += 1 + + def import_level(self): + root = tk.Tk() + root.withdraw() + + filename = filedialog.askopenfilename(initialdir="./Levels", title="Select A File", + filetypes=((".txt", "*.txt"), ("all files", "*.*"))) + if filename == '': + return + with open(filename, 'r', encoding='utf-8') as f: + file_contents = f.read().split("\n") + + # with open(path.join("Levels", f'Level{1}.txt'), 'r') as f: + # file_contents = f.read().split("\n") + + for i in range(0, len(file_contents) - 1, 3): + layer = file_contents[i].split("|") + pos = file_contents[i + 1].split("|") + texture = file_contents[i + 2].split("|") + + for l, p, t in zip(layer, pos, texture): + if p == "": + break + x, y = p.split(',') + self.add_block(self.apply_transformations((float(x), float(y))), self.blocks[l], t, i) + + def toggle_collidable(self): + if self.collision_layer == "none": + self.collision_layer = "world" + else: + self.collision_layer = "none" + button = self.buttons[4] + button.upd_text(button.position, f"{self.collision_layer=}") + + def toggle_show_hitboxes(self): + self.show_hitboxes = not self.show_hitboxes + + def toggle_grid(self): + self.show_grid = not self.show_grid + + def decrease_layer(self): + self.current_layer = max(self.current_layer - 1, 0) + self.upd_layer() + + def increase_layer(self): + self.current_layer = min(self.current_layer + 1, self.canvas_layers - 1) + self.upd_layer() + + def upd_layer(self): + button = self.buttons[2] + button.__init__(button.position, f"{self.current_layer=}", self.upd_layer) + + def fit_to_grid(self, pt, use_floor=True): + pos = self.reverse_transformations(pg.Vector2(pt)) + if use_floor: + return pg.Vector2((pos.x // EditorBlock.width) * EditorBlock.width, + (pos.y // EditorBlock.height) * EditorBlock.height) + else: + return pg.Vector2(round(pos.x / EditorBlock.width) * EditorBlock.width, + round(pos.y / EditorBlock.height) * EditorBlock.height) + + def apply_rect_transformations(self, rect): + top_left = np.array([rect.left, rect.top, 1]) + bottom_right = np.array([rect.right, rect.bottom, 1]) + + top_left = pg.Vector2(tuple((self.world_transform @ self.translation_matrix @ top_left)[0:2])) + bottom_right = pg.Vector2(tuple((self.world_transform @ self.translation_matrix @ bottom_right)[0:2])) + + return pg.Rect(top_left, bottom_right - top_left) + + def add_block(self, pos, mask, texture, canvas_layer): + pos = self.fit_to_grid(pos) + for m in self.blocks.values(): + for i, block in enumerate(m[canvas_layer]): + if block.position == pos: + del m[canvas_layer][i] + break + if texture != "NONE": + mask[canvas_layer].append(EditorBlock(pos, mask, texture)) + + def calculate_transformations(self, current_frame_zoom): + mouse_pos = pg.Vector2(pg.mouse.get_pos()) + + translation_matrix = np.array([[1, 0, mouse_pos.x], + [0, 1, mouse_pos.y], + [0, 0, 1]]) + translation_back_matrix = np.array([[1, 0, -mouse_pos.x], + [0, 1, -mouse_pos.y], + [0, 0, 1]]) + scale_matrix = np.array([[current_frame_zoom, 0, 0], + [0, current_frame_zoom, 0], + [0, 0, 1]]) + self.world_transform = translation_matrix @ scale_matrix @ translation_back_matrix @ self.world_transform + self.inv_world_transform = np.linalg.inv(self.world_transform) + + def apply_transformations(self, pt): + point = pg.Vector2(pt) + point = np.array([point.x, point.y, 1]) + return pg.Vector2(tuple((self.world_transform @ self.translation_matrix @ point)[0:2])) + + def reverse_transformations(self, pt): + point = pg.Vector2(pt) + point = np.array([point.x, point.y, 1]) + return pg.Vector2(tuple((self.translation_back_matrix @ self.inv_world_transform @ point)[0:2])) + + def update(self, delta): + current_frame_zoom = 1 + for event in pg.event.get((pg.MOUSEBUTTONDOWN, pg.MOUSEWHEEL, pg.KEYUP)): + if event.type == pg.MOUSEBUTTONDOWN: + if event.button == 1: + pg.mouse.get_rel() + if event.type == pg.MOUSEWHEEL: + if event.y < 0: + current_frame_zoom *= 0.75 + self.zoom *= 0.75 + elif event.y > 0: + current_frame_zoom *= 1.25 + self.zoom *= 1.25 + if event.type == pg.KEYUP: + if event.key in [pg.K_a, pg.K_s, pg.K_LEFT, pg.K_DOWN]: + self.current_texture = (self.current_texture - 1) % len(self.textures) + elif event.key in [pg.K_d, pg.K_w, pg.K_RIGHT, pg.K_UP]: + self.current_texture = (self.current_texture + 1) % len(self.textures) + + mouse_pressed = pg.mouse.get_pressed(3) + if mouse_pressed[0]: + mouse_rel = pg.mouse.get_rel() + self.total_offset += pg.Vector2(mouse_rel[0] / self.zoom, mouse_rel[1] / self.zoom) + if mouse_pressed[2]: + self.add_block(pg.mouse.get_pos(), self.blocks[self.collision_layer], self.textures[self.current_texture], + self.current_layer) + + self.translation_matrix = np.array([[1, 0, self.total_offset.x], + [0, 1, self.total_offset.y], + [0, 0, 1]]) + self.translation_back_matrix = np.array([[1, 0, -self.total_offset.x], + [0, 1, -self.total_offset.y], + [0, 0, 1]]) + + self.calculate_transformations(current_frame_zoom) + + self.grid.update(delta, self.world_transform, self.inv_world_transform, self.total_offset, self.zoom) + + for mask in self.blocks.values(): + for layer in mask: + for block in layer: + block.update(delta, self.world_transform, self.total_offset) + + prev_x = 0 + for button in self.buttons: + button.update(delta, dx=prev_x) + prev_x += button.width + 10 + + def get_canvas_layers(self): + out = [[] for _ in range(self.canvas_layers)] + for mask in self.blocks.values(): + for i, layer in enumerate(mask): + out[i] += layer + return out + + def draw(self, surf): + surf.fill((0, 0, 0)) + if self.show_grid: + self.grid.draw(surf) + + for i, layer in enumerate(self.get_canvas_layers()): + if i <= self.current_layer: + for block in layer: + block.draw(surf) + if self.show_hitboxes: + block.show_hitbox(surf, self.blocks["world"]) + + pg.draw.line(surf, (255, 0, 0), self.apply_transformations((self.reverse_transformations((0, 0)).x, 0)), + self.apply_transformations((self.reverse_transformations((SCREEN_WIDTH, 0)).x, 0)), + math.ceil(self.zoom * 5)) + pg.draw.line(surf, (255, 0, 0), self.apply_transformations((0, self.reverse_transformations((0, 0)).y)), + self.apply_transformations((0, self.reverse_transformations((0, SCREEN_HEIGHT)).y)), + math.ceil(self.zoom * 5)) + + display_img = EditorBlock.textures[self.textures[self.current_texture]].copy() + display_img.set_alpha(100) + surf.blit(pg.transform.scale(display_img, self.apply_rect_transformations(display_img.get_rect()).size), + self.apply_transformations(self.fit_to_grid(pg.mouse.get_pos(), use_floor=True))) + for button in self.buttons: + button.draw(surf) + + +class Grid: + thickness = 2 + colour = (100, 100, 100) + + def __init__(self): + self.zoom = 1 + self.world_transform = np.identity(3) + self.inv_world_transform = np.linalg.inv(self.world_transform) + self.total_offset = pg.Vector2(0, 0) + self.translation_matrix = np.array([[1, 0, self.total_offset.x], + [0, 1, self.total_offset.y], + [0, 0, 1]]) + self.translation_back_matrix = np.array([[1, 0, -self.total_offset.x], + [0, 1, -self.total_offset.y], + [0, 0, 1]]) + + def update(self, delta, world_transform, inv_world_transform, total_offset, zoom): + self.zoom = zoom + self.world_transform = world_transform + self.inv_world_transform = inv_world_transform + self.total_offset = total_offset + self.translation_matrix = np.array([[1, 0, self.total_offset.x], + [0, 1, self.total_offset.y], + [0, 0, 1]]) + self.translation_back_matrix = np.array([[1, 0, -self.total_offset.x], + [0, 1, -self.total_offset.y], + [0, 0, 1]]) + + def apply_transformations(self, pt): + point = pg.Vector2(pt) + point = np.array([point.x, point.y, 1]) + return pg.Vector2(tuple((self.world_transform @ self.translation_matrix @ point)[0:2])) + + def reverse_transformations(self, pt): + point = pg.Vector2(pt) + point = np.array([point.x, point.y, 1]) + return pg.Vector2(tuple((self.translation_back_matrix @ self.inv_world_transform @ point)[0:2])) + + def draw(self, surf): + start = self.reverse_transformations((0, 0)) + end = self.reverse_transformations(dimensions) + + start = pg.Vector2(start.x // EditorBlock.width, start.y // EditorBlock.width) + end = pg.Vector2(end.x // EditorBlock.height, end.y // EditorBlock.height) + + for i in range(math.floor(start.x), math.floor(end.x) + 1): + pg.draw.line(surf, self.colour, + self.apply_transformations((i * EditorBlock.width, start.y * EditorBlock.height)), + self.apply_transformations((i * EditorBlock.width, (end.y + 1) * EditorBlock.height)), + math.ceil(self.thickness * self.zoom)) + for i in range(math.floor(start.y), math.floor(end.y) + 1): + pg.draw.line(surf, self.colour, + self.apply_transformations((start.x * EditorBlock.width, i * EditorBlock.height)), + self.apply_transformations(((end.x + 1) * EditorBlock.width, i * EditorBlock.height)), + math.ceil(self.thickness * self.zoom)) + + +class EditorBlock: + textures = {file[:file.index(".")]: pg.transform.scale( + pg.image.load(path.join("Assets/world/blocks", file)), (50, 50)) for + file in listdir("Assets/world/blocks")} + width, height = textures["PLACEHOLDER"].get_size() + + def __init__(self, pos, collision_layer, texture="PLACEHOLDER"): + self.position = pg.Vector2(pos) + self.texture = self.textures[texture] + self.texture_name = texture + + self.collision_layer = collision_layer + + self.world_transform = np.identity(3) + self.total_offset = pg.Vector2(0, 0) + self.translation_matrix = np.array([[1, 0, self.total_offset.x], + [0, 1, self.total_offset.y], + [0, 0, 1]]) + + def update(self, delta, world_transform, total_offset): + self.world_transform = world_transform + self.total_offset = total_offset + self.translation_matrix = np.array([[1, 0, self.total_offset.x], + [0, 1, self.total_offset.y], + [0, 0, 1]]) + + def apply_transformations(self, rect): + top_left = np.array([rect.left, rect.top, 1]) + bottom_right = np.array([rect.right, rect.bottom, 1]) + + top_left = pg.Vector2(tuple((self.world_transform @ self.translation_matrix @ top_left)[0:2])) + bottom_right = pg.Vector2(tuple((self.world_transform @ self.translation_matrix @ bottom_right)[0:2])) + + return pg.Rect(top_left, bottom_right - top_left) + + def get_display_rect(self): + return self.apply_transformations(pg.Rect(self.position, (self.width, self.height))) + + def draw(self, surf): + display_rect = self.get_display_rect() + surf.blit(pg.transform.scale(self.texture, display_rect.size), display_rect) + + def show_hitbox(self, surf, collision_layer): + if collision_layer == self.collision_layer: + pg.draw.rect(surf, (255, 0, 0), self.get_display_rect(), 3) + + +class Button: + + def __init__(self, pos, msg, func): + self.position = pg.Vector2(pos) + self.text, self.rect = createText(self.position.x * 2, self.position.y, 20, (200, 200, 200), "Regular", msg) + self.width, self.height = self.text.get_size() + self.func = func + self.msg = msg + self.cooldown = 500 + + def upd_text(self, pos, msg): + self.position = pg.Vector2(pos) + self.text, self.rect = createText(self.position.x * 2, self.position.y, 20, (200, 200, 200), "Regular", msg) + self.width, self.height = self.text.get_size() + self.msg = msg + + def update(self, delta, dx): + self.upd_text((dx, self.position.y), self.msg) + mouse_pos = pg.mouse.get_pos() + if self.cooldown == 0: + if pg.mouse.get_pressed(3)[0]: + if (self.position.x <= mouse_pos[0] <= self.position.x + self.width and + self.position.y <= mouse_pos[1] <= self.position.y + self.height): + self.func() + self.cooldown = 500 + self.cooldown = max(self.cooldown - delta, 0) + + def draw(self, surf): + pg.draw.rect(surf, (80, 80, 80), pg.Rect(self.position, self.text.get_size()), border_radius=3) + pg.draw.rect(surf, (120, 120, 120), pg.Rect(self.position, self.text.get_size()), 1, border_radius=3) + surf.blit(self.text, self.rect) diff --git a/Potion.py b/Potion.py new file mode 100644 index 0000000..3bd81ad --- /dev/null +++ b/Potion.py @@ -0,0 +1,21 @@ +from Setup import * + +class Potion: + + def __init__(self, player, heal_amount = 25): + self.heal = heal_amount + self.player = player + + def get_input(self, player): + pressed_key = pg.key.get_pressed() + if pressed_key[pg.K_1] and player.potion_cooldown == 0: + self.consume_potion(player) + + def consume_potion(self, player): + player.health += self.heal + del player.potion_bag[0] + player.potion_cooldown = 5 + + #def cooldown(self, player): + + diff --git a/SWORD.png b/SWORD.png deleted file mode 100644 index e1c4104..0000000 Binary files a/SWORD.png and /dev/null differ diff --git a/Save/SaveGame.py b/Save/SaveGame.py new file mode 100644 index 0000000..aa08c58 --- /dev/null +++ b/Save/SaveGame.py @@ -0,0 +1,13 @@ +def SaveGame(level): + try: + f = open("./Save/SaveData.txt", "x") + except: + f = open("./Save/SaveData.txt", "w") + f.write(str(level)+"\n") + f.close() + +def LoadGame(): + f = open("./Save/SaveData.txt", "r") + lines = f.readlines() + f.close() + return int(lines[0]) diff --git a/TODO b/TODO new file mode 100644 index 0000000..8daea4d --- /dev/null +++ b/TODO @@ -0,0 +1,33 @@ +Gameplay: +- Make levels +- Add save game functionality + +Movement: +- Custom Dash movement function for dashing + +Combat: +- Health potion items to collect +- bow +- gun +- sword +- buffs? + +- Level Creator + - to facilitate level creation +- Dialogue display + - characters appear one at a time so more readable + +- Story elements + +- dimension travel effect + - I'm thinking like we go on the ship and + the ship travels into a portal that opens + in front and inside that portal is some + purple space with ??? particles flying + around. After a few seconds, go to next + dimension. + + +Art: +- Finish assets +- add assets to game \ No newline at end of file diff --git a/Test.py b/Test.py index ba64cc4..09d366c 100644 --- a/Test.py +++ b/Test.py @@ -8,7 +8,7 @@ class Test: self.angle = 0 self.pivot = pg.Vector2(SCREEN_WIDTH / 2 + 50, SCREEN_HEIGHT / 2 + 50) - self.img = pg.transform.scale(pygame.image.load("SWORD.png"), (100, 100)) + self.img = pg.transform.scale(pygame.image.load("Assets/SWORD.png"), (100, 100)) self.display = self.img.copy() self.img_rect = self.display.get_rect() diff --git a/UI/DashMeter.py b/UI/DashMeter.py new file mode 100644 index 0000000..e1da4c9 --- /dev/null +++ b/UI/DashMeter.py @@ -0,0 +1,33 @@ +from Setup import * +from CommonImports.colours import white +from Function.createText import createText +from datetime import datetime + +class DashMeter: + + def __init__(self, cooldown): + self.texts = ['a'] + self.timeSinceLastDash = datetime.utcnow() + self.timer = self.timeSinceLastDash.second + self.timeSinceLastDash.microsecond / 100000 + self.cooldown = cooldown.seconds + cooldown.microseconds/1000000 + + + def update(self, dash): + self.timeSinceLastDash = datetime.utcnow() - dash + self.timer = self.timeSinceLastDash.seconds + self.timeSinceLastDash.microseconds / 1000000 + if(self.timer > self.cooldown): + self.timer = self.cooldown + + def draw(self, surf): + background_rect = pg.Rect(844, 20, 1080 * 0.2, 640 * 0.08) + foreground_rect = pg.Rect(0, 0, 1080 * 0.185 * (self.timer/self.cooldown), 640 * 0.06) + self.texts[0] = createText(0, 0, 30, white, "Regular", str(round(self.timer/(self.cooldown/100))) + "%")[0] + + foreground_rect.center = ( + background_rect.centerx - 1080 * 0.185 * ((1 - self.timer/self.cooldown) / 2), background_rect.centery) + + pg.draw.rect(surf, (54, 54, 54), background_rect) + pg.draw.rect(surf, (175, 175, 175), foreground_rect) + + text_rect = self.texts[0].get_rect(center=background_rect.center) + surf.blit(self.texts[0], text_rect) diff --git a/UI/HealthBar.py b/UI/HealthBar.py new file mode 100644 index 0000000..8021781 --- /dev/null +++ b/UI/HealthBar.py @@ -0,0 +1,31 @@ +from Setup import * +from CommonImports.colours import white, red +from Function.createText import createText +from datetime import datetime + +class HealthBar: + + def __init__(self): + return; + + def update(self): + return; + + def draw(self, surf, health): + # Healthbar Stuff + # bar is made of 2 rectanges, background which is just a simple rectange and foreground which goes on top and has a bit of math involved + background_rect = pg.Rect(20, 20, 1080 * 0.2, 640 * 0.08) + + # idea is that 1080*0.185 = size of bar at 100% hp, at lower hp you want to get a fraction of that which is why we multiply by (health*0.01) example: 70 hp * 0.01 = 0.7 + foreground_rect = pg.Rect(0, 0, 1080 * 0.185 * (health * 0.01), 640 * 0.06) + # make sure the red part health bar always sits on the left + # sets bar to center of background bar, then subtracts 1/2 of blank space to put it on the left + foreground_rect.center = ( + background_rect.centerx - 1080 * 0.185 * ((1 - health * 0.01) / 2), background_rect.centery) + pg.draw.rect(surf, (54, 54, 54), background_rect) + pg.draw.rect(surf, red, foreground_rect) + + # text + current_health_display = createText(0, 0, 30, white, "Regular", str(health) + "/100")[0] + text_rect = current_health_display.get_rect(center=background_rect.center) + surf.blit(current_health_display, text_rect) diff --git a/Weapon.py b/Weapon.py index 3d424e3..a36395f 100644 --- a/Weapon.py +++ b/Weapon.py @@ -4,11 +4,11 @@ from Setup import * class Melee: - img = pg.transform.scale(pg.image.load("SWORD.png"), (40,40)) + img = pg.transform.scale(pg.image.load("Assets/SWORD.png"), (40, 40)) flipped_img = pg.transform.flip(img,True,False) width,height = img.get_size() - def __init__(self, pos, offset, pivot, width,direction): + def __init__(self, pos, offset, pivot, width,direction, damage): self.position = pg.Vector2(pos) self.offset = pg.Vector2(offset) self.pivot = self.position + pg.Vector2(pivot) @@ -19,12 +19,15 @@ class Melee: self.display = self.img self.display_rect = self.display.get_rect() self.swing_timer = 0 + self.attacking = False + self.damage = damage def update(self, delta, pos, direction): self.position = pg.Vector2(pos) self.pivot = self.position + self.offset + pg.Vector2(self.width/2, self.height/2) - self.direction = direction + if direction != 0: + self.direction = direction if self.direction == -1: angle = 25 * (math.sin(math.radians(self.swing_timer))) @@ -35,6 +38,10 @@ class Melee: self.swing_timer -= delta self.swing_timer = max(self.swing_timer, 0) + if self.swing_timer == 0: + self.attacking = False + else: + self.attacking = True def get_collision_rect(self): if self.direction == -1: @@ -47,7 +54,7 @@ class Melee: if self.swing_timer == 0: self.swing_timer = 360 - def draw(self, surf): - surf.blit(self.display, get_display_rect(self.get_collision_rect()).topleft) - # pygame.draw.circle(surf,(255,0,255),self.pivot,3) - # pygame.draw.circle(surf,(0,255,0),self.position,3) + def draw(self, surf, display_offset = pg.Vector2(0,0)): + surf.blit(self.display, get_display_rect(self.get_collision_rect()).topleft + display_offset) + # pg.draw.circle(surf,(255,0,255),get_display_point(self.pivot),3) + # pg.draw.circle(surf,(0,255,0),get_display_point(self.position),3) diff --git a/World.py b/World.py new file mode 100644 index 0000000..e82f2fe --- /dev/null +++ b/World.py @@ -0,0 +1,42 @@ +from Setup import * +from Block import Block +from os import path + + +class World: + + def __init__(self, collision_layer): + self.collision_layer = collision_layer + self.blocks = [] + + def load_world(self, level): + with open(path.join("Levels", f'Level{level}.txt'), 'r') as f: + file_contents = f.read().split("\n") + + out = [[], center] + for i in range(0, len(file_contents) - 1, 3): + layer = file_contents[i].split("|") + pos = file_contents[i + 1].split("|") + texture = file_contents[i + 2].split("|") + + for l, p, t in zip(layer, pos, texture): + if p == "": + break + x, y = p.split(',') + x = float(x) + y = float(y) + if t == "PLAYER": + out[1] = (x, y) + elif t == "ENEMY": + out[0].append((x, y)) + else: + self.blocks.append(Block((x, y), self.collision_layer[l], t)) + return out + + def update(self, delta): + for block in self.blocks: + block.update(delta) + + def draw(self, surf): + for block in self.blocks: + block.draw(surf) diff --git a/main.py b/main.py index 507912d..e3ccf8b 100644 --- a/main.py +++ b/main.py @@ -1,31 +1,39 @@ from Setup import * from Game import Game from Test import Test +from LevelCreator import LevelCreator from MainMenu import Menu +from DevLevelSelect import DevLevelSelect + delta = 1000//fps is_running = True -level = 1 -old_level = level # scene = Menu() - -scene = Game() +scene = DevLevelSelect() +old_level = 0 +level = 1 while is_running: if pg.event.peek(pg.QUIT): is_running = False - if level == 0: + if level <= 1: level = scene.level + if level == -1: + level = old_level + old_level = 0 + if old_level != level: - old_level = level match level: + case -2: + scene = LevelCreator() case 0: scene = Menu() case 1: - scene = Game() + scene = Game(1) + old_level = level scene.update(delta) scene.draw(screen)