Used inheritance, fixed metrics bugs and fixed save location
This commit is contained in:
parent
ef78027ba7
commit
936674419b
25 changed files with 1524 additions and 278 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -165,4 +165,4 @@ cython_debug/
|
||||||
# Random stuff
|
# Random stuff
|
||||||
__pycache__/
|
__pycache__/
|
||||||
chkpts/
|
chkpts/
|
||||||
figures/
|
figures/
|
||||||
|
|
BIN
assets/.DS_Store
vendored
BIN
assets/.DS_Store
vendored
Binary file not shown.
BIN
assets/map/.DS_Store
vendored
BIN
assets/map/.DS_Store
vendored
Binary file not shown.
|
@ -25,6 +25,15 @@ warrior_stats = {
|
||||||
'speed': 5
|
'speed': 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base_stats = {
|
||||||
|
'role_id': 0,
|
||||||
|
'health': 150,
|
||||||
|
'energy': 70,
|
||||||
|
'attack': 10,
|
||||||
|
'magic': 5,
|
||||||
|
'speed': 5
|
||||||
|
}
|
||||||
|
|
||||||
max_stats = {
|
max_stats = {
|
||||||
'health': 300,
|
'health': 300,
|
||||||
'energy': 150,
|
'energy': 150,
|
||||||
|
|
BIN
effects/.DS_Store
vendored
BIN
effects/.DS_Store
vendored
Binary file not shown.
|
@ -9,31 +9,31 @@ class MagicPlayer:
|
||||||
self.animation_player = animation_player
|
self.animation_player = animation_player
|
||||||
|
|
||||||
def heal(self, player, strength, cost, groups):
|
def heal(self, player, strength, cost, groups):
|
||||||
if player.stats.energy >= cost:
|
if player.energy >= cost:
|
||||||
self.sounds['heal'].play()
|
self.sounds['heal'].play()
|
||||||
player.stats.health += strength
|
player.health += strength
|
||||||
player.stats.energy -= cost
|
player.energy -= cost
|
||||||
if player.stats.health >= player.stats.stats['health']:
|
if player.health >= player.stats['health']:
|
||||||
player.stats.health = player.stats.stats['health']
|
player.health = player.stats['health']
|
||||||
self.animation_player.generate_particles(
|
self.animation_player.generate_particles(
|
||||||
'aura',
|
'aura',
|
||||||
player.animation.rect.center,
|
player.rect.center,
|
||||||
groups)
|
groups)
|
||||||
|
|
||||||
self.animation_player.generate_particles(
|
self.animation_player.generate_particles(
|
||||||
'heal',
|
'heal',
|
||||||
player.animation.rect.center + pygame.math.Vector2(0, -50),
|
player.rect.center + pygame.math.Vector2(0, -50),
|
||||||
groups)
|
groups)
|
||||||
|
|
||||||
def flame(self, player, cost, groups):
|
def flame(self, player, cost, groups):
|
||||||
if player.stats.energy >= cost:
|
if player.energy >= cost:
|
||||||
player.stats.energy -= cost
|
player.energy -= cost
|
||||||
|
|
||||||
if player._input.status.split('_')[0] == 'right':
|
if player.status.split('_')[0] == 'right':
|
||||||
direction = pygame.math.Vector2(1, 0)
|
direction = pygame.math.Vector2(1, 0)
|
||||||
elif player._input.status.split('_')[0] == 'left':
|
elif player.status.split('_')[0] == 'left':
|
||||||
direction = pygame.math.Vector2(-1, 0)
|
direction = pygame.math.Vector2(-1, 0)
|
||||||
elif player._input.status.split('_')[0] == 'up':
|
elif player.status.split('_')[0] == 'up':
|
||||||
direction = pygame.math.Vector2(0, -1)
|
direction = pygame.math.Vector2(0, -1)
|
||||||
else:
|
else:
|
||||||
direction = pygame.math.Vector2(0, 1)
|
direction = pygame.math.Vector2(0, 1)
|
||||||
|
@ -41,17 +41,17 @@ class MagicPlayer:
|
||||||
for i in range(1, 6):
|
for i in range(1, 6):
|
||||||
if direction.x:
|
if direction.x:
|
||||||
offset_x = direction.x * i * TILESIZE
|
offset_x = direction.x * i * TILESIZE
|
||||||
x = player.animation.rect.centerx + offset_x + \
|
x = player.rect.centerx + offset_x + \
|
||||||
randint(-TILESIZE // 3, TILESIZE // 3)
|
randint(-TILESIZE // 3, TILESIZE // 3)
|
||||||
y = player.animation.rect.centery + \
|
y = player.rect.centery + \
|
||||||
randint(-TILESIZE // 3, TILESIZE // 3)
|
randint(-TILESIZE // 3, TILESIZE // 3)
|
||||||
self.animation_player.generate_particles(
|
self.animation_player.generate_particles(
|
||||||
'flame', (x, y), groups)
|
'flame', (x, y), groups)
|
||||||
else:
|
else:
|
||||||
offset_y = direction.y * i * TILESIZE
|
offset_y = direction.y * i * TILESIZE
|
||||||
x = player.animation.rect.centerx + \
|
x = player.rect.centerx + \
|
||||||
randint(-TILESIZE // 3, TILESIZE // 3)
|
randint(-TILESIZE // 3, TILESIZE // 3)
|
||||||
y = player.animation.rect.centery + offset_y + \
|
y = player.rect.centery + offset_y + \
|
||||||
randint(-TILESIZE // 3, TILESIZE // 3)
|
randint(-TILESIZE // 3, TILESIZE // 3)
|
||||||
self.animation_player.generate_particles(
|
self.animation_player.generate_particles(
|
||||||
'flame', (x, y), groups)
|
'flame', (x, y), groups)
|
||||||
|
|
|
@ -10,26 +10,26 @@ class Weapon(pygame.sprite.Sprite):
|
||||||
super().__init__(groups)
|
super().__init__(groups)
|
||||||
|
|
||||||
self.sprite_type = 'weapon'
|
self.sprite_type = 'weapon'
|
||||||
direction = player._input.status.split('_')[0]
|
direction = player.status.split('_')[0]
|
||||||
|
|
||||||
# Graphic
|
# Graphic
|
||||||
self.image = pygame.image.load(import_assets(os.path.join(
|
self.image = pygame.image.load(import_assets(os.path.join(
|
||||||
'graphics',
|
'graphics',
|
||||||
'weapons',
|
'weapons',
|
||||||
player._input.combat.weapon,
|
player.weapon,
|
||||||
f"{direction}.png"))
|
f"{direction}.png"))
|
||||||
).convert_alpha()
|
).convert_alpha()
|
||||||
|
|
||||||
# Sprite Placement
|
# Sprite Placement
|
||||||
if direction == 'right':
|
if direction == 'right':
|
||||||
self.rect = self.image.get_rect(
|
self.rect = self.image.get_rect(
|
||||||
midleft=player.animation.rect.midright + pygame.math.Vector2(0, 16))
|
midleft=player.rect.midright + pygame.math.Vector2(0, 16))
|
||||||
elif direction == 'left':
|
elif direction == 'left':
|
||||||
self.rect = self.image.get_rect(
|
self.rect = self.image.get_rect(
|
||||||
midright=player.animation.rect.midleft + pygame.math.Vector2(0, 16))
|
midright=player.rect.midleft + pygame.math.Vector2(0, 16))
|
||||||
elif direction == 'down':
|
elif direction == 'down':
|
||||||
self.rect = self.image.get_rect(
|
self.rect = self.image.get_rect(
|
||||||
midtop=player.animation.rect.midbottom + pygame.math.Vector2(-10, 0))
|
midtop=player.rect.midbottom + pygame.math.Vector2(-10, 0))
|
||||||
else:
|
else:
|
||||||
self.rect = self.image.get_rect(
|
self.rect = self.image.get_rect(
|
||||||
midbottom=player.animation.rect.midtop + pygame.math.Vector2(-10, 0))
|
midbottom=player.rect.midtop + pygame.math.Vector2(-10, 0))
|
||||||
|
|
BIN
entities/.DS_Store
vendored
BIN
entities/.DS_Store
vendored
Binary file not shown.
0
entities/__init__.py
Normal file
0
entities/__init__.py
Normal file
|
@ -3,25 +3,26 @@ from random import randint, choice
|
||||||
|
|
||||||
from config.game.spell_config import magic_data
|
from config.game.spell_config import magic_data
|
||||||
from config.game.weapon_config import weapon_data
|
from config.game.weapon_config import weapon_data
|
||||||
|
#
|
||||||
from .movement import MovementHandler
|
from .movement import MovementHandler
|
||||||
from .combat import CombatHandler
|
from .combat import CombatHandler
|
||||||
|
|
||||||
|
|
||||||
class InputHandler:
|
class InputHandler(MovementHandler, CombatHandler):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
MovementHandler.__init__(self)
|
||||||
|
CombatHandler.__init__(self)
|
||||||
|
|
||||||
def __init__(self, sprite_type, animation_player, ai_controller=False):
|
|
||||||
self.status = 'down'
|
self.status = 'down'
|
||||||
self.sprite_type = sprite_type
|
|
||||||
|
|
||||||
# Setup Movement
|
# Setup Movement
|
||||||
self.movement = MovementHandler(self.sprite_type)
|
|
||||||
self.move_cooldown = 15
|
self.move_cooldown = 15
|
||||||
self.can_move = True
|
self.can_move = True
|
||||||
self.move_time = None
|
self.move_time = None
|
||||||
|
|
||||||
# Setup Combat
|
# Setup Combat
|
||||||
self.combat = CombatHandler(animation_player)
|
|
||||||
self.attacking = False
|
self.attacking = False
|
||||||
self.attack_cooldown = 400
|
self.attack_cooldown = 400
|
||||||
self.attack_time = None
|
self.attack_time = None
|
||||||
|
@ -35,7 +36,7 @@ class InputHandler:
|
||||||
self.magic_swap_time = None
|
self.magic_swap_time = None
|
||||||
|
|
||||||
# Setup Action Space
|
# Setup Action Space
|
||||||
self.possible_actions = [0, 1, 2, 3, 4, 5]
|
self.possible_actions = [0, 1, 2, 3, 4]
|
||||||
self.action = 10
|
self.action = 10
|
||||||
|
|
||||||
def check_input(self,
|
def check_input(self,
|
||||||
|
@ -43,95 +44,95 @@ class InputHandler:
|
||||||
speed,
|
speed,
|
||||||
hitbox,
|
hitbox,
|
||||||
obstacle_sprites,
|
obstacle_sprites,
|
||||||
rect,
|
rect
|
||||||
player):
|
):
|
||||||
|
|
||||||
if not self.attacking and self.can_move:
|
if not self.attacking and self.can_move:
|
||||||
|
|
||||||
self.move_time = pygame.time.get_ticks()
|
self.move_time = pygame.time.get_ticks()
|
||||||
|
|
||||||
# Movement Input
|
# Movement Input
|
||||||
if button == 0: # keys[pygame.K_w]:
|
if self.action == 0: # keys[pygame.K_w]:
|
||||||
self.movement.direction.y = -1
|
self.direction.y = -1
|
||||||
self.status = 'up'
|
self.status = 'up'
|
||||||
self.can_move = False
|
self.can_move = False
|
||||||
self.action = 0
|
self.action = 0
|
||||||
|
|
||||||
elif button == 1: # keys[pygame.K_s]:
|
elif self.action == 1: # keys[pygame.K_s]:
|
||||||
self.movement.direction.y = 1
|
self.direction.y = 1
|
||||||
self.status = 'down'
|
self.status = 'down'
|
||||||
self.can_move = False
|
self.can_move = False
|
||||||
self.action = 1
|
self.action = 1
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.movement.direction.y = 0
|
self.direction.y = 0
|
||||||
|
|
||||||
if button == 2: # keys[pygame.K_a]:
|
if self.action == 2: # keys[pygame.K_a]:
|
||||||
self.movement.direction.x = -1
|
self.direction.x = -1
|
||||||
self.status = 'left'
|
self.status = 'left'
|
||||||
self.can_move = False
|
self.can_move = False
|
||||||
self.action = 2
|
self.action = 2
|
||||||
|
|
||||||
elif button == 3: # keys[pygame.K_d]:
|
elif self.action == 3: # keys[pygame.K_d]:
|
||||||
self.movement.direction.x = 1
|
self.direction.x = 1
|
||||||
self.status = 'right'
|
self.status = 'right'
|
||||||
self.can_move = False
|
self.can_move = False
|
||||||
self.action = 3
|
self.action = 3
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.movement.direction.x = 0
|
self.direction.x = 0
|
||||||
|
|
||||||
self.movement.move(speed, hitbox, obstacle_sprites, rect)
|
self.move(speed, hitbox, obstacle_sprites, rect)
|
||||||
|
|
||||||
# Combat Input
|
# Combat Input
|
||||||
if button == 4 and not self.attacking: # keys[pygame.K_e]
|
if self.action == 4 and not self.attacking: # keys[pygame.K_e]
|
||||||
self.attacking = True
|
self.attacking = True
|
||||||
self.attack_time = pygame.time.get_ticks()
|
self.attack_time = pygame.time.get_ticks()
|
||||||
self.combat.create_attack_sprite(player)
|
self.create_attack_sprite()
|
||||||
self.action = 4
|
self.action = 4
|
||||||
|
|
||||||
# Magic Input
|
# Magic Input
|
||||||
if button == 5:
|
if self.action == 5:
|
||||||
self.attacking = True
|
self.attacking = True
|
||||||
self.attack_time = pygame.time.get_ticks()
|
self.attack_time = pygame.time.get_ticks()
|
||||||
|
|
||||||
self.combat.magic = list(magic_data.keys())[
|
self.magic = list(magic_data.keys())[
|
||||||
self.combat.magic_index]
|
self.magic_index]
|
||||||
|
|
||||||
strength = list(magic_data.values())[
|
strength = list(magic_data.values())[
|
||||||
self.combat.magic_index]['strength'] + player.stats.magic
|
self.magic_index]['strength'] + self.stats['magic']
|
||||||
|
|
||||||
cost = list(magic_data.values())[
|
cost = list(magic_data.values())[
|
||||||
self.combat.magic_index]['cost']
|
self.magic_index]['cost']
|
||||||
self.combat.create_magic_sprite(
|
self.create_magic_sprite(
|
||||||
player, self.combat.magic, strength, cost)
|
self.magic, strength, cost)
|
||||||
self.action = 5
|
self.action = 5
|
||||||
|
|
||||||
# Rotating Weapons
|
# Rotating Weapons
|
||||||
if button == 6 and self.can_rotate_weapon:
|
if self.action == 6 and self.can_rotate_weapon:
|
||||||
|
|
||||||
self.can_rotate_weapon = False
|
self.can_rotate_weapon = False
|
||||||
self.weapon_rotation_time = pygame.time.get_ticks()
|
self.weapon_rotation_time = pygame.time.get_ticks()
|
||||||
|
|
||||||
if self.combat.weapon_index\
|
if self.weapon_index\
|
||||||
< len(list(weapon_data.keys())) - 1:
|
< len(list(weapon_data.keys())) - 1:
|
||||||
|
|
||||||
self.combat.weapon_index += 1
|
self.weapon_index += 1
|
||||||
else:
|
else:
|
||||||
self.combat.weapon_index = 0
|
self.weapon_index = 0
|
||||||
|
|
||||||
self.combat.weapon = list(weapon_data.keys())[
|
self.weapon = list(weapon_data.keys())[
|
||||||
self.combat.weapon_index]
|
self.weapon_index]
|
||||||
self.action = 6
|
self.action = 6
|
||||||
|
|
||||||
# Swap Spells
|
# Swap Spells
|
||||||
if button == 7 and self.can_swap_magic:
|
if self.action == 7 and self.can_swap_magic:
|
||||||
self.can_swap_magic = False
|
self.can_swap_magic = False
|
||||||
self.magic_swap_time = pygame.time.get_ticks()
|
self.magic_swap_time = pygame.time.get_ticks()
|
||||||
if self.combat.magic_index < len(list(magic_data.keys())) - 1:
|
if self.magic_index < len(list(magic_data.keys())) - 1:
|
||||||
self.combat.magic_index += 1
|
self.magic_index += 1
|
||||||
else:
|
else:
|
||||||
self.combat.magic_index = 0
|
self.magic_index = 0
|
||||||
self.action = 7
|
self.action = 7
|
||||||
|
|
||||||
def cooldowns(self, vulnerable):
|
def cooldowns(self, vulnerable):
|
||||||
|
@ -141,11 +142,11 @@ class InputHandler:
|
||||||
if self.attacking:
|
if self.attacking:
|
||||||
if current_time - self.attack_time\
|
if current_time - self.attack_time\
|
||||||
> self.attack_cooldown\
|
> self.attack_cooldown\
|
||||||
+ weapon_data[self.combat.weapon]['cooldown']:
|
+ weapon_data[self.weapon]['cooldown']:
|
||||||
|
|
||||||
self.attacking = False
|
self.attacking = False
|
||||||
if self.combat.current_attack:
|
if self.current_attack:
|
||||||
self.combat.delete_attack_sprite()
|
self.delete_attack_sprite()
|
||||||
|
|
||||||
if not self.can_rotate_weapon:
|
if not self.can_rotate_weapon:
|
||||||
if current_time - self.weapon_rotation_time\
|
if current_time - self.weapon_rotation_time\
|
||||||
|
@ -160,10 +161,10 @@ class InputHandler:
|
||||||
self.can_swap_magic = True
|
self.can_swap_magic = True
|
||||||
|
|
||||||
if not vulnerable:
|
if not vulnerable:
|
||||||
if current_time - self.combat.hurt_time\
|
if current_time - self.hurt_time\
|
||||||
>= self.combat.invulnerability_duration:
|
>= self.invulnerability_duration:
|
||||||
|
|
||||||
self.combat.vulnerable = True
|
self.vulnerable = True
|
||||||
|
|
||||||
if not self.can_move:
|
if not self.can_move:
|
||||||
if current_time - self.move_time\
|
if current_time - self.move_time\
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
import os
|
import os
|
||||||
import pygame
|
import pygame
|
||||||
from math import sin
|
|
||||||
|
|
||||||
from utils.resource_loader import import_folder, import_assets
|
from math import sin
|
||||||
|
|
||||||
from config.system.window import HITBOX_OFFSET
|
from config.system.window import HITBOX_OFFSET
|
||||||
|
|
||||||
|
from effects.particle_effects import AnimationPlayer
|
||||||
|
|
||||||
class AnimationHandler:
|
from .stats import StatsHandler
|
||||||
|
|
||||||
|
from utils.resource_loader import import_folder, import_assets
|
||||||
|
|
||||||
|
|
||||||
|
class AnimationHandler(StatsHandler):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
def __init__(self, sprite_type, name=None):
|
|
||||||
self.frame_index = 0
|
self.frame_index = 0
|
||||||
self.animation_speed = 0.15
|
self.animation_speed = 0.15
|
||||||
|
|
||||||
self.sprite_type = sprite_type
|
|
||||||
self.name = name
|
|
||||||
|
|
||||||
def import_assets(self, position):
|
def import_assets(self, position):
|
||||||
|
|
||||||
# Import Graphic Assets
|
# Import graphic assets
|
||||||
|
|
||||||
if self.sprite_type == 'player':
|
if self.sprite_type == 'player':
|
||||||
self.image = pygame.image.load(
|
self.image = pygame.image.load(
|
||||||
import_assets(os.path.join('graphics',
|
import_assets(os.path.join('graphics',
|
||||||
|
@ -83,8 +85,8 @@ class AnimationHandler:
|
||||||
else:
|
else:
|
||||||
self.image.set_alpha(255)
|
self.image.set_alpha(255)
|
||||||
|
|
||||||
def trigger_death_particles(self, animation_player, position, particle_type, groups):
|
def trigger_death_particles(self, position, particle_type, groups):
|
||||||
animation_player.generate_particles(
|
AnimationPlayer().generate_particles(
|
||||||
particle_type, position, groups)
|
particle_type, position, groups)
|
||||||
|
|
||||||
def wave_value(self):
|
def wave_value(self):
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
from effects.weapon_effects import Weapon
|
|
||||||
from effects.magic_effects import MagicPlayer
|
|
||||||
|
|
||||||
from config.game.weapon_config import weapon_data
|
from config.game.weapon_config import weapon_data
|
||||||
from config.game.spell_config import magic_data
|
from config.game.spell_config import magic_data
|
||||||
|
|
||||||
|
from effects.magic_effects import MagicPlayer
|
||||||
|
from effects.particle_effects import AnimationPlayer
|
||||||
|
from effects.weapon_effects import Weapon
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CombatHandler:
|
class CombatHandler:
|
||||||
|
|
||||||
def __init__(self, animation_player):
|
def __init__(self):
|
||||||
|
|
||||||
self.animation_player = animation_player
|
|
||||||
|
|
||||||
# Setup Combat
|
# Setup Combat
|
||||||
self.magic_player = MagicPlayer(animation_player)
|
self.magic_player = MagicPlayer(AnimationPlayer())
|
||||||
self.current_attack = None
|
self.current_attack = None
|
||||||
|
|
||||||
# Spell and Weapon Rotation
|
# Spell and Weapon Rotation
|
||||||
|
@ -27,20 +28,20 @@ class CombatHandler:
|
||||||
self.hurt_time = None
|
self.hurt_time = None
|
||||||
self.invulnerability_duration = 300
|
self.invulnerability_duration = 300
|
||||||
|
|
||||||
def create_attack_sprite(self, player):
|
def create_attack_sprite(self):
|
||||||
self.current_attack = Weapon(
|
self.current_attack = Weapon(
|
||||||
player, [player.visible_sprites, player.attack_sprites])
|
self, [self.visible_sprites, self.attack_sprites])
|
||||||
|
|
||||||
def delete_attack_sprite(self):
|
def delete_attack_sprite(self):
|
||||||
if self.current_attack:
|
if self.current_attack:
|
||||||
self.current_attack.kill()
|
self.current_attack.kill()
|
||||||
self.current_attack = None
|
self.current_attack = None
|
||||||
|
|
||||||
def create_magic_sprite(self, player, style, strength, cost):
|
def create_magic_sprite(self, style, strength, cost):
|
||||||
if style == 'heal':
|
if style == 'heal':
|
||||||
self.magic_player.heal(player, strength, cost, [
|
self.magic_player.heal(self, strength, cost, [
|
||||||
player.visible_sprites])
|
self.visible_sprites])
|
||||||
|
|
||||||
if style == 'flame':
|
if style == 'flame':
|
||||||
self.magic_player.flame(
|
self.magic_player.flame(
|
||||||
player, cost, [player.visible_sprites, player.attack_sprites])
|
self, cost, [self.visible_sprites, self.attack_sprites])
|
||||||
|
|
|
@ -3,8 +3,7 @@ import pygame
|
||||||
|
|
||||||
class MovementHandler:
|
class MovementHandler:
|
||||||
|
|
||||||
def __init__(self, sprite_type):
|
def __init__(self):
|
||||||
|
|
||||||
self.direction = pygame.math.Vector2()
|
self.direction = pygame.math.Vector2()
|
||||||
|
|
||||||
def move(self, speed, hitbox, obstacle_sprites, rect):
|
def move(self, speed, hitbox, obstacle_sprites, rect):
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
from config.game.player_config import warrior_stats, mage_stats, tank_stats
|
from config.game.player_config import warrior_stats, mage_stats, tank_stats
|
||||||
from config.game.monster_config import monster_data
|
from config.game.monster_config import monster_data
|
||||||
|
|
||||||
|
|
||||||
class StatsHandler:
|
class StatsHandler:
|
||||||
|
|
||||||
def __init__(self, sprite_type, role=None, monster_name=None):
|
def get_stats(self, sprite_type, role=None, monster_name=None):
|
||||||
|
|
||||||
if sprite_type == 'player':
|
if sprite_type == 'player':
|
||||||
|
|
||||||
if role == 'warrior':
|
if role == 'warrior':
|
||||||
self.stats = warrior_stats
|
self.stats = warrior_stats
|
||||||
elif role == 'tank':
|
elif role == 'tank':
|
||||||
self.stats = tank_stats
|
self.stats = tank_stats
|
||||||
elif role == 'mage':
|
elif role == 'mage':
|
||||||
self.stats = mage_stats
|
self.stats = mage_stats
|
||||||
|
else:
|
||||||
|
self.stats = base_stats
|
||||||
|
|
||||||
self.role_id = self.stats['role_id']
|
self.role_id = self.stats['role_id']
|
||||||
self.health = self.stats['health']
|
self.health = self.stats['health']
|
||||||
|
@ -24,7 +24,6 @@ class StatsHandler:
|
||||||
self.exp = 0
|
self.exp = 0
|
||||||
|
|
||||||
if sprite_type == 'enemy':
|
if sprite_type == 'enemy':
|
||||||
|
|
||||||
self.monster_info = monster_data[monster_name]
|
self.monster_info = monster_data[monster_name]
|
||||||
self.monster_id = self.monster_info['id']
|
self.monster_id = self.monster_info['id']
|
||||||
self.health = self.monster_info['health']
|
self.health = self.monster_info['health']
|
||||||
|
|
|
@ -1,36 +1,34 @@
|
||||||
import pygame
|
import pygame
|
||||||
|
|
||||||
from .components.animation import AnimationHandler
|
from .entity import Entity
|
||||||
from .components.stats import StatsHandler
|
|
||||||
from .components._input import InputHandler
|
|
||||||
|
|
||||||
from effects.particle_effects import AnimationPlayer
|
from effects.particle_effects import AnimationPlayer
|
||||||
|
|
||||||
|
|
||||||
class Enemy(pygame.sprite.Sprite):
|
class Enemy(Entity):
|
||||||
|
|
||||||
def __init__(self, name, position, groups, visible_sprites, obstacle_sprites):
|
def __init__(self,
|
||||||
super().__init__(groups)
|
name,
|
||||||
|
position,
|
||||||
|
groups,
|
||||||
|
visible_sprites,
|
||||||
|
obstacle_sprites
|
||||||
|
):
|
||||||
|
|
||||||
self.sprite_type = "enemy"
|
super().__init__(groups=groups,
|
||||||
|
visible_sprites=visible_sprites,
|
||||||
|
obstacle_sprites=obstacle_sprites,
|
||||||
|
attack_sprites=None,
|
||||||
|
attackable_sprites=None)
|
||||||
|
|
||||||
|
# Setup stats
|
||||||
|
self.sprite_type = 'enemy'
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.get_stats(self.sprite_type, monster_name=self.name)
|
||||||
|
|
||||||
self.visible_sprites = visible_sprites
|
# Graphics Setup
|
||||||
|
|
||||||
# Setup Graphics
|
|
||||||
self.animation_player = AnimationPlayer()
|
self.animation_player = AnimationPlayer()
|
||||||
self.animation = AnimationHandler(self.sprite_type, self.name)
|
self.import_assets(position)
|
||||||
self.animation.import_assets(position)
|
|
||||||
self.image = self.animation.image
|
|
||||||
self.rect = self.animation.rect
|
|
||||||
|
|
||||||
# Setup Inputs
|
|
||||||
self._input = InputHandler(
|
|
||||||
self.sprite_type, self.animation_player)
|
|
||||||
|
|
||||||
# Setup Stats
|
|
||||||
self.stats = StatsHandler(self.sprite_type, monster_name=self.name)
|
|
||||||
self.obstacle_sprites = obstacle_sprites
|
|
||||||
|
|
||||||
self.distance_direction_from_player = None
|
self.distance_direction_from_player = None
|
||||||
|
|
||||||
|
@ -38,49 +36,48 @@ class Enemy(pygame.sprite.Sprite):
|
||||||
player_distance = sorted(
|
player_distance = sorted(
|
||||||
self.distance_direction_from_player, key=lambda x: x[0])[0]
|
self.distance_direction_from_player, key=lambda x: x[0])[0]
|
||||||
|
|
||||||
if player_distance[0] < self.stats.notice_radius and player_distance[0] >= self.stats.attack_radius:
|
if player_distance[0] < self.notice_radius and player_distance[0] >= self.attack_radius:
|
||||||
self._input.movement.direction = player_distance[1]
|
self.direction = player_distance[1]
|
||||||
self.animation.status = "move"
|
self.status = "move"
|
||||||
self._input.movement.move(
|
self.move(
|
||||||
self.stats.speed, self.animation.hitbox, self.obstacle_sprites, self.animation.rect)
|
self.speed, self.hitbox, self.obstacle_sprites, self.rect)
|
||||||
elif player_distance[0] <= self.stats.attack_radius:
|
elif player_distance[0] <= self.attack_radius:
|
||||||
self.animation.status = 'attack'
|
self.status = 'attack'
|
||||||
else:
|
else:
|
||||||
self.animation.status = 'idle'
|
self.status = 'idle'
|
||||||
|
|
||||||
def add_exp(self, player):
|
def add_exp(self, player):
|
||||||
player.stats.exp += self.stats.exp
|
player.exp += self.exp
|
||||||
|
|
||||||
def check_death(self, player):
|
def check_death(self, player):
|
||||||
if self.stats.health <= 0:
|
if self.health <= 0:
|
||||||
self.add_exp(player)
|
self.add_exp(player)
|
||||||
self.animation.trigger_death_particles(
|
self.trigger_death_particles(
|
||||||
self.animation_player, self.rect.center, self.name, self.visible_sprites)
|
self.rect.center, self.name, self.visible_sprites)
|
||||||
self.kill()
|
self.kill()
|
||||||
|
|
||||||
def get_damaged(self, player, attack_type):
|
def get_damaged(self, player, attack_type):
|
||||||
if self._input.combat.vulnerable:
|
if self.vulnerable:
|
||||||
for _, direction, attacking_player in self.distance_direction_from_player:
|
for _, direction, attacking_player in self.distance_direction_from_player:
|
||||||
if attacking_player == player:
|
if attacking_player == player:
|
||||||
self._input.movement.direction = -direction
|
self.direction = -direction
|
||||||
self._input.movement.move(
|
self.move(
|
||||||
self.stats.speed * self.stats.knockback, self.animation.hitbox, self.obstacle_sprites, self.animation.rect)
|
self.speed * self.knockback, self.hitbox, self.obstacle_sprites, self.rect)
|
||||||
break
|
break
|
||||||
if attack_type == 'weapon':
|
if attack_type == 'weapon':
|
||||||
self.stats.health -= player.get_full_weapon_damage()
|
self.health -= player.get_full_weapon_damage()
|
||||||
else:
|
else:
|
||||||
self.stats.health -= player.get_full_magic_damage()
|
self.health -= player.get_full_magic_damage()
|
||||||
self.check_death(player)
|
self.check_death(player)
|
||||||
self._input.combat.hurt_time = pygame.time.get_ticks()
|
self.hurt_time = pygame.time.get_ticks()
|
||||||
self._input.combat.vulnerable = False
|
self.vulnerable = False
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
|
||||||
self.get_action()
|
self.get_action()
|
||||||
|
|
||||||
self.animation.animate(self.animation.status,
|
self.animate(self.status, self.vulnerable)
|
||||||
self._input.combat.vulnerable)
|
self.image = self.image
|
||||||
self.image = self.animation.image
|
self.rect = self.rect
|
||||||
self.rect = self.animation.rect
|
|
||||||
|
|
||||||
self._input.cooldowns(self._input.combat.vulnerable)
|
self.cooldowns(self.vulnerable)
|
||||||
|
|
33
entities/entity.py
Normal file
33
entities/entity.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import pygame
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
from .components._input import InputHandler
|
||||||
|
from .components.animation import AnimationHandler
|
||||||
|
|
||||||
|
from effects.particle_effects import AnimationPlayer
|
||||||
|
|
||||||
|
|
||||||
|
class Entity(pygame.sprite.Sprite, AnimationHandler, InputHandler):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
groups,
|
||||||
|
obstacle_sprites,
|
||||||
|
visible_sprites,
|
||||||
|
attack_sprites = None,
|
||||||
|
attackable_sprites = None
|
||||||
|
):
|
||||||
|
|
||||||
|
super().__init__(groups)
|
||||||
|
AnimationHandler.__init__(self)
|
||||||
|
InputHandler.__init__(self)
|
||||||
|
|
||||||
|
# Sprite Setup
|
||||||
|
self.obstacle_sprites = obstacle_sprites
|
||||||
|
self.visible_sprites = visible_sprites
|
||||||
|
self.attack_sprites = attack_sprites
|
||||||
|
self.attackable_sprites = attackable_sprites
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,14 @@ from random import randint
|
||||||
from config.game.weapon_config import weapon_data
|
from config.game.weapon_config import weapon_data
|
||||||
from config.game.spell_config import magic_data
|
from config.game.spell_config import magic_data
|
||||||
|
|
||||||
from .components.stats import StatsHandler
|
from .entity import Entity
|
||||||
from .components._input import InputHandler
|
|
||||||
from .components.animation import AnimationHandler
|
|
||||||
|
|
||||||
from effects.particle_effects import AnimationPlayer
|
from effects.particle_effects import AnimationPlayer
|
||||||
|
|
||||||
from ml.ppo.agent import Agent
|
from ml.ppo.agent import Agent
|
||||||
|
|
||||||
|
|
||||||
class Player(pygame.sprite.Sprite):
|
class Player(Entity):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
player_id,
|
player_id,
|
||||||
role,
|
role,
|
||||||
|
@ -26,32 +24,26 @@ class Player(pygame.sprite.Sprite):
|
||||||
attack_sprites,
|
attack_sprites,
|
||||||
attackable_sprites
|
attackable_sprites
|
||||||
):
|
):
|
||||||
super().__init__(groups)
|
|
||||||
|
|
||||||
|
super().__init__(groups=groups,
|
||||||
|
obstacle_sprites=obstacle_sprites,
|
||||||
|
visible_sprites=visible_sprites,
|
||||||
|
attack_sprites=attack_sprites, attackable_sprites=attackable_sprites)
|
||||||
|
|
||||||
|
# Setup stats
|
||||||
|
self.sprite_type = 'player'
|
||||||
|
self.get_stats(self.sprite_type, role=role)
|
||||||
|
|
||||||
|
# Graphics Setup
|
||||||
|
self.animation_player = AnimationPlayer()
|
||||||
|
self.import_assets(position)
|
||||||
|
|
||||||
|
# Set misc
|
||||||
self.initial_position = position
|
self.initial_position = position
|
||||||
self.map_edge = map_edge
|
self.map_edge = map_edge
|
||||||
self.player_id = player_id
|
self.player_id = player_id
|
||||||
self.distance_direction_from_enemy = None
|
self.distance_direction_from_enemy = None
|
||||||
|
|
||||||
# Sprite Setup
|
|
||||||
self.sprite_type = "player"
|
|
||||||
self.obstacle_sprites = obstacle_sprites
|
|
||||||
self.visible_sprites = visible_sprites
|
|
||||||
self.attack_sprites = attack_sprites
|
|
||||||
self.attackable_sprites = attackable_sprites
|
|
||||||
|
|
||||||
# Graphics Setup
|
|
||||||
self.animation_player = AnimationPlayer()
|
|
||||||
self.animation = AnimationHandler(self.sprite_type)
|
|
||||||
self.animation.import_assets(position)
|
|
||||||
# Input Setup
|
|
||||||
self._input = InputHandler(
|
|
||||||
self.sprite_type, self.animation_player)
|
|
||||||
|
|
||||||
# Setup Stats
|
|
||||||
self.role = role
|
|
||||||
self.stats = StatsHandler(self.sprite_type, self.role)
|
|
||||||
|
|
||||||
def setup_agent(self,
|
def setup_agent(self,
|
||||||
gamma,
|
gamma,
|
||||||
alpha,
|
alpha,
|
||||||
|
@ -69,7 +61,7 @@ class Player(pygame.sprite.Sprite):
|
||||||
|
|
||||||
self.agent = Agent(
|
self.agent = Agent(
|
||||||
input_dims=self.num_features,
|
input_dims=self.num_features,
|
||||||
n_actions=len(self._input.possible_actions),
|
n_actions=len(self.possible_actions),
|
||||||
gamma=gamma,
|
gamma=gamma,
|
||||||
alpha=alpha,
|
alpha=alpha,
|
||||||
policy_clip=policy_clip,
|
policy_clip=policy_clip,
|
||||||
|
@ -97,24 +89,24 @@ class Player(pygame.sprite.Sprite):
|
||||||
\nSkipping loading ...\n")
|
\nSkipping loading ...\n")
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
if self._input.movement.direction.x == 0\
|
if self.direction.x == 0\
|
||||||
and self._input.movement.direction.y == 0:
|
and self.direction.y == 0:
|
||||||
|
|
||||||
if 'idle' not in self._input.status and 'attack' not in self._input.status:
|
if 'idle' not in self.status and 'attack' not in self.status:
|
||||||
self._input.status += '_idle'
|
self.status += '_idle'
|
||||||
|
|
||||||
if self._input.attacking:
|
if self.attacking:
|
||||||
self._input.movement.direction.x = 0
|
self.direction.x = 0
|
||||||
self._input.movement.direction.y = 0
|
self.direction.y = 0
|
||||||
if 'attack' not in self._input.status:
|
if 'attack' not in self.status:
|
||||||
if 'idle' in self._input.status:
|
if 'idle' in self.status:
|
||||||
self._input.status = self._input.status.replace(
|
self.status = self.status.replace(
|
||||||
'idle', 'attack')
|
'idle', 'attack')
|
||||||
else:
|
else:
|
||||||
self._input.status += '_attack'
|
self.status += '_attack'
|
||||||
else:
|
else:
|
||||||
if 'attack' in self._input.status:
|
if 'attack' in self.status:
|
||||||
self._input.status = self._input.status.replace('_attack', '')
|
self.status = self.status.replace('_attack', '')
|
||||||
|
|
||||||
def attack_logic(self):
|
def attack_logic(self):
|
||||||
if self.attack_sprites:
|
if self.attack_sprites:
|
||||||
|
@ -137,13 +129,13 @@ class Player(pygame.sprite.Sprite):
|
||||||
self, attack_sprite.sprite_type)
|
self, attack_sprite.sprite_type)
|
||||||
|
|
||||||
def get_full_weapon_damage(self):
|
def get_full_weapon_damage(self):
|
||||||
base_damage = self.stats.attack
|
base_damage = self.attack
|
||||||
weapon_damage = weapon_data[self._input.combat.weapon]['damage']
|
weapon_damage = weapon_data[self.weapon]['damage']
|
||||||
return (base_damage + weapon_damage)
|
return (base_damage + weapon_damage)
|
||||||
|
|
||||||
def get_full_magic_damage(self):
|
def get_full_magic_damage(self):
|
||||||
base_damage = self.stats.magic
|
base_damage = self.stats['magic']
|
||||||
spell_damage = magic_data[self._input.combat.magic]['strength']
|
spell_damage = magic_data[self.magic]['strength']
|
||||||
return (base_damage + spell_damage)
|
return (base_damage + spell_damage)
|
||||||
|
|
||||||
def get_current_state(self):
|
def get_current_state(self):
|
||||||
|
@ -156,43 +148,37 @@ class Player(pygame.sprite.Sprite):
|
||||||
|
|
||||||
nearest_dist, nearest_en_dir, nearest_enemy = sorted_distances[0]
|
nearest_dist, nearest_en_dir, nearest_enemy = sorted_distances[0]
|
||||||
|
|
||||||
self.action_features = [self._input.action]
|
self.action_features = [self.action]
|
||||||
|
|
||||||
if hasattr(self, 'state_features'):
|
if hasattr(self, 'state_features'):
|
||||||
self.old_state_features = self.state_features
|
self.old_state_features = self.state_features
|
||||||
|
|
||||||
self.reward = self.stats.exp\
|
self.reward = self.exp\
|
||||||
+ self.stats.health/self.stats.stats['health']
|
+ self.health/self.stats['health']
|
||||||
# - nearest_dist/np.sqrt(np.sum(self.map_edge))
|
# - nearest_dist/np.sqrt(np.sum(self.map_edge))
|
||||||
|
|
||||||
self.state_features = [
|
self.state_features = [
|
||||||
self.animation.rect.center[0]/self.map_edge[0],
|
self.rect.center[0]/self.map_edge[0],
|
||||||
self.animation.rect.center[1]/self.map_edge[1],
|
self.rect.center[1]/self.map_edge[1],
|
||||||
self._input.movement.direction.x,
|
self.direction.x,
|
||||||
self._input.movement.direction.y,
|
self.direction.y,
|
||||||
self.stats.health/self.stats.stats['health'],
|
self.health/self.stats['health'],
|
||||||
self.stats.energy/self.stats.stats['energy'],
|
self.energy/self.stats['energy'],
|
||||||
]
|
]
|
||||||
|
|
||||||
# self.state_features.extend([
|
|
||||||
# nearest_dist/np.sqrt(np.sum(self.map_edge)),
|
|
||||||
# nearest_en_dir[0],
|
|
||||||
# nearest_en_dir[1],
|
|
||||||
# nearest_enemy.stats.exp
|
|
||||||
# ])
|
|
||||||
|
|
||||||
for distance, direction, enemy in sorted_distances[:5]:
|
for distance, direction, enemy in sorted_distances[:5]:
|
||||||
self.state_features.extend([
|
self.state_features.extend([
|
||||||
|
|
||||||
distance/np.sqrt(np.sum(self.map_edge)),
|
distance/np.sqrt(np.sum(self.map_edge)),
|
||||||
|
|
||||||
direction[0],
|
direction[0],
|
||||||
|
|
||||||
direction[1],
|
direction[1],
|
||||||
|
|
||||||
enemy.stats.health /
|
enemy.health /
|
||||||
enemy.stats.monster_info['health'],
|
enemy.monster_info['health'],
|
||||||
|
|
||||||
enemy.stats.exp,
|
enemy.exp,
|
||||||
])
|
])
|
||||||
|
|
||||||
if hasattr(self, 'num_features'):
|
if hasattr(self, 'num_features'):
|
||||||
|
@ -202,9 +188,9 @@ class Player(pygame.sprite.Sprite):
|
||||||
self.state_features = np.array(self.state_features)
|
self.state_features = np.array(self.state_features)
|
||||||
|
|
||||||
def is_dead(self):
|
def is_dead(self):
|
||||||
if self.stats.health <= 0:
|
if self.health <= 0:
|
||||||
self.stats.health = 0
|
self.health = 0
|
||||||
self.animation.import_assets((3264, 448))
|
self.import_assets((3264, 448))
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
@ -215,18 +201,18 @@ class Player(pygame.sprite.Sprite):
|
||||||
self.get_current_state()
|
self.get_current_state()
|
||||||
|
|
||||||
# Choose action based on current state
|
# Choose action based on current state
|
||||||
action, probs, value\
|
self.action, probs, value\
|
||||||
= self.agent.choose_action(self.state_features)
|
= self.agent.choose_action(self.state_features)
|
||||||
|
|
||||||
# Apply chosen action
|
# Apply chosen action
|
||||||
self._input.check_input(action,
|
self.check_input(self.action,
|
||||||
self.stats.speed,
|
self.speed,
|
||||||
self.animation.hitbox,
|
self.hitbox,
|
||||||
self.obstacle_sprites,
|
self.obstacle_sprites,
|
||||||
self.animation.rect,
|
self.rect
|
||||||
self)
|
)
|
||||||
|
|
||||||
self.agent.remember(self.state_features, action,
|
self.agent.remember(self.state_features, self.action,
|
||||||
probs, value, self.reward, self.is_dead())
|
probs, value, self.reward, self.is_dead())
|
||||||
|
|
||||||
self.get_current_state()
|
self.get_current_state()
|
||||||
|
@ -236,11 +222,11 @@ class Player(pygame.sprite.Sprite):
|
||||||
self.agent_update()
|
self.agent_update()
|
||||||
|
|
||||||
# Cooldowns and Regen
|
# Cooldowns and Regen
|
||||||
self.stats.health_recovery()
|
self.health_recovery()
|
||||||
self.stats.energy_recovery()
|
self.energy_recovery()
|
||||||
|
|
||||||
# Refresh player based on input and animate
|
# Refresh player based on input and animate
|
||||||
self.get_status()
|
self.get_status()
|
||||||
self.animation.animate(
|
self.animate(
|
||||||
self._input.status, self._input.combat.vulnerable)
|
self.status, self.vulnerable)
|
||||||
self._input.cooldowns(self._input.combat.vulnerable)
|
self.cooldowns(self.vulnerable)
|
||||||
|
|
BIN
figures/.DS_Store
vendored
BIN
figures/.DS_Store
vendored
Binary file not shown.
30
level.py
30
level.py
|
@ -50,8 +50,6 @@ class Level:
|
||||||
|
|
||||||
self.possible_player_locations = []
|
self.possible_player_locations = []
|
||||||
|
|
||||||
player_id = 0
|
|
||||||
|
|
||||||
self.layouts = {
|
self.layouts = {
|
||||||
'boundary': import_csv_layout(os.path.join('map',
|
'boundary': import_csv_layout(os.path.join('map',
|
||||||
'FloorBlocks.csv')),
|
'FloorBlocks.csv')),
|
||||||
|
@ -195,16 +193,16 @@ class Level:
|
||||||
|
|
||||||
for player in self.player_sprites:
|
for player in self.player_sprites:
|
||||||
|
|
||||||
player.animation.import_assets(
|
player.import_assets(
|
||||||
choice(self.possible_player_locations))
|
choice(self.possible_player_locations))
|
||||||
|
|
||||||
player.stats.health\
|
player.health\
|
||||||
= player.stats.stats['health']
|
= player.stats['health']
|
||||||
|
|
||||||
player.stats.energy\
|
player.energy\
|
||||||
= player.stats.stats['energy']
|
= player.stats['energy']
|
||||||
|
|
||||||
player.stats.exp = 0
|
player.exp = 0
|
||||||
|
|
||||||
self.get_entities()
|
self.get_entities()
|
||||||
self.get_distance_direction()
|
self.get_distance_direction()
|
||||||
|
@ -235,12 +233,12 @@ class Level:
|
||||||
for player in self.player_sprites:
|
for player in self.player_sprites:
|
||||||
if not player.is_dead():
|
if not player.is_dead():
|
||||||
player_vector = pygame.math.Vector2(
|
player_vector = pygame.math.Vector2(
|
||||||
player.animation.rect.center
|
player.rect.center
|
||||||
)
|
)
|
||||||
|
|
||||||
for enemy in self.enemy_sprites:
|
for enemy in self.enemy_sprites:
|
||||||
enemy_vector = pygame.math.Vector2(
|
enemy_vector = pygame.math.Vector2(
|
||||||
enemy.animation.rect.center
|
enemy.rect.center
|
||||||
)
|
)
|
||||||
distance\
|
distance\
|
||||||
= (player_vector - enemy_vector).magnitude()
|
= (player_vector - enemy_vector).magnitude()
|
||||||
|
@ -261,12 +259,12 @@ class Level:
|
||||||
for enemy in self.enemy_sprites:
|
for enemy in self.enemy_sprites:
|
||||||
for distance, _, player in enemy.distance_direction_from_player:
|
for distance, _, player in enemy.distance_direction_from_player:
|
||||||
|
|
||||||
if (distance < enemy.stats.attack_radius
|
if (distance < enemy.attack_radius
|
||||||
and player._input.combat.vulnerable):
|
and player.vulnerable):
|
||||||
|
|
||||||
player.stats.health -= enemy.stats.attack
|
player.health -= enemy.attack
|
||||||
player._input.combat.vulnerable = False
|
player.vulnerable = False
|
||||||
player._input.combat.hurt_time = pygame.time.get_ticks()
|
player.hurt_time = pygame.time.get_ticks()
|
||||||
|
|
||||||
def toggle_pause(self):
|
def toggle_pause(self):
|
||||||
self.paused = not self.paused
|
self.paused = not self.paused
|
||||||
|
@ -279,7 +277,7 @@ class Level:
|
||||||
if not self.paused:
|
if not self.paused:
|
||||||
# Update the game
|
# Update the game
|
||||||
for player in self.player_sprites:
|
for player in self.player_sprites:
|
||||||
if player.stats.health > 0:
|
if player.health > 0:
|
||||||
player.attack_logic()
|
player.attack_logic()
|
||||||
|
|
||||||
self.get_entities()
|
self.get_entities()
|
||||||
|
|
5
main.py
5
main.py
|
@ -180,8 +180,9 @@ def main():
|
||||||
|
|
||||||
# Save models
|
# Save models
|
||||||
player.agent.save_models(
|
player.agent.save_models(
|
||||||
f"A{player.player_id}",
|
os.path.join(chkpt_path, f"A{player.player_id}"),
|
||||||
f"C{player.player_id}")
|
os.path.join(chkpt_path, f"C{player.player_id}")
|
||||||
|
)
|
||||||
|
|
||||||
print(f"Models saved to {chkpt_path}")
|
print(f"Models saved to {chkpt_path}")
|
||||||
|
|
||||||
|
|
1190
poetry.lock
generated
Normal file
1190
poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
45
pyproject.toml
Normal file
45
pyproject.toml
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
[tool.poetry]
|
||||||
|
name = "thesis"
|
||||||
|
version = "0.8.1"
|
||||||
|
description = "A training environment for MARL"
|
||||||
|
authors = ["Vasilis Valatsos <vasilvalat@gmail.com>"]
|
||||||
|
license = "MPL-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
package-mode = false
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.11"
|
||||||
|
contourpy = "^1.2.0"
|
||||||
|
cycler = "^0.12.1"
|
||||||
|
docstring-to-markdown = "^0.13"
|
||||||
|
filelock = "^3.13.1"
|
||||||
|
fonttools = "^4.45.1"
|
||||||
|
fsspec = "^2023.10.0"
|
||||||
|
jedi = "^0.19.1"
|
||||||
|
jinja2 = "^3.1.2"
|
||||||
|
kiwisolver = "^1.4.5"
|
||||||
|
markupsafe = "^2.1.3"
|
||||||
|
matplotlib = "^3.8.2"
|
||||||
|
mpmath = "^1.3.0"
|
||||||
|
networkx = "^3.2.1"
|
||||||
|
numpy = "^1.26.2"
|
||||||
|
packaging = "^23.2"
|
||||||
|
parso = "^0.8.3"
|
||||||
|
pillow = "^10.1.0"
|
||||||
|
pluggy = "^1.3.0"
|
||||||
|
pygame = "^2.5.2"
|
||||||
|
pyparsing = "^3.1.1"
|
||||||
|
python-dateutil = "^2.8.2"
|
||||||
|
python-lsp-jsonrpc = "^1.1.2"
|
||||||
|
python-lsp-server = "^1.9.0"
|
||||||
|
six = "^1.16.0"
|
||||||
|
sympy = "^1.12"
|
||||||
|
torch = "^2.1.0"
|
||||||
|
tqdm = "^4.66.1"
|
||||||
|
typing-extensions = "^4.8.0"
|
||||||
|
ujson = "^5.8.0"
|
||||||
|
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
|
@ -1,29 +0,0 @@
|
||||||
contourpy==1.2.0
|
|
||||||
cycler==0.12.1
|
|
||||||
docstring-to-markdown==0.13
|
|
||||||
filelock==3.13.1
|
|
||||||
fonttools==4.45.1
|
|
||||||
fsspec==2023.10.0
|
|
||||||
jedi==0.19.1
|
|
||||||
Jinja2==3.1.2
|
|
||||||
kiwisolver==1.4.5
|
|
||||||
MarkupSafe==2.1.3
|
|
||||||
matplotlib==3.8.2
|
|
||||||
mpmath==1.3.0
|
|
||||||
networkx==3.2.1
|
|
||||||
numpy==1.26.2
|
|
||||||
packaging==23.2
|
|
||||||
parso==0.8.3
|
|
||||||
Pillow==10.1.0
|
|
||||||
pluggy==1.3.0
|
|
||||||
pygame==2.5.2
|
|
||||||
pyparsing==3.1.1
|
|
||||||
python-dateutil==2.8.2
|
|
||||||
python-lsp-jsonrpc==1.1.2
|
|
||||||
python-lsp-server==1.9.0
|
|
||||||
six==1.16.0
|
|
||||||
sympy==1.12
|
|
||||||
torch==2.1.0
|
|
||||||
tqdm==4.66.1
|
|
||||||
typing_extensions==4.8.0
|
|
||||||
ujson==5.8.0
|
|
11
shell.nix
Normal file
11
shell.nix
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
with import <nixpkgs> {};
|
||||||
|
|
||||||
|
mkShell {
|
||||||
|
NIX_LD_LIBRARY_PATH = lib.makeLibraryPath [
|
||||||
|
stdenv.cc.cc
|
||||||
|
];
|
||||||
|
NIX_LD = lib.fileContents "${stdenv.cc}/nix-support/dynamic-linker";
|
||||||
|
shellHook = ''
|
||||||
|
export LD_LIBRARY_PATH=$NIX_LD_LIBRARY_PATH
|
||||||
|
'';
|
||||||
|
}
|
|
@ -13,7 +13,8 @@ def plot_learning_curve(scores, num_players, figure_path, n_episodes):
|
||||||
for score in scores:
|
for score in scores:
|
||||||
running_avg = np.zeros(len(score))
|
running_avg = np.zeros(len(score))
|
||||||
for i in range(len(score)):
|
for i in range(len(score)):
|
||||||
running_avg[i] = np.mean(score[max(0, i-int(n_episodes/10)):(i+1)])
|
if score[i] != 0:
|
||||||
|
running_avg[i] = np.mean(score[max(0, i-int(n_episodes/10)):i+1])
|
||||||
plt.plot(running_avg)
|
plt.plot(running_avg)
|
||||||
plt.savefig(os.path.join(figure_path, "avg_score.png"))
|
plt.savefig(os.path.join(figure_path, "avg_score.png"))
|
||||||
plt.close()
|
plt.close()
|
||||||
|
@ -50,7 +51,8 @@ def plot_loss(nn_type, losses, num_players, figure_path, n_episodes):
|
||||||
for loss in losses:
|
for loss in losses:
|
||||||
running_avg = np.zeros(len(loss))
|
running_avg = np.zeros(len(loss))
|
||||||
for i in range(len(loss)):
|
for i in range(len(loss)):
|
||||||
running_avg[i] = np.mean(loss[max(0, i-int(n_episodes/10)):(i+1)])
|
if loss[i] != 0:
|
||||||
|
running_avg[i] = np.mean(loss[max(0, i-int(n_episodes/10)):(i+1)])
|
||||||
plt.plot(running_avg)
|
plt.plot(running_avg)
|
||||||
plt.savefig(os.path.join(figure_path, f"{nn_type}_loss.png"))
|
plt.savefig(os.path.join(figure_path, f"{nn_type}_loss.png"))
|
||||||
plt.close()
|
plt.close()
|
||||||
|
@ -66,7 +68,8 @@ def plot_parameter(name, parameter, num_players, figure_path, n_episodes):
|
||||||
for param in parameter:
|
for param in parameter:
|
||||||
running_avg = np.zeros(len(param))
|
running_avg = np.zeros(len(param))
|
||||||
for i in range(len(param)):
|
for i in range(len(param)):
|
||||||
running_avg[i] = np.mean(param[max(0, i-int(n_episodes/10)):(i+1)])
|
if param[i] != 0:
|
||||||
|
running_avg[i] = np.mean(param[max(0, i-int(n_episodes/10)):(i+1)])
|
||||||
plt.plot(running_avg)
|
plt.plot(running_avg)
|
||||||
plt.savefig(os.path.join(figure_path, f"{name}.png"))
|
plt.savefig(os.path.join(figure_path, f"{name}.png"))
|
||||||
plt.close()
|
plt.close()
|
||||||
|
|
Loading…
Reference in a new issue