From 1d88c6b985eef66d26ea895ccdb1296f3b4f9e89 Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Apr 2020 13:32:15 -0500 Subject: [PATCH 01/14] create dungeon matrix for pathfinding --- triple-dungeon/map.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/triple-dungeon/map.py b/triple-dungeon/map.py index 8394d7b..4a66e95 100644 --- a/triple-dungeon/map.py +++ b/triple-dungeon/map.py @@ -7,6 +7,8 @@ Pathfinding will also depend on objects here, and is thus integral to it's funct from __future__ import annotations import json +from pprint import pprint + import arcade import numpy as np @@ -40,6 +42,14 @@ class Dungeon(object): self.levels = [ [Level.load_file(x, y, center) for y in range(size)] for x in range(size) ] + self.matrix = [[0 for yy in range(size * 10)] for xx in range(10 * size)] + for column in self.levels: + for level in column: + for xx in range(10): + for yy in range(10): + if level.structure[xx][yy] == 'w': + self.matrix[(level.x * 10) + xx][(level.y * 10) + yy] = 1 + # pprint(self.matrix, width=1000) def getWalls(self) -> arcade.SpriteList: """ From 2a1d1bce6e496525b6b32311b1ea7981c7c7ab5a Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Apr 2020 13:50:17 -0500 Subject: [PATCH 02/14] skeleton functions for pathing in Mobs using target attribute and target and dungeon references, create new TILE_SIZE config option --- triple-dungeon/config.py | 1 + triple-dungeon/main.py | 9 ++++----- triple-dungeon/mobs.py | 27 +++++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index a395e94..71a5d64 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -29,6 +29,7 @@ class Config(object): # Constants used to scale our sprites from their original size CHARACTER_SCALING = 1 TILE_SCALING = 2 + TILE_SIZE = TILE_WIDTH * TILE_SCALING # The number of pixels across the level LEVEL_SIZE = 10 * TILE_SCALING * TILE_WIDTH diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index 4d3b3d4..93072a0 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -10,7 +10,6 @@ import random import time import arcade - from config import Config from map import Dungeon from mobs import Player @@ -70,7 +69,7 @@ class Game(arcade.Window): self.dungeon = Dungeon(0, 3) # Set up the player, specifically placing it at these coordinates. - self.player = Player() + self.player = Player(self.dungeon) self.player.scale = 1 level = random.choice(self.dungeon.levelList) self.player.center_x, self.player.center_y = level.center() @@ -105,9 +104,9 @@ class Game(arcade.Window): if Config.DEBUG: x, y = self.player.position - tile = Config.TILE_WIDTH * Config.TILE_SCALING - arcade.draw_rectangle_outline(round(x / tile) * tile, round(y / tile) * tile, tile, tile, - arcade.color.RED) + arcade.draw_rectangle_outline(round(x / Config.TILE_SIZE) * Config.TILE_SIZE, + round(y / Config.TILE_SIZE) * Config.TILE_SIZE, + Config.TILE_SIZE, Config.TILE_SIZE, arcade.color.RED) self.player.draw_hit_box() arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index 9b9906b..12c52e6 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -3,9 +3,11 @@ mobs.py Organizes all classes related to Mobs, Entities, Enemies, Players and Items. """ -import arcade +from typing import List, Tuple +import arcade from config import Config, Enums, SpritePaths +from map import Dungeon from sprites import PlayerAnimations @@ -14,7 +16,7 @@ class Mob(arcade.Sprite): Represents a Mob. No defined behaviour, it has no intelligence. """ - def __init__(self, max_health=100, max_armor=0, *args, **kwargs) -> None: + def __init__(self, dungeon: Dungeon, max_health=100, max_armor=0, *args, **kwargs) -> None: # Set up parent class super().__init__() @@ -26,12 +28,33 @@ class Mob(arcade.Sprite): self.down_textures = [] self.cur_texture = 0 + self.dungeon = dungeon + self.target = None + def tick(self) -> None: """ A on_update function, the Mob should decide it's next actions here. """ + + if Config.DEBUG: + if self.target is not None: + x, y = self.target.position + self.draw_path(self.get_path( + (round(x / Config.TILE_SIZE) * Config.TILE_SIZE, round(y / Config.TILE_SIZE) * Config.TILE_SIZE) + )) + + def draw_path(self, path: List[Tuple[int, int]]) -> None: pass + def get_path(self, end: Tuple[int, int]) -> List[Tuple[int, int]]: + """ + Returns the path to get to the Mob's target in absolute integer positions. + + :param matrix: + :param end: + :return: + """ + class Player(Mob): """ From b65d12be16098934198bcba20d730d0a63a281c1 Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Apr 2020 14:04:45 -0500 Subject: [PATCH 03/14] create draw and get path methodology --- triple-dungeon/main.py | 15 +++++++++++++++ triple-dungeon/mobs.py | 24 ++++++++++++++---------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index 93072a0..00415f3 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -8,6 +8,7 @@ import collections import math import random import time +from typing import Tuple, List import arcade from config import Config @@ -111,11 +112,25 @@ class Game(arcade.Window): arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, arcade.color.WHITE, 16, font_name='Arial') + + # Draw paths for all mobs + for mob in self.enemy_list: + if mob.target is not None: + self.draw_path(mob.mob.get_path()) + self.fps.tick() except Exception: import traceback traceback.print_exc() + def draw_path(self, path: List[Tuple[int, int]]) -> None: + """ + Draws a line between positions in a list of tuple, also known as the path. + :param path: A list of tuple positions defining a path that can be traversed. + """ + print(path) + pass + def on_key_press(self, key, modifiers): """Called whenever a key is pressed. """ diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index 12c52e6..bf6366e 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -31,6 +31,15 @@ class Mob(arcade.Sprite): self.dungeon = dungeon self.target = None + def nearestPosition(self) -> Tuple[int, int]: + """ + Returns the nearest absolute dungeon tile the Mob is placed on. + + :return: A tuple containing the Mob's dungeon tile position. + """ + return (round(self.center_x / Config.TILE_SIZE) * Config.TILE_SIZE, + round(self.center_y / Config.TILE_SIZE) * Config.TILE_SIZE) + def tick(self) -> None: """ A on_update function, the Mob should decide it's next actions here. @@ -38,22 +47,17 @@ class Mob(arcade.Sprite): if Config.DEBUG: if self.target is not None: - x, y = self.target.position - self.draw_path(self.get_path( - (round(x / Config.TILE_SIZE) * Config.TILE_SIZE, round(y / Config.TILE_SIZE) * Config.TILE_SIZE) - )) - def draw_path(self, path: List[Tuple[int, int]]) -> None: - pass - - def get_path(self, end: Tuple[int, int]) -> List[Tuple[int, int]]: + def get_path(self, end: Tuple[int, int] = None) -> List[Tuple[int, int]]: """ Returns the path to get to the Mob's target in absolute integer positions. - :param matrix: - :param end: + :param end: A the endpoint tuple. Must be a valid position within the matrix. :return: """ + if end is None: + x, y = self.target.position + x, y = (round(x / Config.TILE_SIZE) * Config.TILE_SIZE, round(y / Config.TILE_SIZE) * Config.TILE_SIZE) class Player(Mob): From 7948662459f39e343b190f2b35df07d69885e01e Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Apr 2020 14:09:56 -0500 Subject: [PATCH 04/14] fix draw path function --- triple-dungeon/main.py | 10 +++++++--- triple-dungeon/mobs.py | 4 +--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index 00415f3..3714a8f 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -123,13 +123,17 @@ class Game(arcade.Window): import traceback traceback.print_exc() - def draw_path(self, path: List[Tuple[int, int]]) -> None: + @staticmethod + def draw_path(path: List[Tuple[int, int]]) -> None: """ Draws a line between positions in a list of tuple, also known as the path. :param path: A list of tuple positions defining a path that can be traversed. """ - print(path) - pass + + if len(path) > 2: + path = map(lambda point: ((0.5 + point[0]) * Config.TILE_SIZE, (0.5 + point[1]) * Config.TILE_SIZE), path) + arcade.draw_lines(list(path)) + # for pos1, pos2 in zip(path, path[1:]) def on_key_press(self, key, modifiers): """Called whenever a key is pressed. """ diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index bf6366e..a85ba67 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -44,9 +44,7 @@ class Mob(arcade.Sprite): """ A on_update function, the Mob should decide it's next actions here. """ - - if Config.DEBUG: - if self.target is not None: + pass def get_path(self, end: Tuple[int, int] = None) -> List[Tuple[int, int]]: """ From 50f56e41909e88e45aa0c6de3ec4e505c1b3bfdc Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Apr 2020 17:53:00 -0500 Subject: [PATCH 05/14] get path work and printing --- triple-dungeon/main.py | 9 +++++++-- triple-dungeon/map.py | 5 +++++ triple-dungeon/mobs.py | 15 ++++++++++----- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index 3714a8f..fc897a4 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -13,7 +13,7 @@ from typing import Tuple, List import arcade from config import Config from map import Dungeon -from mobs import Player +from mobs import Player, Mob from projectiles import Temp @@ -76,6 +76,11 @@ class Game(arcade.Window): self.player.center_x, self.player.center_y = level.center() # x, y = level.center() + mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) + mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() + mob.target = self.player + self.enemy_list.append(mob) + # Setup viewport self.view_bottom = self.player.center_x - (0.5 * Config.SCREEN_WIDTH) + 300 self.view_left = self.player.center_x - (0.5 * Config.SCREEN_WIDTH) @@ -116,7 +121,7 @@ class Game(arcade.Window): # Draw paths for all mobs for mob in self.enemy_list: if mob.target is not None: - self.draw_path(mob.mob.get_path()) + self.draw_path(mob.get_path()) self.fps.tick() except Exception: diff --git a/triple-dungeon/map.py b/triple-dungeon/map.py index 4a66e95..7803d67 100644 --- a/triple-dungeon/map.py +++ b/triple-dungeon/map.py @@ -14,6 +14,9 @@ import numpy as np from itertools import chain from config import Config +from pathfinding.core.diagonal_movement import DiagonalMovement +from pathfinding.core.grid import Grid +from pathfinding.finder.a_star import AStarFinder class Dungeon(object): @@ -49,6 +52,8 @@ class Dungeon(object): for yy in range(10): if level.structure[xx][yy] == 'w': self.matrix[(level.x * 10) + xx][(level.y * 10) + yy] = 1 + self.grid = Grid(matrix=self.matrix) + self.finder = AStarFinder(diagonal_movement=DiagonalMovement.always) # pprint(self.matrix, width=1000) def getWalls(self) -> arcade.SpriteList: diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index a85ba67..4e50815 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -18,7 +18,7 @@ class Mob(arcade.Sprite): def __init__(self, dungeon: Dungeon, max_health=100, max_armor=0, *args, **kwargs) -> None: # Set up parent class - super().__init__() + super(Mob, self).__init__(*args, **kwargs) self.max_health, self.max_armor = max_health, max_armor self.health, self.armor = max_health, max_armor @@ -37,8 +37,8 @@ class Mob(arcade.Sprite): :return: A tuple containing the Mob's dungeon tile position. """ - return (round(self.center_x / Config.TILE_SIZE) * Config.TILE_SIZE, - round(self.center_y / Config.TILE_SIZE) * Config.TILE_SIZE) + return (round(self.center_x / Config.TILE_SIZE), + round(self.center_y / Config.TILE_SIZE)) def tick(self) -> None: """ @@ -54,8 +54,13 @@ class Mob(arcade.Sprite): :return: """ if end is None: - x, y = self.target.position - x, y = (round(x / Config.TILE_SIZE) * Config.TILE_SIZE, round(y / Config.TILE_SIZE) * Config.TILE_SIZE) + end = self.target.position + start, end = self.nearestPosition(), (round(end[0] / Config.TILE_SIZE), round(end[1] / Config.TILE_SIZE)) + print(start, end) + start, end = self.dungeon.grid.node(*start), self.dungeon.grid.node(*end) + paths, runs = self.dungeon.finder.find_path(start, end, self.dungeon.grid) + print(paths, runs) + return paths class Player(Mob): From 02a650d72b69fce16936cfe28accd0304739f0cb Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Apr 2020 18:06:53 -0500 Subject: [PATCH 06/14] add grid cleanup so pathing works more than once, fix matrix reverse obstacle/clear --- triple-dungeon/main.py | 13 +++++++++---- triple-dungeon/map.py | 6 +++--- triple-dungeon/mobs.py | 3 +-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index fc897a4..05829d1 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -121,7 +121,11 @@ class Game(arcade.Window): # Draw paths for all mobs for mob in self.enemy_list: if mob.target is not None: - self.draw_path(mob.get_path()) + t1 = time.time() + path = mob.get_path() + t2 = time.time() + print(f'Path acquired in {round(t2 - t1, 4)}s') + self.draw_path(path) self.fps.tick() except Exception: @@ -136,9 +140,10 @@ class Game(arcade.Window): """ if len(path) > 2: - path = map(lambda point: ((0.5 + point[0]) * Config.TILE_SIZE, (0.5 + point[1]) * Config.TILE_SIZE), path) - arcade.draw_lines(list(path)) - # for pos1, pos2 in zip(path, path[1:]) + path = map(lambda point: ((point[0]) * Config.TILE_SIZE, (point[1]) * Config.TILE_SIZE), path) + path = list(path) + for pos1, pos2 in zip(path, path[1:]): + arcade.draw_line(*pos1, *pos2, color=arcade.color.RED) def on_key_press(self, key, modifiers): """Called whenever a key is pressed. """ diff --git a/triple-dungeon/map.py b/triple-dungeon/map.py index 7803d67..32f254e 100644 --- a/triple-dungeon/map.py +++ b/triple-dungeon/map.py @@ -45,16 +45,16 @@ class Dungeon(object): self.levels = [ [Level.load_file(x, y, center) for y in range(size)] for x in range(size) ] - self.matrix = [[0 for yy in range(size * 10)] for xx in range(10 * size)] + self.matrix = [[1 for yy in range(size * 10)] for xx in range(10 * size)] for column in self.levels: for level in column: for xx in range(10): for yy in range(10): if level.structure[xx][yy] == 'w': - self.matrix[(level.x * 10) + xx][(level.y * 10) + yy] = 1 + self.matrix[(level.x * 10) + xx][(level.y * 10) + yy] = 0 self.grid = Grid(matrix=self.matrix) self.finder = AStarFinder(diagonal_movement=DiagonalMovement.always) - # pprint(self.matrix, width=1000) + pprint(self.matrix, width=1000) def getWalls(self) -> arcade.SpriteList: """ diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index 4e50815..aba6ac2 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -56,10 +56,9 @@ class Mob(arcade.Sprite): if end is None: end = self.target.position start, end = self.nearestPosition(), (round(end[0] / Config.TILE_SIZE), round(end[1] / Config.TILE_SIZE)) - print(start, end) start, end = self.dungeon.grid.node(*start), self.dungeon.grid.node(*end) paths, runs = self.dungeon.finder.find_path(start, end, self.dungeon.grid) - print(paths, runs) + self.dungeon.grid.cleanup() return paths From 9b133749aff56ea52321eb05ba0bdd6e362f352a Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Apr 2020 18:18:25 -0500 Subject: [PATCH 07/14] add tick function for mob movement --- triple-dungeon/config.py | 2 +- triple-dungeon/main.py | 1 + triple-dungeon/mobs.py | 18 ++++++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index 71a5d64..3ea935d 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -28,7 +28,7 @@ class Config(object): # Constants used to scale our sprites from their original size CHARACTER_SCALING = 1 - TILE_SCALING = 2 + TILE_SCALING = 1 TILE_SIZE = TILE_WIDTH * TILE_SCALING # The number of pixels across the level diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index 05829d1..15fdd8d 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -126,6 +126,7 @@ class Game(arcade.Window): t2 = time.time() print(f'Path acquired in {round(t2 - t1, 4)}s') self.draw_path(path) + mob.tick(path) self.fps.tick() except Exception: diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index aba6ac2..8a309b0 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -40,11 +40,25 @@ class Mob(arcade.Sprite): return (round(self.center_x / Config.TILE_SIZE), round(self.center_y / Config.TILE_SIZE)) - def tick(self) -> None: + def tick(self, path: Tuple[int, int] = None) -> None: """ A on_update function, the Mob should decide it's next actions here. """ - pass + pos, next = self.nearestPosition(), path[0] + + if next[0] > pos[0]: + self.change_x = Config.PLAYER_MOVEMENT_SPEED + elif next[0] < pos[0]: + self.change_x = -Config.PLAYER_MOVEMENT_SPEED + else: + self.change_x = 0 + + if next[1] > pos[1]: + self.change_y = Config.PLAYER_MOVEMENT_SPEED + elif next[1] < pos[1]: + self.change_y = Config.PLAYER_MOVEMENT_SPEED + else: + self.change_y = 0 def get_path(self, end: Tuple[int, int] = None) -> List[Tuple[int, int]]: """ From 3d5b0f636c07bceca941a71c2a7c2447f347532d Mon Sep 17 00:00:00 2001 From: Xevion Date: Tue, 21 Apr 2020 18:44:54 -0500 Subject: [PATCH 08/14] fix mob movement --- triple-dungeon/config.py | 4 ++-- triple-dungeon/main.py | 6 ++++++ triple-dungeon/mobs.py | 21 ++++++++++++--------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index 3ea935d..623eb5a 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -28,14 +28,14 @@ class Config(object): # Constants used to scale our sprites from their original size CHARACTER_SCALING = 1 - TILE_SCALING = 1 + TILE_SCALING = 2 TILE_SIZE = TILE_WIDTH * TILE_SCALING # The number of pixels across the level LEVEL_SIZE = 10 * TILE_SCALING * TILE_WIDTH # Movement speed of player, in pixels per frame - PLAYER_MOVEMENT_SPEED = 7 + PLAYER_MOVEMENT_SPEED = 14 # How many pixels to keep as a minimum margin between the characters and the edge of the screen. LEFT_VIEWPORT_MARGIN = 250 diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index 15fdd8d..fe6496e 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -186,6 +186,10 @@ class Game(arcade.Window): """ Called whenever the mouse is clicked. """ + + for mob in self.enemy_list: + mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() + # Create a bullet TEMP SPRITE, currently wielding frog slingshot bullet = Temp() # Position the bullet at the player's current location @@ -259,6 +263,8 @@ class Game(arcade.Window): self.view_bottom, Config.SCREEN_HEIGHT + self.view_bottom) + self.enemy_list.update() + # Projectile updates self.bullet_list.update() for bullet in self.bullet_list: diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index 8a309b0..62c9206 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -44,22 +44,25 @@ class Mob(arcade.Sprite): """ A on_update function, the Mob should decide it's next actions here. """ - pos, next = self.nearestPosition(), path[0] + curpos, nextpos = self.nearestPosition(), path[1] + print(curpos, nextpos) - if next[0] > pos[0]: - self.change_x = Config.PLAYER_MOVEMENT_SPEED - elif next[0] < pos[0]: - self.change_x = -Config.PLAYER_MOVEMENT_SPEED + if nextpos[0] > curpos[0]: + self.change_x = Config.PLAYER_MOVEMENT_SPEED - 3 + elif nextpos[0] < curpos[0]: + self.change_x = -Config.PLAYER_MOVEMENT_SPEED + 3 else: self.change_x = 0 - if next[1] > pos[1]: - self.change_y = Config.PLAYER_MOVEMENT_SPEED - elif next[1] < pos[1]: - self.change_y = Config.PLAYER_MOVEMENT_SPEED + if nextpos[1] > curpos[1]: + self.change_y = Config.PLAYER_MOVEMENT_SPEED - 3 + elif nextpos[1] < curpos[1]: + self.change_y = -Config.PLAYER_MOVEMENT_SPEED + 3 else: self.change_y = 0 + print(self.change_x, self.change_y) + def get_path(self, end: Tuple[int, int] = None) -> List[Tuple[int, int]]: """ Returns the path to get to the Mob's target in absolute integer positions. From 7e213e7c59440dca8c07ad812e7d47ef6fa69cc0 Mon Sep 17 00:00:00 2001 From: Cameron Smart Date: Wed, 22 Apr 2020 11:16:27 -0700 Subject: [PATCH 09/14] added more monsters to test lag. --- triple-dungeon/config.py | 8 ++++---- triple-dungeon/main.py | 34 +++++++++++++++++++++++++++------- triple-dungeon/mobs.py | 4 ++-- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index 623eb5a..b082e3e 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -38,10 +38,10 @@ class Config(object): PLAYER_MOVEMENT_SPEED = 14 # How many pixels to keep as a minimum margin between the characters and the edge of the screen. - LEFT_VIEWPORT_MARGIN = 250 - RIGHT_VIEWPORT_MARGIN = 250 - BOTTOM_VIEWPORT_MARGIN = 50 - TOP_VIEWPORT_MARGIN = 100 + LEFT_VIEWPORT_MARGIN = 500 + RIGHT_VIEWPORT_MARGIN = 500 + BOTTOM_VIEWPORT_MARGIN = 250 + TOP_VIEWPORT_MARGIN = 200 # All debug statements and renderings should use this DEBUG = True diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index fe6496e..75ac0ba 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -79,6 +79,22 @@ class Game(arcade.Window): mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() mob.target = self.player + mob.scale = 4 + self.enemy_list.append(mob) + mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) + mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() + mob.target = self.player + mob.scale = 4 + self.enemy_list.append(mob) + mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) + mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() + mob.target = self.player + mob.scale = 4 + self.enemy_list.append(mob) + mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) + mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() + mob.target = self.player + mob.scale = 4 self.enemy_list.append(mob) # Setup viewport @@ -114,9 +130,9 @@ class Game(arcade.Window): round(y / Config.TILE_SIZE) * Config.TILE_SIZE, Config.TILE_SIZE, Config.TILE_SIZE, arcade.color.RED) self.player.draw_hit_box() - arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') - arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, - arcade.color.WHITE, 16, font_name='Arial') + #arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') + #arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, + # arcade.color.WHITE, 16, font_name='Arial') # Draw paths for all mobs for mob in self.enemy_list: @@ -124,7 +140,7 @@ class Game(arcade.Window): t1 = time.time() path = mob.get_path() t2 = time.time() - print(f'Path acquired in {round(t2 - t1, 4)}s') + #print(f'Path acquired in {round(t2 - t1, 4)}s') self.draw_path(path) mob.tick(path) @@ -187,8 +203,7 @@ class Game(arcade.Window): Called whenever the mouse is clicked. """ - for mob in self.enemy_list: - mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() + # Create a bullet TEMP SPRITE, currently wielding frog slingshot bullet = Temp() @@ -263,17 +278,22 @@ class Game(arcade.Window): self.view_bottom, Config.SCREEN_HEIGHT + self.view_bottom) + self.enemy_list.update() # Projectile updates self.bullet_list.update() for bullet in self.bullet_list: + # Collision Checks hit_list = arcade.check_for_collision_with_list(bullet, self.dungeon.getWalls()) - + enemy_hit_list = arcade.check_for_collision_with_list(bullet, self.enemy_list) # If it did, get rid of the bullet if len(hit_list) > 0: bullet.remove_from_sprite_lists() + if len(enemy_hit_list): + enemy_hit_list[0].remove_from_sprite_lists() + # If the bullet flies off-screen, remove it. TEMP change to range calc if ( diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index 62c9206..3f1158e 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -45,7 +45,7 @@ class Mob(arcade.Sprite): A on_update function, the Mob should decide it's next actions here. """ curpos, nextpos = self.nearestPosition(), path[1] - print(curpos, nextpos) + # print(curpos, nextpos) if nextpos[0] > curpos[0]: self.change_x = Config.PLAYER_MOVEMENT_SPEED - 3 @@ -61,7 +61,7 @@ class Mob(arcade.Sprite): else: self.change_y = 0 - print(self.change_x, self.change_y) + # print(self.change_x, self.change_y) def get_path(self, end: Tuple[int, int] = None) -> List[Tuple[int, int]]: """ From 11ffacef01b25b279edc393e7936728d501e672d Mon Sep 17 00:00:00 2001 From: Lief9100 Date: Wed, 22 Apr 2020 13:38:35 -0700 Subject: [PATCH 10/14] add and implement active monster list --- triple-dungeon/config.py | 3 +++ triple-dungeon/main.py | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index b082e3e..7018973 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -45,6 +45,9 @@ class Config(object): # All debug statements and renderings should use this DEBUG = True + + #Monster Count to be spawned + MONSTER_COUNT = 4 class Enums(Enum): diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index 75ac0ba..cf488dd 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -47,6 +47,7 @@ class Game(arcade.Window): # Sprite Lists self.enemy_list = None + self.active_enemies = [] self.bullet_list = None self.player = None # Game Objects @@ -63,6 +64,7 @@ class Game(arcade.Window): # Create the Sprite lists self.enemy_list = arcade.SpriteList() + self.active_enemies = arcade.SpriteList() self.fps = FPSCounter() self.bullet_list = arcade.SpriteList() @@ -76,6 +78,14 @@ class Game(arcade.Window): self.player.center_x, self.player.center_y = level.center() # x, y = level.center() + #Set up monsters + for count in range(Config.MONSTER_COUNT): + mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) + mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() + mob.target = self.player + mob.scale = 4 + self.enemy_list.append(mob) + ''' mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() mob.target = self.player @@ -96,7 +106,7 @@ class Game(arcade.Window): mob.target = self.player mob.scale = 4 self.enemy_list.append(mob) - + ''' # Setup viewport self.view_bottom = self.player.center_x - (0.5 * Config.SCREEN_WIDTH) + 300 self.view_left = self.player.center_x - (0.5 * Config.SCREEN_WIDTH) @@ -122,6 +132,7 @@ class Game(arcade.Window): self.dungeon.render() self.player.draw() self.enemy_list.draw() + self.active_enemies.draw() self.bullet_list.draw() if Config.DEBUG: @@ -130,12 +141,12 @@ class Game(arcade.Window): round(y / Config.TILE_SIZE) * Config.TILE_SIZE, Config.TILE_SIZE, Config.TILE_SIZE, arcade.color.RED) self.player.draw_hit_box() - #arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') - #arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, - # arcade.color.WHITE, 16, font_name='Arial') + arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') + arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, + arcade.color.WHITE, 16, font_name='Arial') # Draw paths for all mobs - for mob in self.enemy_list: + for mob in self.active_enemies: if mob.target is not None: t1 = time.time() path = mob.get_path() @@ -277,9 +288,20 @@ class Game(arcade.Window): Config.SCREEN_WIDTH + self.view_left, self.view_bottom, Config.SCREEN_HEIGHT + self.view_bottom) - - - self.enemy_list.update() + + #Enemy activation and update + for enemy in reversed(self.enemy_list): + if ( + enemy.bottom > self.view_bottom and + enemy.top < self.view_bottom + Config.SCREEN_HEIGHT and + enemy.right < self.view_left + Config.SCREEN_WIDTH and + enemy.left > self.view_left + ): + if Config.DEBUG: print("Activate Enemy") + self.active_enemies.append(enemy) + self.enemy_list.remove(enemy) + for enemy in self.active_enemies: + enemy.update() # Projectile updates self.bullet_list.update() @@ -287,7 +309,7 @@ class Game(arcade.Window): # Collision Checks hit_list = arcade.check_for_collision_with_list(bullet, self.dungeon.getWalls()) - enemy_hit_list = arcade.check_for_collision_with_list(bullet, self.enemy_list) + enemy_hit_list = arcade.check_for_collision_with_list(bullet, self.active_enemies) # If it did, get rid of the bullet if len(hit_list) > 0: bullet.remove_from_sprite_lists() From 68f572124aa80d6c95627b2956d40a5aff492b70 Mon Sep 17 00:00:00 2001 From: Cameron Smart Date: Wed, 22 Apr 2020 20:18:00 -0700 Subject: [PATCH 11/14] Added kill list and recipes. Checks every three kills. --- triple-dungeon/config.py | 12 +-- triple-dungeon/main.py | 28 ++++--- triple-dungeon/mobs.py | 167 ++++++++++++++++++++------------------- 3 files changed, 107 insertions(+), 100 deletions(-) diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index 7018973..9a3b166 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -38,16 +38,16 @@ class Config(object): PLAYER_MOVEMENT_SPEED = 14 # How many pixels to keep as a minimum margin between the characters and the edge of the screen. - LEFT_VIEWPORT_MARGIN = 500 - RIGHT_VIEWPORT_MARGIN = 500 - BOTTOM_VIEWPORT_MARGIN = 250 - TOP_VIEWPORT_MARGIN = 200 + LEFT_VIEWPORT_MARGIN = 700 + RIGHT_VIEWPORT_MARGIN = 700 + BOTTOM_VIEWPORT_MARGIN = 300 + TOP_VIEWPORT_MARGIN = 350 # All debug statements and renderings should use this - DEBUG = True + DEBUG = False #Monster Count to be spawned - MONSTER_COUNT = 4 + MONSTER_COUNT = 20 class Enums(Enum): diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index cf488dd..e1660f2 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -13,7 +13,7 @@ from typing import Tuple, List import arcade from config import Config from map import Dungeon -from mobs import Player, Mob +from mobs import Player, Enemy from projectiles import Temp @@ -80,10 +80,11 @@ class Game(arcade.Window): #Set up monsters for count in range(Config.MONSTER_COUNT): - mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) + mob = Enemy(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() mob.target = self.player mob.scale = 4 + mob.monster_type = 'ghost' self.enemy_list.append(mob) ''' mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) @@ -140,10 +141,10 @@ class Game(arcade.Window): arcade.draw_rectangle_outline(round(x / Config.TILE_SIZE) * Config.TILE_SIZE, round(y / Config.TILE_SIZE) * Config.TILE_SIZE, Config.TILE_SIZE, Config.TILE_SIZE, arcade.color.RED) - self.player.draw_hit_box() - arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') - arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, - arcade.color.WHITE, 16, font_name='Arial') + #self.player.draw_hit_box() + #arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') + #arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, + # arcade.color.WHITE, 16, font_name='Arial') # Draw paths for all mobs for mob in self.active_enemies: @@ -152,7 +153,7 @@ class Game(arcade.Window): path = mob.get_path() t2 = time.time() #print(f'Path acquired in {round(t2 - t1, 4)}s') - self.draw_path(path) + #self.draw_path(path) mob.tick(path) self.fps.tick() @@ -288,7 +289,6 @@ class Game(arcade.Window): Config.SCREEN_WIDTH + self.view_left, self.view_bottom, Config.SCREEN_HEIGHT + self.view_bottom) - #Enemy activation and update for enemy in reversed(self.enemy_list): if ( @@ -300,9 +300,14 @@ class Game(arcade.Window): if Config.DEBUG: print("Activate Enemy") self.active_enemies.append(enemy) self.enemy_list.remove(enemy) - for enemy in self.active_enemies: - enemy.update() - + try: + for enemy in self.active_enemies: + enemy.update() + path = enemy.get_path() + enemy.tick(path) + except Exception: + import traceback + traceback.print_exc() # Projectile updates self.bullet_list.update() for bullet in self.bullet_list: @@ -314,6 +319,7 @@ class Game(arcade.Window): if len(hit_list) > 0: bullet.remove_from_sprite_lists() if len(enemy_hit_list): + self.player.add_kill(enemy_hit_list[0].monster_type) enemy_hit_list[0].remove_from_sprite_lists() diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index 3f1158e..7534c2d 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -31,6 +31,90 @@ class Mob(arcade.Sprite): self.dungeon = dungeon self.target = None + + + +class Player(Mob): + """ + Represents a Player. + While this is a instance, there should only be one in the world at any given time. + """ + + def __init__(self, *args, **kwargs) -> None: + super(Player, self).__init__(*args, **kwargs) + + self.animations = PlayerAnimations(SpritePaths.KNIGHT) + # Used for mapping directions to animations + self.map = { + Enums.IDLE: self.animations.idles, + Enums.UP: self.animations.up, + Enums.DOWN: self.animations.down, + Enums.RIGHT: self.animations.right, + Enums.LEFT: self.animations.left + } + + self.refreshIndex = 0 + self.prev = Enums.IDLE + self.texture = next(self.map[self.prev]) + self.kill_list = [] + self.cur_recipe = ['ghost', 'ghost', 'ghost'] + + def add_kill(self, creature): + # Adds a kill to kill_list. If 3 or more check the recipe then give a power up if it matches. + + self.kill_list.append(creature) + if self.cur_recipe == self.kill_list: + print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++") + self.kill_list = [] + + + def update_animation(self, delta_time: float = 1 / 60) -> None: + """ + Updates animations for the Player. + :param delta_time: No idea. + """ + + # Increase the refresh index according + self.refreshIndex = (self.refreshIndex + 1) % Config.RUN_UPDATES_PER_FRAME + + # Logic to determine what direction we're in. + if self.change_x == 0 and self.change_y == 0: + cur = Enums.IDLE + elif self.change_y > 0: # Up + cur = Enums.UP + elif self.change_y < 0: # Down + cur = Enums.DOWN + elif self.change_x > 0: # Left + cur = Enums.RIGHT + elif self.change_x < 0: # Right + cur = Enums.LEFT + else: # Idle + cur = Enums.IDLE + + # If we're in a new direction or the refresh index has reset + if self.prev is not cur or self.refreshIndex == 0: + self.texture = next(self.map[cur]) + + self.prev = cur + + def tick(self): + """ + While Player objects do not have any AI (they are controlled by the user), + the tick function can keep track of statistics that progress over time, like + regenerating health/armor or status effects like poison. + """ + + +class Enemy(Mob): + """ + Represents an Enemy Mob. + Will take basic offensive actions against Player objects. + """ + + def __init__(self, *args, **kwargs) -> None: + super(Enemy, self).__init__(*args, **kwargs) + self.monster_type = '' + def nearestPosition(self) -> Tuple[int, int]: """ Returns the nearest absolute dungeon tile the Mob is placed on. @@ -78,86 +162,3 @@ class Mob(arcade.Sprite): self.dungeon.grid.cleanup() return paths - -class Player(Mob): - """ - Represents a Player. - While this is a instance, there should only be one in the world at any given time. - """ - - def __init__(self, *args, **kwargs) -> None: - super(Player, self).__init__(*args, **kwargs) - - self.animations = PlayerAnimations(SpritePaths.KNIGHT) - # Used for mapping directions to animations - self.map = { - Enums.IDLE: self.animations.idles, - Enums.UP: self.animations.up, - Enums.DOWN: self.animations.down, - Enums.RIGHT: self.animations.right, - Enums.LEFT: self.animations.left - } - - self.refreshIndex = 0 - self.prev = Enums.IDLE - self.texture = next(self.map[self.prev]) - - def update_animation(self, delta_time: float = 1 / 60) -> None: - """ - Updates animations for the Player. - :param delta_time: No idea. - """ - - # Increase the refresh index according - self.refreshIndex = (self.refreshIndex + 1) % Config.RUN_UPDATES_PER_FRAME - - # Logic to determine what direction we're in. - if self.change_x == 0 and self.change_y == 0: - cur = Enums.IDLE - elif self.change_y > 0: # Up - cur = Enums.UP - elif self.change_y < 0: # Down - cur = Enums.DOWN - elif self.change_x > 0: # Left - cur = Enums.RIGHT - elif self.change_x < 0: # Right - cur = Enums.LEFT - else: # Idle - cur = Enums.IDLE - - # If we're in a new direction or the refresh index has reset - if self.prev is not cur or self.refreshIndex == 0: - self.texture = next(self.map[cur]) - - self.prev = cur - - def tick(self): - """ - While Player objects do not have any AI (they are controlled by the user), - the tick function can keep track of statistics that progress over time, like - regenerating health/armor or status effects like poison. - """ - - -class Enemy(Mob): - """ - Represents an Enemy Mob. - Will take basic offensive actions against Player objects. - """ - - def __init__(self, *args, **kwargs) -> None: - super(Enemy, self).__init__(*args, **kwargs) - - def tick(self) -> None: - """ - A on_update function, the Enemy Mob should scan for the player, decide how to path to it, and - decide how to take offensive action. - """ - pass - - def path(self) -> None: - """ - Not yet decided how this function should work. - Basically, most pathfinding decisions should be kept within this function. - """ - pass From 05a99006870e4f69004b30beedbc189c1eb942df Mon Sep 17 00:00:00 2001 From: Cameron Smart Date: Wed, 22 Apr 2020 21:58:33 -0700 Subject: [PATCH 12/14] Active recipe in top right corner. Shift cycles recipes. --- triple-dungeon/config.py | 2 +- triple-dungeon/main.py | 39 +++++++------------------- triple-dungeon/mobs.py | 2 +- triple-dungeon/recipe.py | 60 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 31 deletions(-) create mode 100644 triple-dungeon/recipe.py diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index 9a3b166..1a799cd 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -47,7 +47,7 @@ class Config(object): DEBUG = False #Monster Count to be spawned - MONSTER_COUNT = 20 + MONSTER_COUNT = 0 class Enums(Enum): diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index e1660f2..6466ba2 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -15,6 +15,7 @@ from config import Config from map import Dungeon from mobs import Player, Enemy from projectiles import Temp +from recipe import ActiveRecipe class FPSCounter: @@ -56,6 +57,7 @@ class Game(arcade.Window): self.physics_engine = None # Our physics engine # Used to keep track of our scrolling self.view_bottom = self.view_left = 0 + self.active_recipe = [] arcade.set_background_color(arcade.color.BLACK) @@ -78,6 +80,9 @@ class Game(arcade.Window): self.player.center_x, self.player.center_y = level.center() # x, y = level.center() + self.active_recipe = ActiveRecipe() + self.active_recipe.set_ghosts() + #Set up monsters for count in range(Config.MONSTER_COUNT): mob = Enemy(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) @@ -86,28 +91,7 @@ class Game(arcade.Window): mob.scale = 4 mob.monster_type = 'ghost' self.enemy_list.append(mob) - ''' - mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) - mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() - mob.target = self.player - mob.scale = 4 - self.enemy_list.append(mob) - mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) - mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() - mob.target = self.player - mob.scale = 4 - self.enemy_list.append(mob) - mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) - mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() - mob.target = self.player - mob.scale = 4 - self.enemy_list.append(mob) - mob = Mob(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) - mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() - mob.target = self.player - mob.scale = 4 - self.enemy_list.append(mob) - ''' + # Setup viewport self.view_bottom = self.player.center_x - (0.5 * Config.SCREEN_WIDTH) + 300 self.view_left = self.player.center_x - (0.5 * Config.SCREEN_WIDTH) @@ -116,10 +100,6 @@ class Game(arcade.Window): self.view_bottom, Config.SCREEN_HEIGHT + self.view_bottom) - # Create monsters - # self.enemy_list.append(Enemy("resources/images/monsters/ghost/ghost1.png", 200, 200, 4)) - # self.enemy_list.append(Enemy("resources/images/monsters/frog/frog1.png", 200, 1000, 4)) - # Create the 'physics engine' self.physics_engine = arcade.PhysicsEngineSimple(self.player, self.dungeon.getWalls()) @@ -135,6 +115,7 @@ class Game(arcade.Window): self.enemy_list.draw() self.active_enemies.draw() self.bullet_list.draw() + self.active_recipe.render() if Config.DEBUG: x, y = self.player.position @@ -191,6 +172,8 @@ class Game(arcade.Window): self.prev_keypress.append(key) elif key == 65307: self.close() + elif key == 65505: + self.active_recipe.next_recipe() def on_key_release(self, key, modifiers): """Called when the user releases a key. """ @@ -207,6 +190,7 @@ class Game(arcade.Window): elif key == arcade.key.RIGHT or key == arcade.key.D: self.player.change_x = 0 self.prev_keypress.remove(key) + if self.prev_keypress: self.on_key_press(self.prev_keypress.pop(0), 0) @@ -215,8 +199,6 @@ class Game(arcade.Window): Called whenever the mouse is clicked. """ - - # Create a bullet TEMP SPRITE, currently wielding frog slingshot bullet = Temp() # Position the bullet at the player's current location @@ -322,7 +304,6 @@ class Game(arcade.Window): self.player.add_kill(enemy_hit_list[0].monster_type) enemy_hit_list[0].remove_from_sprite_lists() - # If the bullet flies off-screen, remove it. TEMP change to range calc if ( bullet.bottom < self.view_bottom or diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index 7534c2d..cfb7e25 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -63,7 +63,7 @@ class Player(Mob): # Adds a kill to kill_list. If 3 or more check the recipe then give a power up if it matches. self.kill_list.append(creature) - if self.cur_recipe == self.kill_list: + if self.cur_recipe.sort() == self.kill_list.sort(): print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++") self.kill_list = [] diff --git a/triple-dungeon/recipe.py b/triple-dungeon/recipe.py new file mode 100644 index 0000000..11630a3 --- /dev/null +++ b/triple-dungeon/recipe.py @@ -0,0 +1,60 @@ +''' +Recipes are combinations of three monsters. When a player fills a recipe they get an updgrade +''' +import arcade + +from enum import Enum + + +class Recipe(Enum): + '''A class of different recipes''' + + GHOSTS = ['ghost', 'ghost', 'ghost'] + FROGS = ['frog', 'frog', 'frog'] + GHOST_FROG = ['ghost', 'ghost', 'frog'] + FROG_GHOST = ['ghost', 'frog', 'frog'] + + +class ActiveRecipe(arcade.SpriteList): + ''' + Keeps track of the active recipe and draws it. + ''' + + def __init__(self): + super().__init__() + self.active = Recipe.GHOSTS + self.cycle_recipes = [self.set_frogs, self.set_ghosts] + self.pos = 0 + + + def render(self) -> None: + x = 0 + for sprite in self.sprite_list: + screen_right = arcade.get_viewport()[1] - 100 + screen_top = arcade.get_viewport()[3] - 80 + sprite.scale = 4 + sprite.center_x = screen_right - x + sprite.center_y = screen_top + x += 70 + sprite.draw() + + def next_recipe(self): + + self.cycle_recipes[self.pos]() + self.pos += 1 + if self.pos == len(self.cycle_recipes): + self.pos = 0 + + def set_ghosts(self) -> None: + self.active = Recipe.GHOSTS + self.sprite_list = [] + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/ghost/ghost1.png")) + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/ghost/ghost1.png")) + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/ghost/ghost1.png")) + + def set_frogs(self) -> None: + self.active = Recipe.FROGS + self.sprite_list = [] + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/frog/frog1.png")) + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/frog/frog1.png")) + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/frog/frog1.png")) \ No newline at end of file From e9c8afa75858f0ae35544c906220a58fd0934a62 Mon Sep 17 00:00:00 2001 From: Cameron Smart Date: Wed, 22 Apr 2020 22:17:37 -0700 Subject: [PATCH 13/14] Added frogs. Linting. --- triple-dungeon/config.py | 6 +-- triple-dungeon/main.py | 34 ++++++++++------ triple-dungeon/mobs.py | 4 -- triple-dungeon/recipe.py | 88 ++++++++++++++++++++-------------------- 4 files changed, 69 insertions(+), 63 deletions(-) diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index 1a799cd..ddf7fc0 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -45,9 +45,9 @@ class Config(object): # All debug statements and renderings should use this DEBUG = False - - #Monster Count to be spawned - MONSTER_COUNT = 0 + + # Monster Count to be spawned + MONSTER_COUNT = 6 class Enums(Enum): diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index 6466ba2..430c93a 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -83,14 +83,21 @@ class Game(arcade.Window): self.active_recipe = ActiveRecipe() self.active_recipe.set_ghosts() - #Set up monsters - for count in range(Config.MONSTER_COUNT): + # Set up monsters + for count in range(Config.MONSTER_COUNT//2): mob = Enemy(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() mob.target = self.player mob.scale = 4 mob.monster_type = 'ghost' self.enemy_list.append(mob) + for count in range(Config.MONSTER_COUNT//2): + mob = Enemy(filename="resources/images/monsters/frog/frog1.png", dungeon=self.dungeon) + mob.center_x, mob.center_y = random.choice(self.dungeon.levelList).center() + mob.target = self.player + mob.scale = 4 + mob.monster_type = 'frog' + self.enemy_list.append(mob) # Setup viewport self.view_bottom = self.player.center_x - (0.5 * Config.SCREEN_WIDTH) + 300 @@ -122,10 +129,10 @@ class Game(arcade.Window): arcade.draw_rectangle_outline(round(x / Config.TILE_SIZE) * Config.TILE_SIZE, round(y / Config.TILE_SIZE) * Config.TILE_SIZE, Config.TILE_SIZE, Config.TILE_SIZE, arcade.color.RED) - #self.player.draw_hit_box() - #arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') - #arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, - # arcade.color.WHITE, 16, font_name='Arial') + self.player.draw_hit_box() + arcade.draw_text(str((x, y)), x - 40, y + 50, arcade.color.WHITE, 15, font_name='Arial') + arcade.draw_text(f"FPS: {self.fps.get_fps():3.0f}", self.view_left + 50, self.view_bottom + 30, + arcade.color.WHITE, 16, font_name='Arial') # Draw paths for all mobs for mob in self.active_enemies: @@ -133,8 +140,8 @@ class Game(arcade.Window): t1 = time.time() path = mob.get_path() t2 = time.time() - #print(f'Path acquired in {round(t2 - t1, 4)}s') - #self.draw_path(path) + print(f'Path acquired in {round(t2 - t1, 4)}s') + self.draw_path(path) mob.tick(path) self.fps.tick() @@ -271,7 +278,7 @@ class Game(arcade.Window): Config.SCREEN_WIDTH + self.view_left, self.view_bottom, Config.SCREEN_HEIGHT + self.view_bottom) - #Enemy activation and update + # Enemy activation and update for enemy in reversed(self.enemy_list): if ( enemy.bottom > self.view_bottom and @@ -279,9 +286,10 @@ class Game(arcade.Window): enemy.right < self.view_left + Config.SCREEN_WIDTH and enemy.left > self.view_left ): - if Config.DEBUG: print("Activate Enemy") - self.active_enemies.append(enemy) - self.enemy_list.remove(enemy) + if Config.DEBUG: + print("Activate Enemy") + self.active_enemies.append(enemy) + self.enemy_list.remove(enemy) try: for enemy in self.active_enemies: enemy.update() @@ -293,7 +301,7 @@ class Game(arcade.Window): # Projectile updates self.bullet_list.update() for bullet in self.bullet_list: - + # Collision Checks hit_list = arcade.check_for_collision_with_list(bullet, self.dungeon.getWalls()) enemy_hit_list = arcade.check_for_collision_with_list(bullet, self.active_enemies) diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index cfb7e25..82c2546 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -32,8 +32,6 @@ class Mob(arcade.Sprite): self.target = None - - class Player(Mob): """ Represents a Player. @@ -67,7 +65,6 @@ class Player(Mob): print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++") self.kill_list = [] - def update_animation(self, delta_time: float = 1 / 60) -> None: """ Updates animations for the Player. @@ -161,4 +158,3 @@ class Enemy(Mob): paths, runs = self.dungeon.finder.find_path(start, end, self.dungeon.grid) self.dungeon.grid.cleanup() return paths - diff --git a/triple-dungeon/recipe.py b/triple-dungeon/recipe.py index 11630a3..c8e5f3f 100644 --- a/triple-dungeon/recipe.py +++ b/triple-dungeon/recipe.py @@ -1,60 +1,62 @@ ''' Recipes are combinations of three monsters. When a player fills a recipe they get an updgrade ''' + import arcade from enum import Enum class Recipe(Enum): - '''A class of different recipes''' - - GHOSTS = ['ghost', 'ghost', 'ghost'] - FROGS = ['frog', 'frog', 'frog'] - GHOST_FROG = ['ghost', 'ghost', 'frog'] - FROG_GHOST = ['ghost', 'frog', 'frog'] + ''' + A class of different recipes + ''' + + GHOSTS = ['ghost', 'ghost', 'ghost'] + FROGS = ['frog', 'frog', 'frog'] + GHOST_FROG = ['ghost', 'ghost', 'frog'] + FROG_GHOST = ['ghost', 'frog', 'frog'] class ActiveRecipe(arcade.SpriteList): - ''' - Keeps track of the active recipe and draws it. - ''' + ''' + Keeps track of the active recipe and draws it. + ''' - def __init__(self): - super().__init__() - self.active = Recipe.GHOSTS - self.cycle_recipes = [self.set_frogs, self.set_ghosts] - self.pos = 0 - + def __init__(self): + super().__init__() + self.active = Recipe.GHOSTS + self.cycle_recipes = [self.set_frogs, self.set_ghosts] + self.pos = 0 - def render(self) -> None: - x = 0 - for sprite in self.sprite_list: - screen_right = arcade.get_viewport()[1] - 100 - screen_top = arcade.get_viewport()[3] - 80 - sprite.scale = 4 - sprite.center_x = screen_right - x - sprite.center_y = screen_top - x += 70 - sprite.draw() + def render(self) -> None: + x = 0 + for sprite in self.sprite_list: + screen_right = arcade.get_viewport()[1] - 100 + screen_top = arcade.get_viewport()[3] - 80 + sprite.scale = 4 + sprite.center_x = screen_right - x + sprite.center_y = screen_top + x += 70 + sprite.draw() - def next_recipe(self): - - self.cycle_recipes[self.pos]() - self.pos += 1 - if self.pos == len(self.cycle_recipes): - self.pos = 0 + def next_recipe(self): + + self.cycle_recipes[self.pos]() + self.pos += 1 + if self.pos == len(self.cycle_recipes): + self.pos = 0 - def set_ghosts(self) -> None: - self.active = Recipe.GHOSTS - self.sprite_list = [] - self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/ghost/ghost1.png")) - self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/ghost/ghost1.png")) - self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/ghost/ghost1.png")) + def set_ghosts(self) -> None: + self.active = Recipe.GHOSTS + self.sprite_list = [] + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/ghost/ghost1.png")) + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/ghost/ghost1.png")) + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/ghost/ghost1.png")) - def set_frogs(self) -> None: - self.active = Recipe.FROGS - self.sprite_list = [] - self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/frog/frog1.png")) - self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/frog/frog1.png")) - self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/frog/frog1.png")) \ No newline at end of file + def set_frogs(self) -> None: + self.active = Recipe.FROGS + self.sprite_list = [] + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/frog/frog1.png")) + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/frog/frog1.png")) + self.sprite_list.append(arcade.Sprite(filename="resources/images/monsters/frog/frog1.png")) From 9c26aa156f7ebc91c927a1720d2ae55506fdad5d Mon Sep 17 00:00:00 2001 From: Cameron Smart Date: Wed, 22 Apr 2020 23:11:36 -0700 Subject: [PATCH 14/14] Shift key to cycle recipes --- triple-dungeon/config.py | 2 +- triple-dungeon/main.py | 19 +++++++++++-------- triple-dungeon/mobs.py | 9 ++++++--- triple-dungeon/recipe.py | 5 +---- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/triple-dungeon/config.py b/triple-dungeon/config.py index ddf7fc0..393d685 100644 --- a/triple-dungeon/config.py +++ b/triple-dungeon/config.py @@ -47,7 +47,7 @@ class Config(object): DEBUG = False # Monster Count to be spawned - MONSTER_COUNT = 6 + MONSTER_COUNT = 10 class Enums(Enum): diff --git a/triple-dungeon/main.py b/triple-dungeon/main.py index 430c93a..2ecb526 100644 --- a/triple-dungeon/main.py +++ b/triple-dungeon/main.py @@ -73,16 +73,18 @@ class Game(arcade.Window): # Create the dungeon self.dungeon = Dungeon(0, 3) + # Set up recipes + self.active_recipe = ActiveRecipe() + self.active_recipe.set_ghosts() + # Set up the player, specifically placing it at these coordinates. self.player = Player(self.dungeon) self.player.scale = 1 level = random.choice(self.dungeon.levelList) self.player.center_x, self.player.center_y = level.center() + self.player.cur_recipe = self.active_recipe.active # x, y = level.center() - self.active_recipe = ActiveRecipe() - self.active_recipe.set_ghosts() - # Set up monsters for count in range(Config.MONSTER_COUNT//2): mob = Enemy(filename="resources/images/monsters/ghost/ghost1.png", dungeon=self.dungeon) @@ -181,6 +183,7 @@ class Game(arcade.Window): self.close() elif key == 65505: self.active_recipe.next_recipe() + self.player.cur_recipe = self.active_recipe.active def on_key_release(self, key, modifiers): """Called when the user releases a key. """ @@ -281,12 +284,12 @@ class Game(arcade.Window): # Enemy activation and update for enemy in reversed(self.enemy_list): if ( - enemy.bottom > self.view_bottom and - enemy.top < self.view_bottom + Config.SCREEN_HEIGHT and - enemy.right < self.view_left + Config.SCREEN_WIDTH and - enemy.left > self.view_left + enemy.bottom > self.view_bottom and + enemy.top < self.view_bottom + Config.SCREEN_HEIGHT and + enemy.right < self.view_left + Config.SCREEN_WIDTH and + enemy.left > self.view_left ): - if Config.DEBUG: + if Config.DEBUG: print("Activate Enemy") self.active_enemies.append(enemy) self.enemy_list.remove(enemy) diff --git a/triple-dungeon/mobs.py b/triple-dungeon/mobs.py index 82c2546..9560f13 100644 --- a/triple-dungeon/mobs.py +++ b/triple-dungeon/mobs.py @@ -55,15 +55,18 @@ class Player(Mob): self.prev = Enums.IDLE self.texture = next(self.map[self.prev]) self.kill_list = [] - self.cur_recipe = ['ghost', 'ghost', 'ghost'] + self.cur_recipe = None def add_kill(self, creature): # Adds a kill to kill_list. If 3 or more check the recipe then give a power up if it matches. - self.kill_list.append(creature) - if self.cur_recipe.sort() == self.kill_list.sort(): + print(self.kill_list) + print(self.cur_recipe) + if self.cur_recipe == self.kill_list: print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++") self.kill_list = [] + elif len(self.kill_list) >= 3: + self.kill_list = [] def update_animation(self, delta_time: float = 1 / 60) -> None: """ diff --git a/triple-dungeon/recipe.py b/triple-dungeon/recipe.py index c8e5f3f..2a35ca0 100644 --- a/triple-dungeon/recipe.py +++ b/triple-dungeon/recipe.py @@ -4,10 +4,8 @@ Recipes are combinations of three monsters. When a player fills a recipe they ge import arcade -from enum import Enum - -class Recipe(Enum): +class Recipe: ''' A class of different recipes ''' @@ -41,7 +39,6 @@ class ActiveRecipe(arcade.SpriteList): sprite.draw() def next_recipe(self): - self.cycle_recipes[self.pos]() self.pos += 1 if self.pos == len(self.cycle_recipes):