diff --git a/.DS_Store b/.DS_Store index 746009c..13f2c08 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/agents/ppo/.DS_Store b/agents/ppo/.DS_Store new file mode 100644 index 0000000..1776c5d Binary files /dev/null and b/agents/ppo/.DS_Store differ diff --git a/agents/saved_models/A0 b/agents/saved_models/A0 index f675985..63dd231 100644 Binary files a/agents/saved_models/A0 and b/agents/saved_models/A0 differ diff --git a/agents/saved_models/C0 b/agents/saved_models/C0 index 8ae113c..4c96720 100644 Binary files a/agents/saved_models/C0 and b/agents/saved_models/C0 differ diff --git a/assets/.DS_Store b/assets/.DS_Store new file mode 100644 index 0000000..7daf92c Binary files /dev/null and b/assets/.DS_Store differ diff --git a/assets/graphics/.DS_Store b/assets/graphics/.DS_Store new file mode 100644 index 0000000..e2d53d3 Binary files /dev/null and b/assets/graphics/.DS_Store differ diff --git a/assets/graphics/particles/.DS_Store b/assets/graphics/particles/.DS_Store new file mode 100644 index 0000000..847d9f0 Binary files /dev/null and b/assets/graphics/particles/.DS_Store differ diff --git a/assets/map/.DS_Store b/assets/map/.DS_Store new file mode 100644 index 0000000..ce03a6c Binary files /dev/null and b/assets/map/.DS_Store differ diff --git a/assets/map/Entities.csv b/assets/map/Entities.csv index 54888e1..88c8391 100644 --- a/assets/map/Entities.csv +++ b/assets/map/Entities.csv @@ -18,8 +18,8 @@ -1,-1,-1,-1,-1,-1,-1,-1,-1,393,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,390,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,390,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 --1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,390,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,500,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 --1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,390,-1,-1,400,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,390,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,400,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,393,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,390,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -1,-1,-1,-1,-1,-1,390,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 diff --git a/camera.py b/camera.py index 842fe1b..19999fa 100644 --- a/camera.py +++ b/camera.py @@ -11,9 +11,7 @@ class Camera(pygame.sprite.Group): # General Setup self.display_surface = pygame.display.get_surface() - self.half_width = self.display_surface.get_size()[0] // 2 - self.half_height = self.display_surface.get_size()[1] // 2 - self.offset = pygame.math.Vector2(100, 200) + self.display_size = self.display_surface.get_size() self.floor_surf = pygame.image.load( import_assets( @@ -25,32 +23,45 @@ class Camera(pygame.sprite.Group): self.floor_rect = self.floor_surf.get_rect(topleft=(0, 0)) - def custom_draw(self, entity): + self.calculate_scale() - self.sprite_type = entity.sprite_type - # Getting the offset - if hasattr(entity, 'animation'): - self.offset.x = entity.animation.rect.centerx - self.half_width + def calculate_scale(self): + map_width, map_height = self.floor_rect.size + screen_width, screen_height = self.display_size - self.offset.y = entity.animation.rect.centery - self.half_height + # Calculating the scale to fit the map on the screen + self.scale = min(screen_width / map_width, screen_height / map_height) + self.scaled_floor_surf = pygame.transform.scale(self.floor_surf, + (int(map_width * self.scale), + int(map_height * self.scale))) + self.scaled_floor_rect = self.scaled_floor_surf.get_rect() - else: - self.offset.x = entity.rect.centerx - self.half_width - - self.offset.y = entity.rect.centery - self.half_height - - # Drawing the floor - floor_offset_pos = self.floor_rect.topleft - self.offset - self.display_surface.blit(self.floor_surf, floor_offset_pos) - - for sprite in sorted(self.sprites(), - key=lambda sprite: sprite.animation.rect.centery - if hasattr(sprite, 'animation') - else sprite.rect.centery): + def custom_draw(self): + # Drawing the scaled floor + self.display_surface.blit( + self.scaled_floor_surf, self.scaled_floor_rect.topleft) + for sprite in sorted(self.sprites(), key=lambda sprite: sprite.rect.centery if not hasattr(sprite, 'animation') else sprite.animation.rect.centery): + # Check for sprites with 'animation' attribute if hasattr(sprite, 'animation'): - offset_pos = sprite.animation.rect.topleft - self.offset - self.display_surface.blit(sprite.animation.image, offset_pos) + scaled_sprite_image = pygame.transform.scale(sprite.animation.image, + (int(sprite.animation.rect.width * self.scale), + int(sprite.animation.rect.height * self.scale))) + scaled_position = (int(sprite.animation.rect.x * self.scale), + int(sprite.animation.rect.y * self.scale)) + for sprite in sorted(self.sprites(), key=lambda sprite: sprite.rect.centery if not hasattr(sprite, 'animation') else sprite.animation.rect.centery): + # Check for sprites with 'animation' attribute + if hasattr(sprite, 'animation'): + scaled_sprite_image = pygame.transform.scale(sprite.animation.image, + (int(sprite.animation.rect.width * self.scale), + int(sprite.animation.rect.height * self.scale))) + scaled_position = (int(sprite.animation.rect.x * self.scale), + int(sprite.animation.rect.y * self.scale)) else: - offset_pos = sprite.rect.topleft - self.offset - self.display_surface.blit(sprite.image, offset_pos) + scaled_sprite_image = pygame.transform.scale(sprite.image, + (int(sprite.rect.width * self.scale), + int(sprite.rect.height * self.scale))) + scaled_position = (int(sprite.rect.x * self.scale), + int(sprite.rect.y * self.scale)) + + self.display_surface.blit(scaled_sprite_image, scaled_position) diff --git a/configs/.DS_Store b/configs/.DS_Store new file mode 100644 index 0000000..e2069c7 Binary files /dev/null and b/configs/.DS_Store differ diff --git a/effects/.DS_Store b/effects/.DS_Store new file mode 100644 index 0000000..84be986 Binary files /dev/null and b/effects/.DS_Store differ diff --git a/entities/.DS_Store b/entities/.DS_Store new file mode 100644 index 0000000..e31aec4 Binary files /dev/null and b/entities/.DS_Store differ diff --git a/entities/player.py b/entities/player.py index 1260052..8fb0e97 100644 --- a/entities/player.py +++ b/entities/player.py @@ -148,14 +148,6 @@ class Player(pygame.sprite.Sprite): def get_current_state(self): - def fermi(x, a): - # Used for rescaling features - return 1 / (np.exp((x - a)) + 1) - - def maxwell(x, a): - # Used for rescaling features - return 1 / np.exp((x - a) / a) - if self.distance_direction_from_enemy != []: sorted_distances = sorted( self.distance_direction_from_enemy, key=lambda x: x[0]) @@ -166,32 +158,11 @@ class Player(pygame.sprite.Sprite): self.action_features = [self._input.action] - self.reward = [ - np.log(1 + self.stats.exp) if self.stats.exp >= 0 else -10, - - fermi(nearest_dist, 300), - - fermi( - nearest_enemy.stats.health, - nearest_enemy.stats.monster_info['health'] - ), - - maxwell( - len(self.distance_direction_from_enemy), - self.max_num_enemies - ) - 1, - - - fermi( - self.stats.health, - self.stats.stats['health'] - ) - ] - - # self.reward = self.stats.exp\ - # + self.stats.health/self.stats.stats['health'] - 1\ - # - nearest_dist/np.sqrt(np.sum(self.map_edge))\ - # - nearest_enemy.stats.health/nearest_enemy.stats.monster_info['health']\ - # - 2*len(self.distance_direction_from_enemy)/self.max_num_enemies + self.reward = self.stats.exp\ + + self.stats.health/self.stats.stats['health'] - 1\ + - nearest_dist/np.sqrt(np.sum(self.map_edge))\ + - nearest_enemy.stats.health/nearest_enemy.stats.monster_info['health']\ + - 2*len(self.distance_direction_from_enemy)/self.max_num_enemies self.state_features = [ self.animation.rect.center[0]/self.map_edge[0], @@ -204,10 +175,8 @@ class Player(pygame.sprite.Sprite): ] - enemy_states = [] - for distance, direction, enemy in self.distance_direction_from_enemy: - enemy_states.extend([ + self.state_features.extend([ distance/np.sqrt(np.sum(self.map_edge)), @@ -215,14 +184,12 @@ class Player(pygame.sprite.Sprite): direction[1], - nearest_enemy.stats.health / - nearest_enemy.stats.monster_info['health'], + enemy.stats.health / + enemy.stats.monster_info['health'], enemy.stats.exp, ]) - self.state_features.extend(enemy_states) - if hasattr(self, 'num_features'): while len(self.state_features) < self.num_features: self.state_features.append(0) @@ -255,7 +222,7 @@ class Player(pygame.sprite.Sprite): self) self.agent.remember(self.state_features, action, - probs, value, self.stats.exp, self.is_dead()) + probs, value, self.reward, self.is_dead()) self.get_current_state() diff --git a/entities/terrain.py b/entities/terrain.py index ac02b77..31a0b27 100644 --- a/entities/terrain.py +++ b/entities/terrain.py @@ -27,4 +27,5 @@ class Terrain(pygame.sprite.Sprite): topleft=(position[0], position[1] - TILESIZE)) else: self.rect = self.image.get_rect(topleft=position) + self.hitbox = self.rect.inflate(HITBOX_OFFSET[sprite_type]) diff --git a/figures/.DS_Store b/figures/.DS_Store new file mode 100644 index 0000000..2e4e618 Binary files /dev/null and b/figures/.DS_Store differ diff --git a/figures/actor_loss.png b/figures/actor_loss.png index bf947fd..73bb246 100644 Binary files a/figures/actor_loss.png and b/figures/actor_loss.png differ diff --git a/figures/critic_loss.png b/figures/critic_loss.png index 19147f6..882c2e0 100644 Binary files a/figures/critic_loss.png and b/figures/critic_loss.png differ diff --git a/figures/score.png b/figures/score.png index 5fb8a5f..0fd60cd 100644 Binary files a/figures/score.png and b/figures/score.png differ diff --git a/figures/total_loss.png b/figures/total_loss.png index 766f492..f738615 100644 Binary files a/figures/total_loss.png and b/figures/total_loss.png differ diff --git a/game.py b/game.py index 67e6d18..d6c48ea 100644 --- a/game.py +++ b/game.py @@ -1,16 +1,13 @@ -import os - -os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" - -import sys -import pygame - -from level import Level - from configs.system.window_config import WIDTH,\ HEIGHT,\ WATER_COLOR,\ FPS +from level import Level +import pygame +import sys +import os + +os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" class Game: @@ -44,8 +41,6 @@ class Game: def run(self): - self.clock = pygame.time.Clock() - for event in pygame.event.get(): if event.type == pygame.QUIT: self.quit() @@ -55,10 +50,9 @@ class Game: self.screen.fill(WATER_COLOR) - self.level.run('observer', self.clock.get_fps()) + self.level.run() pygame.display.update() - self.clock.tick(FPS) def quit(self): pygame.quit() diff --git a/interface/ui.py b/interface/ui.py index a01d7c2..c2b476a 100644 --- a/interface/ui.py +++ b/interface/ui.py @@ -108,24 +108,5 @@ class UI: self.display_surface.blit(magic_surf, magic_rect) - def display(self, player): - if player.sprite_type == 'player': - self.show_bar( - player.stats.health, - player.stats.stats['health'], - self.health_bar_rect, - HEALTH_COLOR) - - self.show_bar( - player.stats.energy, - player.stats.stats['energy'], - self.energy_bar_rect, - ENERGY_COLOR) - - self.show_exp(player.stats.exp) - self.weapon_overlay(player._input.combat.weapon_index, - player._input.can_rotate_weapon) - self.magic_overlay(player._input.combat.magic_index, - player._input.can_swap_magic) - if player.sprite_type == 'camera': - self.show_exp(player.exp) + def display(self): + self.show_exp(-1) diff --git a/level.py b/level.py index 44af9f6..671514d 100644 --- a/level.py +++ b/level.py @@ -85,57 +85,48 @@ class Level: elif col != '700': Terrain((x, y), - [self.obstacle_sprites, - self.visible_sprites], + [self.obstacle_sprites], 'invisible') elif col == '700' and self.n_players > 1: print(f"Prison set at:{(x, y)}") # Generate grass - # if style == 'grass': - # random_grass_image = choice(self.graphics['grass']) - # - # Terrain((x, y), [ - # self.visible_sprites, - # self.obstacle_sprites, - # self.attackable_sprites - # ], - # 'grass', - # random_grass_image) + if style == 'grass': + random_grass_image = choice(self.graphics['grass']) + + Terrain((x, y), [ + self.visible_sprites, + self.obstacle_sprites, + self.attackable_sprites + ], + 'grass', + random_grass_image) # Generate objects like trees and statues - # if style == 'objects': - # surface = self.graphics['objects'][int(col)] - # Terrain((x, y), [ - # self.visible_sprites, - # self.obstacle_sprites - # ], - # 'object', - # surface) + if style == 'objects': + surface = self.graphics['objects'][int(col)] + Terrain((x, y), [ + self.visible_sprites, + self.obstacle_sprites + ], + 'object', + surface) # Generate observer, players and monsters if style == 'entities': - # Generate observer - if col == '500': - self.observer = Observer( - (x, y), - [self.visible_sprites] - ) - # Generate player(s) - # TODO: Make a way to generate players in random locations - elif col == '400': + if col == '400': self.possible_player_locations.append((x, y)) - # Monster generation - else: + # Monster generation + elif col in ['390', '391', '392', '393']: if col == '390': monster_name = 'bamboo' elif col == '391': monster_name = 'spirit' elif col == '392': monster_name = 'raccoon' - elif col == ' 393': + elif col == '393': monster_name = 'squid' Enemy(name=monster_name, position=(x, y), @@ -171,35 +162,29 @@ class Level: if int(col) != -1: x = col_index * TILESIZE y = row_index * TILESIZE - # # Regenerate grass - # if style == 'grass': - # random_grass_image = choice( - # self.graphics['grass']) - # - # Terrain((x, y), [ - # self.visible_sprites, - # self.obstacle_sprites, - # self.attackable_sprites - # ], - # 'grass', - # random_grass_image) + # Regenerate grass + if style == 'grass': + random_grass_image = choice( + self.graphics['grass']) + + Terrain((x, y), [ + self.visible_sprites, + self.obstacle_sprites, + self.attackable_sprites + ], + 'grass', + random_grass_image) if style == 'entities': - if col == '500': - continue - - if col == '400': - continue - - else: + if col in ['390', '391', '392', '393']: if col == '390': monster_name = 'bamboo' elif col == '391': monster_name = 'spirit' elif col == '392': monster_name = 'raccoon' - elif col == ' 393': + elif col == '393': monster_name = 'squid' Enemy(monster_name, @@ -287,12 +272,10 @@ class Level: def toggle_pause(self): self.paused = not self.paused - def run(self, who='observer', fps='v0.9'): + def run(self): # Draw the game - self.visible_sprites.custom_draw(self.observer) - self.ui.display(self.observer) - - debug(f"{fps}") + self.visible_sprites.custom_draw() + self.ui.display() if not self.paused: # Update the game @@ -310,7 +293,7 @@ class Level: for player in self.player_sprites: if player.is_dead(): - print(f"\nPlayer {player.player_id} is dead") + print(f"\nPlayer {player.player_id} is dead\n") player.stats.exp = -10 player.update() self.dead_players[player.player_id] = player.is_dead() diff --git a/pneuma.py b/pneuma.py index 49bab8d..57bb83f 100644 --- a/pneuma.py +++ b/pneuma.py @@ -182,8 +182,7 @@ if __name__ == "__main__": for player in game.level.player_sprites: - episode_reward[player.player_id][step] = np.mean( - player.reward) + episode_reward[player.player_id][step] = player.reward if (step % horizon == 0 and step != 0) or player.is_dead():