diff --git a/assets/jackninjas/images/entities/player/kayla_idle/0.aseprite b/assets/jackninjas/images/entities/player/kayla_idle/0.aseprite new file mode 100644 index 0000000..3acc448 Binary files /dev/null and b/assets/jackninjas/images/entities/player/kayla_idle/0.aseprite differ diff --git a/assets/jackninjas/images/entities/player/kayla_idle/0.png b/assets/jackninjas/images/entities/player/kayla_idle/0.png new file mode 100644 index 0000000..77dabd6 Binary files /dev/null and b/assets/jackninjas/images/entities/player/kayla_idle/0.png differ diff --git a/scenes/jackdefense/jackdefensegameboard.py b/scenes/jackdefense/jackdefensegameboard.py index 39adf5b..0d4bd64 100644 --- a/scenes/jackdefense/jackdefensegameboard.py +++ b/scenes/jackdefense/jackdefensegameboard.py @@ -4,7 +4,7 @@ import settings from copy import deepcopy -from scenes.jackdefense.scripts.util import Deck +from scenes.jackdefense.scripts.util import Deck, Enemy from utils import Button, draw_grid class JackDefenseGameBoard(Scene): @@ -16,29 +16,54 @@ def __init__(self, game): self.deck = Deck() - self.create_enemy_path() + self.path = self.create_enemy_path() + self.enemy_list = { + "basic": { + "total_count": 20, + "remaining": 20, + "spawn_delay": 90, + "spawn_cd": 90, # frames between spawns + "frame_count": 0 + } + } + self.enemy_group = pygame.sprite.Group() print(self.tile_grid) # creates a straight horizontal enemy path along the grid def create_enemy_path(self, start_pos = (0, 4)): + path = [] img: pygame.surface.Surface = pygame.surface.Surface((self.tile_size, self.tile_size)) img.fill((0, 0, 20)) for i in range(start_pos[0], self.background.get_width() // self.tile_size): - self.tile_grid[f'{i};{start_pos[1]}'] = { + piece = { "type": "path", "img": img, - "pos": (i * self.tile_size, start_pos[1] * self.tile_size) + "pos": (i * self.tile_size, start_pos[1] * self.tile_size), + "direction": (1, 0), } + self.tile_grid[f'{i};{start_pos[1]}'] = piece + path.append(piece) + return path def update(self): self.background.fill((80, 80, 80)) for key in self.tile_grid: - self.background.blit(self.tile_grid[key]["img"], self.tile_grid[key]["pos"]) + for e_type in self.enemy_list: + e = self.enemy_list[e_type] + + if (e["total_count"] == e["remaining"] and e["frame_count"] >= e["spawn_delay"]) or (e["total_count"] != e["remaining"] and e["frame_count"] >= e["spawn_cd"]): + self.enemy_list[e_type]["frame_count"] = 0 + self.enemy_group.add(Enemy(self.game, "basic", self.path)) + else: self.enemy_list[e_type]["frame_count"] += 1 + + self.enemy_group.update() + self.enemy_group.draw(self.background) + if pygame.K_ESCAPE in self.game.just_pressed: self.game.scene_push = "GameSelect" diff --git a/scenes/jackdefense/scripts/util.py b/scenes/jackdefense/scripts/util.py index a256388..2ed3f4d 100644 --- a/scenes/jackdefense/scripts/util.py +++ b/scenes/jackdefense/scripts/util.py @@ -1,13 +1,17 @@ import pygame import random -class Deck(): + +class Deck: def __init__(self): self.deck: list[str] = ["basic", "fire"] - def get_deck(self,): + def get_deck( + self, + ): return self.deck.copy() - def draw_from_deck(self,): + def draw_from_deck( + self, + ): return random.choices(self.deck) - diff --git a/scenes/jackninjas/jackninjas.py b/scenes/jackninjas/jackninjas.py index 0b05de3..2e8c2c6 100644 --- a/scenes/jackninjas/jackninjas.py +++ b/scenes/jackninjas/jackninjas.py @@ -8,6 +8,7 @@ from .scripts.tilemap import Tilemap from .scripts.clouds import Clouds from .scripts.particle import Particle +from .scripts.spark import Spark class JackNinjas(Scene): @@ -20,6 +21,7 @@ def __init__(self, game): self.clock = pygame.time.Clock() self.play_music("sounds/ambience.wav") + self.movement = [False, False] self.assets = { "decor": load_images("tiles/decor"), @@ -51,18 +53,15 @@ def __init__(self, game): self.clouds = Clouds(self.assets["clouds"], count=16) self.player = Player(self, (75, 75), (8, 15)) - self.tilemap = Tilemap(self, tile_size=16) - try: - self.tilemap.load("assets/jackninjas/map.json") - except FileNotFoundError: - pass - self.movement = [False, False] + self.load_level(0) + - # setup our pseudo camera - self.scroll = [0, 0] + def load_level(self, map_id): + self.tilemap.load("assets/jackninjas/maps/" + str(map_id) + '.json') + # setup leaf spawners self.leaf_spawners = [] for tree in self.tilemap.extract([("large_decor", 2)], keep=True): @@ -80,6 +79,9 @@ def __init__(self, game): self.projectiles = [] self.particles = [] + self.sparks = [] + # setup our pseudo camera + self.scroll = [0, 0] def perform_quit(self): pygame.quit() @@ -168,17 +170,26 @@ def draw(self): self.display.blit(img, (projectile[0][0] - img.get_width() / 2 - render_scroll[0], projectile[0][1] - img.get_height() / 2 - render_scroll[1])) if self.tilemap.solid_check(projectile[0]): self.projectiles.remove(projectile) + for i in range(4): + self.sparks.append(Spark(projectile[0], random.random() - 0.5 + (math.pi if projectile[1] > 0 else 0), 2 + random.random())) elif projectile[2] > 360: self.projectiles.remove(projectile) elif abs(self.player.dashing) < 50: # fast part of dash is over if self.player.rect().collidepoint(projectile[0]): self.projectiles.remove(projectile) + for i in range(30): + angle = random.random() * math.pi + speed = random.random() * 5 + self.sparks.append(Spark(self.player.rect().center, angle, 2 + random.random())) + self.particles.append(Particle(self, 'particle', self.player.rect().center, velocity=(math.cos(angle + math.pi) * speed * 0.5, math.sin(angle * math.pi) * speed * 0.5), frame = random.randint(0, 7))) + + for spark in self.sparks.copy(): + kill = spark.update() + spark.render(self.display, offset = render_scroll) + if kill: + self.sparks.remove(spark) - - # update and draw our player - self.player.render(self.display, offset=render_scroll) - # spawn leaf particles for rect in self.leaf_spawners: if random.random() * 50000 < rect.width * rect.height: @@ -205,6 +216,9 @@ def draw(self): if kill: self.particles.remove(particle) + # update and draw our player + self.player.render(self.display, offset=render_scroll) + # FRAME COMPLETE # we finished drawing our frame, lets render it to the screen and # get our input events ready for the next frame and sleep for a bit diff --git a/scenes/jackninjas/jackninjaseditor.py b/scenes/jackninjas/jackninjaseditor.py index d541764..89abca1 100644 --- a/scenes/jackninjas/jackninjaseditor.py +++ b/scenes/jackninjas/jackninjaseditor.py @@ -2,6 +2,7 @@ from scene import Scene from .scripts.utils import load_images from .scripts.tilemap import Tilemap +from utils import Button class JackNinjasEditor(Scene): diff --git a/scenes/jackninjas/scripts/entities.py b/scenes/jackninjas/scripts/entities.py index 6cd157f..6e6fc40 100644 --- a/scenes/jackninjas/scripts/entities.py +++ b/scenes/jackninjas/scripts/entities.py @@ -3,6 +3,7 @@ import pygame from .particle import Particle from scene import Scene +from .spark import Spark GRAVITY = 0.1 MAX_FALL_SPEED = 5 @@ -117,56 +118,97 @@ def __init__(self, scene: Scene, pos, size): def update(self, tilemap, movement=(0, 0)): if self.walking: - if tilemap.solid_check((self.rect().centerx + (-7 if self.flip else 7), self.pos[1] + 23)): - if (self.collisions["left"] or self.collisions["right"]): + if tilemap.solid_check( + (self.rect().centerx + (-7 if self.flip else 7), self.pos[1] + 23) + ): + if self.collisions["left"] or self.collisions["right"]: self.flip = not self.flip else: - movement = (movement[0] - 0.5 if self.flip else movement[0] + 0.5, movement[1]) + movement = ( + movement[0] - 0.5 if self.flip else movement[0] + 0.5, + movement[1], + ) else: self.flip = not self.flip self.walking = max(0, self.walking - 1) if not self.walking: - dis = (self.scene.player.pos[0] - self.pos[0], self.scene.player.pos[1] - self.pos[1]) + dis = ( + self.scene.player.pos[0] - self.pos[0], + self.scene.player.pos[1] - self.pos[1], + ) # check if the player is in range vertically - if abs(dis[1]) < 16: + if abs(dis[1]) < 16: # check if we are facing the player shoot = False shoot_mul = 1 shoot_offset = 7 shoot_speed = 1.5 + + # determine if we shoot if self.flip and dis[0] < 0: shoot = True shoot_mul = -1 elif not self.flip and dis[0] > 0: shoot = True - + + # take the shot if shoot: + start_timer = 0 self.scene.projectiles.append( - [[self.rect().centerx + shoot_offset * shoot_mul, self.rect().centery], shoot_speed * shoot_mul, 0] + [ + [ + self.rect().centerx + shoot_offset * shoot_mul, + self.rect().centery, + ], + shoot_speed * shoot_mul, + start_timer, + ] ) - - - # self.game.projectiles + for i in range(4): + self.scene.sparks.append( + Spark( + self.scene.projectiles[-1][0], + random.random() + - 0.5 + + (0 if shoot_mul == 1 else math.pi), + 2 + random.random(), + ) + ) + + # .projectiles elif random.random() < 0.01: self.walking = random.randint(30, 120) super().update(tilemap, movement) if movement[0] != 0: - self.set_action('run') + self.set_action("run") else: - self.set_action('idle') + self.set_action("idle") - def render(self, surf, offset=(0,0)): - super().render(surf=surf,offset=offset) + def render(self, surf, offset=(0, 0)): + super().render(surf=surf, offset=offset) if self.flip: - surf.blit(pygame.transform.flip(self.scene.assets['gun'], True, False), (self.rect().centerx - 4 - self.scene.assets['gun'].get_width() - offset[0], self.rect().centery - offset[1])) + surf.blit( + pygame.transform.flip(self.scene.assets["gun"], True, False), + ( + self.rect().centerx + - 4 + - self.scene.assets["gun"].get_width() + - offset[0], + self.rect().centery - offset[1], + ), + ) else: - surf.blit(self.scene.assets['gun'], (self.rect().centerx + 4 - offset[0], self.rect().centery - offset[1])) + surf.blit( + self.scene.assets["gun"], + (self.rect().centerx + 4 - offset[0], self.rect().centery - offset[1]), + ) + class Player(PhysicsEntity): def __init__(self, scene: Scene, pos, size): @@ -301,10 +343,15 @@ def update(self, tilemap, movement=(0, 0)): # create a particle effect particle_angle = random.random() * math.pi * 2 # radians particle_speed = random.random() * 0.5 + 0.5 +<<<<<<< HEAD + particle_velocity = [abs(self.dashing) / self.dashing * random.random() * 3, 0] + # particle_velocity = [math.cos(particle_angle) * particle_speed, math.sin(particle_angle) * particle_speed] +======= particle_velocity = [ abs(self.dashing) / self.dashing * random.random() * 3, 0, ] +>>>>>>> cbd0d84cc053696f81d3a991ee904085763e01dc self.scene.particles.append( Particle( self.scene, diff --git a/scenes/jackninjas/scripts/spark.py b/scenes/jackninjas/scripts/spark.py new file mode 100644 index 0000000..6771346 --- /dev/null +++ b/scenes/jackninjas/scripts/spark.py @@ -0,0 +1,26 @@ +import math + +import pygame + +class Spark: + def __init__(self, pos, angle, speed): + self.pos = list(pos) + self.angle = angle + self.speed = speed + + def update(self): + self.pos[0] += math.cos(self.angle) * self.speed + self.pos[1] += math.sin(self.angle) * self.speed + + self.speed = max(0, self.speed - 0.1) + return not self.speed + + def render(self, surf, offset=(0, 0)): + render_points = [ + (self.pos[0] + math.cos(self.angle) * self.speed * 3 - offset[0], self.pos[1] + math.sin(self.angle) * self.speed * 3 - offset[1]), + (self.pos[0] + math.cos(self.angle + math.pi * 0.5) * self.speed * 0.5 - offset[0], self.pos[1] + math.sin(self.angle + math.pi * 0.5) * self.speed * 0.5 - offset[1]), + (self.pos[0] + math.cos(self.angle + math.pi) * self.speed * 3 - offset[0], self.pos[1] + math.sin(self.angle + math.pi) * self.speed * 3 - offset[1]), + (self.pos[0] + math.cos(self.angle - math.pi * 0.5) * self.speed * 0.5 - offset[0], self.pos[1] + math.sin(self.angle - math.pi * 0.5) * self.speed * 0.5 - offset[1]), + ] + + pygame.draw.polygon(surf, (255, 255, 255), render_points) \ No newline at end of file diff --git a/scenes/jackninjas/scripts/tilemap.py b/scenes/jackninjas/scripts/tilemap.py index 63d0847..5101b6b 100644 --- a/scenes/jackninjas/scripts/tilemap.py +++ b/scenes/jackninjas/scripts/tilemap.py @@ -75,6 +75,13 @@ def save(self, path): ) def load(self, path): + with open(path, "r") as f: + data = json.load(f) + self.tilemap = data["tilemap"] + self.tile_size = data["tile_size"] + self.offgrid_tiles = data["offgrid"] + + def generative_load(self, path): with open(path, "r") as f: data = json.load(f) self.tilemap = data["tilemap"] diff --git a/utils.py b/utils.py index 50b930c..45ed1bc 100644 --- a/utils.py +++ b/utils.py @@ -48,6 +48,50 @@ def draw_grid(surf, tile_size = 16, color = (242,245,255)): pygame.draw.line(surf, color, (0, x * tile_size), (width, x * tile_size)) pygame.draw.line(surf, color, (x * tile_size, 0), (x * tile_size, height)) +class UserInterface(): + def __init__( + self, + screen, + pos: tuple[int, int] = (0, 0), + size: tuple[int, int] = None, + growth_dir: tuple[int, int] = (0, 1), # default menu expansion direction, used as a tuple for control in both directions + gap: int = 4, # default number of pixels between each item + ): + self.screen = screen + self.image = make_surface(size) + self.pos = pos + + self.growth_dir = growth_dir + self.gap = gap + + self.items: dict = { + + } + + def add_item(self, item, draw = True, path = None,): + if path: + if path not in self.items.keys(): + self.screen.log("ERROR: Path not found!") + return + self.items[path][item] = { + "draw": draw + } + else: + self.items[item] = {} + + # Removes specified element path from our list and returns the element + def remove_item(self, path): + return self.items[path].pop() + + def toggle_draw(self, item): + item["draw"] = !(item["draw"].) + + def update(): + pass + + def render(): + pass + class Button(): def __init__( self, @@ -110,7 +154,7 @@ def make_text( surf_text.get_width() + strokeThickness * 3, surf_text.get_height() + strokeThickness * 3, ) - surface = self.make_transparent_surface(size) + surface = make_transparent_surface(size) # blit the stroke text to the surface for i in range(strokeThickness * 2 + 1): @@ -344,7 +388,16 @@ def blit_outline(source: pygame.Surface, target: pygame.Surface, dest: tuple): target.blit(mask, (x, y - 1)) target.blit(mask, (x, y + 1)) +def make_surface(self, size) -> pygame.Surface: + """an alias for make_transparent_surface + + Returns: + pygame.Surface: a transparent surface + """ + return self.make_transparent_surface(size) +def make_transparent_surface(size) -> pygame.Surface: + return pygame.Surface(size, pygame.SRCALPHA, 32).convert_alpha() # test our utilities if ran directly if __name__ == "__main__": # test the Seed class