Finished refactoring code
This commit is contained in:
parent
cd0333cbff
commit
b0a925292e
25 changed files with 429 additions and 194 deletions
BIN
assets/audio/attack/claw.wav
Normal file
BIN
assets/audio/attack/claw.wav
Normal file
Binary file not shown.
BIN
assets/audio/attack/fireball.wav
Normal file
BIN
assets/audio/attack/fireball.wav
Normal file
Binary file not shown.
BIN
assets/audio/attack/slash.wav
Normal file
BIN
assets/audio/attack/slash.wav
Normal file
Binary file not shown.
BIN
assets/audio/death.wav
Normal file
BIN
assets/audio/death.wav
Normal file
Binary file not shown.
BIN
assets/audio/flame.wav
Normal file
BIN
assets/audio/flame.wav
Normal file
Binary file not shown.
BIN
assets/audio/heal.wav
Normal file
BIN
assets/audio/heal.wav
Normal file
Binary file not shown.
BIN
assets/audio/hit.wav
Normal file
BIN
assets/audio/hit.wav
Normal file
Binary file not shown.
BIN
assets/audio/main.ogg
Normal file
BIN
assets/audio/main.ogg
Normal file
Binary file not shown.
BIN
assets/audio/sword.wav
Normal file
BIN
assets/audio/sword.wav
Normal file
Binary file not shown.
|
@ -1,5 +1,12 @@
|
|||
import os
|
||||
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
asset_path = os.path.join(
|
||||
script_dir, '../../..', 'assets')
|
||||
|
||||
monster_data = {
|
||||
'squid': {'health': 100,'exp':100,'damage':20,'attack_type': 'slash', 'attack_sound':'../Graphics/audio/attack/slash.wav', 'speed': 3, 'resistance': 3, 'attack_radius': 80, 'notice_radius': 360},
|
||||
'raccoon': {'health': 300,'exp':250,'damage':40,'attack_type': 'claw', 'attack_sound':'../Graphics/audio/attack/claw.wav','speed': 2, 'resistance': 3, 'attack_radius': 120, 'notice_radius': 400},
|
||||
'spirit': {'health': 100,'exp':110,'damage':8,'attack_type': 'thunder', 'attack_sound':'../Graphics/audio/attack/fireball.wav', 'speed': 4, 'resistance': 3, 'attack_radius': 60, 'notice_radius': 350},
|
||||
'bamboo': {'health': 70,'exp':120,'damage':6,'attack_type': 'leaf_attack', 'attack_sound':'../Graphics/audio/attack/slash.wav', 'speed': 3, 'resistance': 3, 'attack_radius': 50, 'notice_radius': 300}}
|
||||
'squid': {'health': 100, 'exp': 100, 'attack': 20, 'attack_type': 'slash', 'attack_sound': f'{asset_path}/audio/attack/slash.wav', 'speed': 3, 'knockback': 20, 'attack_radius': 80, 'notice_radius': 360},
|
||||
'raccoon': {'health': 300, 'exp': 250, 'attack': 40, 'attack_type': 'claw', 'attack_sound': f'{asset_path}/audio/attack/claw.wav', 'speed': 2, 'knockback': 20, 'attack_radius': 120, 'notice_radius': 400},
|
||||
'spirit': {'health': 100, 'exp': 110, 'attack': 8, 'attack_type': 'thunder', 'attack_sound': f'{asset_path}/audio/attack/fireball.wav', 'speed': 4, 'knockback': 20, 'attack_radius': 60, 'notice_radius': 350},
|
||||
'bamboo': {'health': 70, 'exp': 120, 'attack': 6, 'attack_type': 'leaf_attack', 'attack_sound': f'{asset_path}/audio/attack/slash.wav', 'speed': 3, 'knockback': 20, 'attack_radius': 50, 'notice_radius': 300}}
|
||||
|
|
23
game/configs/game/player_config.py
Normal file
23
game/configs/game/player_config.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
stats = {
|
||||
'health': 100,
|
||||
'energy': 60,
|
||||
'attack': 10,
|
||||
'magic': 4,
|
||||
'speed': 5
|
||||
}
|
||||
|
||||
max_stats = {
|
||||
'health': 300,
|
||||
'energy': 150,
|
||||
'attack': 20,
|
||||
'magic': 10,
|
||||
'speed': 10
|
||||
}
|
||||
|
||||
upgrade_costs = {
|
||||
'health': 100,
|
||||
'energy': 100,
|
||||
'attack': 100,
|
||||
'magic': 100,
|
||||
'speed': 100
|
||||
}
|
|
@ -13,37 +13,3 @@ HITBOX_OFFSET = {
|
|||
|
||||
# general colors
|
||||
WATER_COLOR = '#71ddee'
|
||||
UI_BG_COLOR = '#222222'
|
||||
UI_BORDER_COLOR = '#111111'
|
||||
TEXT_COLOR = '#EEEEEE'
|
||||
|
||||
# ui colors
|
||||
HEALTH_COLOR = 'red'
|
||||
ENERGY_COLOR = 'blue'
|
||||
UI_BORDER_COLOR_ACTIVE = 'gold'
|
||||
|
||||
# Upgrade menu
|
||||
TEXT_COLOR_SELECTED = '#111111'
|
||||
BAR_COLOR = '#EEEEEE'
|
||||
BAR_COLOR_SELECTED = '#111111'
|
||||
UPGRADE_BG_COLOR_SELECTED = '#EEEEEE'
|
||||
|
||||
# # weapons
|
||||
# weapon_data = {
|
||||
# 'sword': {'cooldown': 100, 'damage': 15,'graphic':'../Graphics/graphics/weapons/sword/full.png'},
|
||||
# 'lance': {'cooldown': 400, 'damage': 30,'graphic':'../Graphics/graphics/weapons/lance/full.png'},
|
||||
# 'axe': {'cooldown': 300, 'damage': 20, 'graphic':'../Graphics/graphics/weapons/axe/full.png'},
|
||||
# 'rapier':{'cooldown': 50, 'damage': 8, 'graphic':'../Graphics/graphics/weapons/rapier/full.png'},
|
||||
# 'sai':{'cooldown': 80, 'damage': 10, 'graphic':'../Graphics/graphics/weapons/sai/full.png'}}
|
||||
#
|
||||
# # magic
|
||||
# magic_data = {
|
||||
# 'flame': {'strength': 5,'cost': 20,'graphic':'../Graphics/graphics/particles/flame/fire.png'},
|
||||
# 'heal' : {'strength': 20,'cost': 10,'graphic':'../Graphics/graphics/particles/heal/heal.png'}}
|
||||
#
|
||||
# # enemy
|
||||
# monster_data = {
|
||||
# 'squid': {'health': 100,'exp':100,'damage':20,'attack_type': 'slash', 'attack_sound':'../Graphics/audio/attack/slash.wav', 'speed': 3, 'resistance': 3, 'attack_radius': 80, 'notice_radius': 360},
|
||||
# 'raccoon': {'health': 300,'exp':250,'damage':40,'attack_type': 'claw', 'attack_sound':'../Graphics/audio/attack/claw.wav','speed': 2, 'resistance': 3, 'attack_radius': 120, 'notice_radius': 400},
|
||||
# 'spirit': {'health': 100,'exp':110,'damage':8,'attack_type': 'thunder', 'attack_sound':'../Graphics/audio/attack/fireball.wav', 'speed': 4, 'resistance': 3, 'attack_radius': 60, 'notice_radius': 350},
|
||||
# 'bamboo': {'health': 70,'exp':120,'damage':6,'attack_type': 'leaf_attack', 'attack_sound':'../Graphics/audio/attack/slash.wav', 'speed': 3, 'resistance': 3, 'attack_radius': 50, 'notice_radius': 300}}
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
import os
|
||||
import pygame
|
||||
from random import randint
|
||||
|
||||
from configs.system.window_config import TILESIZE
|
||||
|
||||
from configs.game.spell_config import *
|
||||
|
||||
|
||||
class MagicPlayer:
|
||||
def __init__(self, animation_player):
|
||||
self.animation_player = animation_player
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
asset_path = os.path.join(
|
||||
script_dir, '../..', 'assets')
|
||||
|
||||
# Sound Setup
|
||||
# self.sounds = {
|
||||
# 'heal': pygame.mixer.Sound('../Graphics/audio/heal.wav'),
|
||||
# 'flame': pygame.mixer.Sound('../Graphics/audio/flame.wav')
|
||||
# }
|
||||
self.sounds = {
|
||||
'heal': pygame.mixer.Sound(f'{asset_path}/audio/heal.wav'),
|
||||
'flame': pygame.mixer.Sound(f'{asset_path}/audio/flame.wav')
|
||||
}
|
||||
|
||||
def heal(self, player, strength, cost, groups):
|
||||
if player.stats.energy >= cost:
|
||||
# self.sounds['heal'].play()
|
||||
self.sounds['heal'].play()
|
||||
player.stats.health += strength
|
||||
player.stats.energy -= cost
|
||||
if player.stats.health >= player.stats.stats['health']:
|
||||
|
@ -31,13 +33,13 @@ class MagicPlayer:
|
|||
def flame(self, player, cost, groups):
|
||||
if player.stats.energy >= cost:
|
||||
player.stats.energy -= cost
|
||||
# self.sounds['flame'].play()
|
||||
self.sounds['flame'].play()
|
||||
|
||||
if player.status.split('_')[0] == 'right':
|
||||
if player._input.status.split('_')[0] == 'right':
|
||||
direction = pygame.math.Vector2(1, 0)
|
||||
elif player.status.split('_')[0] == 'left':
|
||||
elif player._input.status.split('_')[0] == 'left':
|
||||
direction = pygame.math.Vector2(-1, 0)
|
||||
elif player.status.split('_')[0] == 'up':
|
||||
elif player._input.status.split('_')[0] == 'up':
|
||||
direction = pygame.math.Vector2(0, -1)
|
||||
else:
|
||||
direction = pygame.math.Vector2(0, 1)
|
||||
|
|
|
@ -12,7 +12,7 @@ class Weapon(pygame.sprite.Sprite):
|
|||
script_dir, '../..', 'assets')
|
||||
|
||||
self.sprite_type = 'weapon'
|
||||
direction = player.status.split('_')[0]
|
||||
direction = player._input.status.split('_')[0]
|
||||
|
||||
# Graphic
|
||||
full_path = f"{asset_path}/graphics/weapons/{player._input.combat.weapon}/{direction}.png"
|
||||
|
|
|
@ -10,21 +10,22 @@ from .combat import CombatHandler
|
|||
|
||||
class InputHandler:
|
||||
|
||||
def __init__(self, sprite_type, status):
|
||||
self.status = status
|
||||
# , status):
|
||||
def __init__(self, sprite_type, animation_player):
|
||||
self.status = 'down'
|
||||
self.sprite_type = sprite_type
|
||||
|
||||
# Setup Movement
|
||||
self.movement = MovementHandler(sprite_type)
|
||||
self.movement = MovementHandler(self.sprite_type)
|
||||
self.move_cooldown = 15
|
||||
self.can_move = True
|
||||
self.move_time = None
|
||||
|
||||
# Setup Combat
|
||||
self.combat = CombatHandler()
|
||||
self.combat = CombatHandler(animation_player)
|
||||
self.attacking = False
|
||||
self.attack_cooldown = 400
|
||||
self.attack_time = None
|
||||
self.can_move = True
|
||||
|
||||
# Setup Special Actions
|
||||
self.can_rotate_weapon = True
|
||||
|
@ -37,28 +38,30 @@ class InputHandler:
|
|||
def check_input(self, speed, hitbox, obstacle_sprites, rect, player):
|
||||
|
||||
if not self.attacking and self.can_move:
|
||||
|
||||
keys = pygame.key.get_pressed()
|
||||
button = randint(0, 7)
|
||||
|
||||
# button = randint(0, 5)
|
||||
|
||||
self.move_time = pygame.time.get_ticks()
|
||||
|
||||
# Movement Input
|
||||
if button == 0: # keys[pygame.K_w]:
|
||||
if keys[pygame.K_w]: # button == 0: # keys[pygame.K_w]:
|
||||
self.movement.direction.y = -1
|
||||
self.status = 'up'
|
||||
self.can_move = False
|
||||
elif button == 1: # keys[pygame.K_s]:
|
||||
elif keys[pygame.K_s]: # button == 1: # keys[pygame.K_s]:
|
||||
self.movement.direction.y = 1
|
||||
self.status = 'down'
|
||||
self.can_move = False
|
||||
else:
|
||||
self.movement.direction.y = 0
|
||||
|
||||
if button == 2: # keys[pygame.K_a]:
|
||||
if keys[pygame.K_a]: # button == 2: # keys[pygame.K_a]:
|
||||
self.movement.direction.x = -1
|
||||
self.status = 'left'
|
||||
self.can_move = False
|
||||
elif button == 3: # keys[pygame.K_d]:
|
||||
elif keys[pygame.K_d]: # keys[pygame.K_d]:
|
||||
self.movement.direction.x = 1
|
||||
self.status = 'right'
|
||||
self.can_move = False
|
||||
|
@ -67,15 +70,16 @@ class InputHandler:
|
|||
|
||||
self.movement.move(speed, hitbox, obstacle_sprites, rect)
|
||||
|
||||
if self.sprite_type == 'player':
|
||||
# Combat Input
|
||||
if button == 4 and not self.attacking: # keys[pygame.K_e]
|
||||
if keys[pygame.K_e] and not self.attacking: # keys[pygame.K_e]
|
||||
self.attacking = True
|
||||
self.attack_time = pygame.time.get_ticks()
|
||||
self.combat.create_attack_sprite(player)
|
||||
# self.weapon_attack_sound.play()
|
||||
self.combat.weapon_attack_sound.play()
|
||||
|
||||
# Magic Input
|
||||
if button == 5: # keys[pygame.K_q]:
|
||||
if keys[pygame.K_q]: # keys[pygame.K_q]:
|
||||
self.attacking = True
|
||||
self.attack_time = pygame.time.get_ticks()
|
||||
|
||||
|
@ -87,12 +91,12 @@ class InputHandler:
|
|||
|
||||
cost = list(magic_data.values())[
|
||||
self.combat.magic_index]['cost']
|
||||
print(self.combat.magic)
|
||||
self.combat.create_magic_sprite(
|
||||
player, self.combat.magic, strength, cost)
|
||||
|
||||
# Rotating Weapons
|
||||
if button == 6 and self.can_rotate_weapon: # keys[pygame.K_LSHIFT]
|
||||
# keys[pygame.K_LSHIFT]
|
||||
if keys[pygame.K_LSHIFT] and self.can_rotate_weapon:
|
||||
self.can_rotate_weapon = False
|
||||
self.weapon_rotation_time = pygame.time.get_ticks()
|
||||
if self.combat.weapon_index < len(list(weapon_data.keys())) - 1:
|
||||
|
@ -104,7 +108,8 @@ class InputHandler:
|
|||
self.combat.weapon_index]
|
||||
|
||||
# Swap Spells
|
||||
if button == 7 and self.can_swap_magic: # keys[pygame.K_LCTRL] :
|
||||
# keys[pygame.K_LCTRL] :
|
||||
if keys[pygame.K_LCTRL] and self.can_swap_magic:
|
||||
self.can_swap_magic = False
|
||||
self.magic_swap_time = pygame.time.get_ticks()
|
||||
if self.combat.magic_index < len(list(magic_data.keys())) - 1:
|
||||
|
@ -114,6 +119,7 @@ class InputHandler:
|
|||
|
||||
def cooldowns(self, vulnerable):
|
||||
current_time = pygame.time.get_ticks()
|
||||
self.vulnerable = vulnerable
|
||||
|
||||
if self.attacking:
|
||||
if current_time - self.attack_time > self.attack_cooldown + weapon_data[self.combat.weapon]['cooldown']:
|
||||
|
@ -130,8 +136,8 @@ class InputHandler:
|
|||
self.can_swap_magic = True
|
||||
|
||||
if not vulnerable:
|
||||
if current_time - self.hurt_time >= self.invulnerability_duration:
|
||||
vulnerable = True
|
||||
if current_time - self.combat.hurt_time >= self.combat.invulnerability_duration:
|
||||
self.combat.vulnerable = True
|
||||
|
||||
if not self.can_move:
|
||||
if current_time - self.move_time >= self.move_cooldown:
|
||||
|
|
|
@ -3,20 +3,25 @@ import pygame
|
|||
from math import sin
|
||||
|
||||
from utils.resource_loader import import_folder
|
||||
|
||||
from configs.system.window_config import HITBOX_OFFSET
|
||||
|
||||
|
||||
class AnimationHandler:
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, sprite_type, name=None):
|
||||
self.frame_index = 0
|
||||
self.animation_speed = 0.15
|
||||
|
||||
def import_assets(self, sprite_type, position, name=None):
|
||||
self.sprite_type = sprite_type
|
||||
self.name = name
|
||||
|
||||
def import_assets(self, position):
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
asset_path = os.path.join(
|
||||
script_dir, '../../..', 'assets', 'graphics')
|
||||
if sprite_type == 'player':
|
||||
|
||||
if self.sprite_type == 'player':
|
||||
|
||||
character_path = f"{asset_path}/player"
|
||||
|
||||
|
@ -24,7 +29,8 @@ class AnimationHandler:
|
|||
self.image = pygame.image.load(
|
||||
f"{character_path}/down/down_0.png").convert_alpha()
|
||||
self.rect = self.image.get_rect(topleft=position)
|
||||
self.hitbox = self.rect.inflate(HITBOX_OFFSET[sprite_type])
|
||||
self.hitbox = self.rect.inflate(HITBOX_OFFSET[self.sprite_type])
|
||||
|
||||
self.animations = {
|
||||
'up': [], 'down': [], 'left': [], 'right': [],
|
||||
'up_idle': [], 'down_idle': [], 'left_idle': [], 'right_idle': [],
|
||||
|
@ -34,21 +40,30 @@ class AnimationHandler:
|
|||
full_path = f"{character_path}/{animation}"
|
||||
self.animations[animation] = import_folder(full_path)
|
||||
|
||||
elif sprite_type == 'enemy':
|
||||
elif self.sprite_type == 'enemy':
|
||||
|
||||
self.status = 'idle'
|
||||
|
||||
character_path = f"{asset_path}/monsters/{self.name}"
|
||||
|
||||
character_path = f"{asset_path}/monsters/{name}"
|
||||
self.animations = {'idle': [], 'move': [], 'attack': []}
|
||||
main_path = f"{asset_path}/monsters/{name}"
|
||||
|
||||
for animation in self.animations.keys():
|
||||
self.animations[animation] = import_folder(
|
||||
f"{main_path}/{animation}")
|
||||
f"{character_path}/{animation}")
|
||||
|
||||
self.image = self.animations[self.status][self.frame_index]
|
||||
self.rect = self.image.get_rect(topleft=position)
|
||||
self.hitbox = self.rect.inflate(0, -10)
|
||||
|
||||
def animate(self, status, vulnerable=True, can_attack=False):
|
||||
|
||||
def animate(self, status, vulnerable):
|
||||
animation = self.animations[status]
|
||||
|
||||
self.frame_index += self.animation_speed
|
||||
if self.frame_index >= len(animation):
|
||||
if self.sprite_type == 'enemy':
|
||||
if status == 'attack':
|
||||
self.can_attack = False
|
||||
self.frame_index = 0
|
||||
|
||||
# Set the image
|
||||
|
@ -61,6 +76,10 @@ class AnimationHandler:
|
|||
else:
|
||||
self.image.set_alpha(255)
|
||||
|
||||
def trigger_death_particles(self, animation_player, position, particle_type, groups):
|
||||
animation_player.generate_particles(
|
||||
particle_type, position, groups)
|
||||
|
||||
def wave_value(self):
|
||||
value = sin(pygame.time.get_ticks())
|
||||
if value >= 0:
|
||||
|
|
27
game/entities/components/audio.py
Normal file
27
game/entities/components/audio.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
import os
|
||||
import pygame
|
||||
|
||||
from configs.game.monster_config import monster_data
|
||||
|
||||
|
||||
class AudioHandler:
|
||||
|
||||
def __init__(self, sprite_type, monster_name=None):
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
asset_path = os.path.join(
|
||||
script_dir, '../../..', 'assets', 'audio')
|
||||
|
||||
if sprite_type == 'player':
|
||||
pass
|
||||
|
||||
elif sprite_type == 'enemy':
|
||||
|
||||
# Sounds
|
||||
self.attack_sound = pygame.mixer.Sound(
|
||||
monster_data[monster_name]['attack_sound'])
|
||||
self.death_sound = pygame.mixer.Sound(
|
||||
f'{asset_path}/death.wav')
|
||||
self.hit_sound = pygame.mixer.Sound(f'{asset_path}/hit.wav')
|
||||
self.death_sound.set_volume(0.2)
|
||||
self.hit_sound.set_volume(0.2)
|
||||
self.attack_sound.set_volume(0.2)
|
|
@ -3,7 +3,6 @@ import pygame
|
|||
|
||||
from effects.weapon_effects import Weapon
|
||||
from effects.magic_effects import MagicPlayer
|
||||
from effects.particle_effects import AnimationPlayer
|
||||
|
||||
from configs.game.weapon_config import weapon_data
|
||||
from configs.game.spell_config import magic_data
|
||||
|
@ -11,11 +10,12 @@ from configs.game.spell_config import magic_data
|
|||
|
||||
class CombatHandler:
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, animation_player):
|
||||
|
||||
self.animation_player = animation_player
|
||||
|
||||
# Setup Combat
|
||||
self.animation_player = AnimationPlayer()
|
||||
self.magic_player = MagicPlayer(self.animation_player)
|
||||
self.magic_player = MagicPlayer(animation_player)
|
||||
self.current_attack = None
|
||||
|
||||
# Spell and Weapon Rotation
|
||||
|
@ -31,13 +31,13 @@ class CombatHandler:
|
|||
self.invulnerability_duration = 300
|
||||
|
||||
# Import Sounds
|
||||
# script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
# asset_path = os.path.join(
|
||||
# script_dir, '../../..', 'assets', 'audio')
|
||||
#
|
||||
# self.weapon_attack_sound = pygame.mixer.Sound(
|
||||
# f"{asset_path}/sword.wav")
|
||||
# self.weapon_attack_sound.set_volume(0.2)
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
asset_path = os.path.join(
|
||||
script_dir, '../../..', 'assets', 'audio')
|
||||
|
||||
self.weapon_attack_sound = pygame.mixer.Sound(
|
||||
f"{asset_path}/sword.wav")
|
||||
self.weapon_attack_sound.set_volume(0.2)
|
||||
|
||||
def create_attack_sprite(self, player):
|
||||
self.current_attack = Weapon(
|
||||
|
@ -49,7 +49,6 @@ class CombatHandler:
|
|||
self.current_attack = None
|
||||
|
||||
def create_magic_sprite(self, player, style, strength, cost):
|
||||
print(style)
|
||||
if style == 'heal':
|
||||
self.magic_player.heal(player, strength, cost, [
|
||||
player.visible_sprites])
|
||||
|
|
|
@ -1,29 +1,18 @@
|
|||
from configs.game.player_config import stats, max_stats, upgrade_costs
|
||||
from configs.game.monster_config import monster_data
|
||||
|
||||
|
||||
class StatsHandler:
|
||||
|
||||
def __init__(self):
|
||||
self.stats = {
|
||||
'health': 100,
|
||||
'energy': 60,
|
||||
'attack': 10,
|
||||
'magic': 4,
|
||||
'speed': 5
|
||||
}
|
||||
def __init__(self, sprite_type, monster_name=None):
|
||||
|
||||
self.max_stats = {
|
||||
'health': 300,
|
||||
'energy': 150,
|
||||
'attack': 20,
|
||||
'magic': 10,
|
||||
'speed': 10
|
||||
}
|
||||
if sprite_type == 'player':
|
||||
|
||||
self.upgrade_costs = {
|
||||
'health': 100,
|
||||
'energy': 100,
|
||||
'attack': 100,
|
||||
'magic': 100,
|
||||
'speed': 100
|
||||
}
|
||||
self.stats = stats
|
||||
|
||||
self.max_stats = max_stats
|
||||
|
||||
self.upgrade_costs = upgrade_costs
|
||||
|
||||
self.health = self.stats['health']
|
||||
self.energy = self.stats['energy']
|
||||
|
@ -32,9 +21,21 @@ class StatsHandler:
|
|||
self.speed = self.stats['speed']
|
||||
self.exp = 10000
|
||||
|
||||
if sprite_type == 'enemy':
|
||||
|
||||
self.monster_info = monster_data[monster_name]
|
||||
self.health = self.monster_info['health']
|
||||
self.attack = self.monster_info['attack']
|
||||
self.attack_type = self.monster_info['attack_type']
|
||||
self.attack_radius = self.monster_info['attack_radius']
|
||||
self.speed = self.monster_info['speed']
|
||||
self.knockback = self.monster_info['knockback']
|
||||
self.notice_radius = self.monster_info['notice_radius']
|
||||
self.exp = self.monster_info['exp']
|
||||
|
||||
def energy_recovery(self):
|
||||
if self.energy < self.stats['energy']:
|
||||
self.energy += 0.01 * self.stats['magic']
|
||||
self.energy += 0.01 * self.magic
|
||||
else:
|
||||
self.energy = self.stats['energy']
|
||||
|
||||
|
|
92
game/entities/enemy.py
Normal file
92
game/entities/enemy.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
import pygame
|
||||
|
||||
from .components.animaton import AnimationHandler
|
||||
from .components.stats import StatsHandler
|
||||
from .components._input import InputHandler
|
||||
|
||||
from effects.particle_effects import AnimationPlayer
|
||||
|
||||
from .components.audio import AudioHandler
|
||||
|
||||
|
||||
class Enemy(pygame.sprite.Sprite):
|
||||
|
||||
def __init__(self, name, position, groups, visible_sprites, obstacle_sprites):
|
||||
super().__init__(groups)
|
||||
self.sprite_type = "enemy"
|
||||
self.name = name
|
||||
self.visible_sprites = visible_sprites
|
||||
|
||||
# Setup Graphics
|
||||
self.audio = AudioHandler(self.sprite_type, self.name)
|
||||
self.animation_player = AnimationPlayer()
|
||||
self.animation = AnimationHandler(self.sprite_type, self.name)
|
||||
self.animation.import_assets(position)
|
||||
self.status = self.animation.status
|
||||
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, self.name)
|
||||
self.obstacle_sprites = obstacle_sprites
|
||||
|
||||
self.distance_direction_from_player = None
|
||||
|
||||
self.kills = 0
|
||||
|
||||
def get_action(self):
|
||||
player_distance = sorted(
|
||||
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:
|
||||
self._input.movement.direction = player_distance[1]
|
||||
self.animation.status = "move"
|
||||
self._input.movement.move(
|
||||
self.stats.speed, self.animation.hitbox, self.obstacle_sprites, self.animation.rect)
|
||||
elif player_distance[0] <= self.stats.attack_radius:
|
||||
self.animation.status = 'attack'
|
||||
else:
|
||||
self.animation.status = 'idle'
|
||||
|
||||
def add_exp(self, player):
|
||||
player.stats.exp += self.stats.exp
|
||||
|
||||
def check_death(self, player):
|
||||
if self.stats.health <= 0:
|
||||
self.add_exp(player)
|
||||
self.animation.trigger_death_particles(
|
||||
self.animation_player, self.rect.center, self.name, self.visible_sprites)
|
||||
self.audio.death_sound.play()
|
||||
self.kill()
|
||||
|
||||
def get_damaged(self, player, attack_type):
|
||||
if self._input.combat.vulnerable:
|
||||
self.audio.hit_sound.play()
|
||||
for _, direction, attacking_player in self.distance_direction_from_player:
|
||||
if attacking_player == player:
|
||||
self._input.movement.direction = -direction
|
||||
self._input.movement.move(
|
||||
self.stats.speed * self.stats.knockback, self.animation.hitbox, self.obstacle_sprites, self.animation.rect)
|
||||
break
|
||||
if attack_type == 'weapon':
|
||||
self.stats.health -= player.get_full_weapon_damage()
|
||||
else:
|
||||
self.stats.health -= player.get_full_magic_damage()
|
||||
self.check_death(player)
|
||||
self._input.combat.hurt_time = pygame.time.get_ticks()
|
||||
self._input.combat.vulnerable = False
|
||||
|
||||
def update(self):
|
||||
|
||||
self.get_action()
|
||||
self.status = self.animation.status
|
||||
|
||||
self.animation.animate(self.status, self._input.combat.vulnerable)
|
||||
self.image = self.animation.image
|
||||
self.rect = self.animation.rect
|
||||
|
||||
self._input.cooldowns(self._input.combat.vulnerable)
|
|
@ -1,14 +1,19 @@
|
|||
import pygame
|
||||
from random import randint
|
||||
|
||||
from configs.game.weapon_config import weapon_data
|
||||
from configs.game.spell_config import magic_data
|
||||
|
||||
from .components.combat import CombatHandler
|
||||
from .components.stats import StatsHandler
|
||||
from .components._input import InputHandler
|
||||
from .components.animaton import AnimationHandler
|
||||
|
||||
from effects.particle_effects import AnimationPlayer
|
||||
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
|
||||
def __init__(self, position, groups, obstacle_sprites, visible_sprites, attack_sprites):
|
||||
def __init__(self, position, groups, obstacle_sprites, visible_sprites, attack_sprites, attackable_sprites):
|
||||
super().__init__(groups)
|
||||
|
||||
# Setup Sprites
|
||||
|
@ -16,32 +21,33 @@ class Player(pygame.sprite.Sprite):
|
|||
self.visible_sprites = visible_sprites
|
||||
self.attack_sprites = attack_sprites
|
||||
self.obstacle_sprites = obstacle_sprites
|
||||
self.status = 'down'
|
||||
self.attackable_sprites = attackable_sprites
|
||||
|
||||
# Setup Graphics
|
||||
self.animation_player = AnimationPlayer()
|
||||
self.animation = AnimationHandler(self.sprite_type)
|
||||
self.animation.import_assets(position)
|
||||
self.image = self.animation.image
|
||||
self.rect = self.animation.rect
|
||||
|
||||
# Setup Inputs
|
||||
self._input = InputHandler(
|
||||
self.sprite_type, self.status)
|
||||
|
||||
# Setup Graphics
|
||||
self.animation = AnimationHandler()
|
||||
self.animation.import_assets(self.sprite_type, position)
|
||||
self.animate = self.animation.animate
|
||||
self.image = self.animation.image
|
||||
self.animate(self.status, self._input.combat.vulnerable)
|
||||
self.rect = self.animation.rect
|
||||
self.sprite_type, self.animation_player) # , self.status)
|
||||
|
||||
# Setup Stats
|
||||
self.stats = StatsHandler()
|
||||
self.stats = StatsHandler(self.sprite_type)
|
||||
|
||||
self.distance_direction_from_enemy = None
|
||||
|
||||
def get_status(self):
|
||||
if self._input.movement.direction.x == 0 and self._input.movement.direction.y == 0:
|
||||
if not 'idle' in self.status and not 'attack' in self.status:
|
||||
if 'idle' not in self.status and 'attack' not in self.status:
|
||||
self.status += '_idle'
|
||||
|
||||
if self._input.attacking:
|
||||
self._input.movement.direction.x = 0
|
||||
self._input.movement.direction.y = 0
|
||||
if not 'attack' in self.status:
|
||||
if 'attack' not in self.status:
|
||||
if 'idle' in self.status:
|
||||
self.status = self.status.replace('idle', 'attack')
|
||||
else:
|
||||
|
@ -50,10 +56,38 @@ class Player(pygame.sprite.Sprite):
|
|||
if 'attack' in self.status:
|
||||
self.status = self.status.replace('_attack', '')
|
||||
|
||||
def attack_logic(self):
|
||||
if self.attack_sprites:
|
||||
for attack_sprite in self.attack_sprites:
|
||||
collision_sprites = pygame.sprite.spritecollide(
|
||||
attack_sprite, self.attackable_sprites, False)
|
||||
if collision_sprites:
|
||||
for target_sprite in collision_sprites:
|
||||
if target_sprite.sprite_type == 'grass':
|
||||
pos = target_sprite.rect.center
|
||||
offset = pygame.math.Vector2(0, 75)
|
||||
for leaf in range(randint(3, 6)):
|
||||
self.animation_player.create_grass_particles(
|
||||
position=pos - offset, groups=[self.visible_sprites])
|
||||
target_sprite.kill()
|
||||
else:
|
||||
target_sprite.get_damaged(
|
||||
self, attack_sprite.sprite_type)
|
||||
|
||||
def get_full_weapon_damage(self):
|
||||
base_damage = self.stats.attack
|
||||
weapon_damage = weapon_data[self._input.combat.weapon]['damage']
|
||||
return (base_damage + weapon_damage)
|
||||
|
||||
def get_full_magic_damage(self):
|
||||
base_damage = self.stats.magic
|
||||
spell_damage = magic_data[self._input.combat.magic]['strength']
|
||||
return (base_damage + spell_damage)
|
||||
|
||||
def update(self):
|
||||
# Refresh objects based on input
|
||||
self._input.check_input(
|
||||
self.stats.stats['speed'], self.animation.hitbox, self.obstacle_sprites, self.animation.rect, self)
|
||||
self.stats.speed, self.animation.hitbox, self.obstacle_sprites, self.animation.rect, self)
|
||||
self.status = self._input.status
|
||||
|
||||
# Animate
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import pygame
|
||||
|
||||
from .ui_settings import *
|
||||
from .ui_settings import UI_FONT, UI_FONT_SIZE, TEXT_COLOR, TEXT_COLOR_SELECTED, UPGRADE_BG_COLOR_SELECTED, UI_BORDER_COLOR, UI_BG_COLOR, BAR_COLOR_SELECTED, BAR_COLOR
|
||||
|
||||
|
||||
class Upgrade:
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import os
|
||||
import pygame
|
||||
|
||||
from random import choice, randint
|
||||
from random import choice
|
||||
|
||||
from configs.game.spell_config import magic_data
|
||||
from configs.game.weapon_config import weapon_data
|
||||
from configs.game.monster_config import monster_data
|
||||
from configs.system.window_config import TILESIZE
|
||||
|
||||
from utils.debug import debug
|
||||
|
@ -14,12 +11,9 @@ from utils.resource_loader import import_csv_layout, import_folder
|
|||
from interface.ui import UI
|
||||
from interface.upgrade import Upgrade
|
||||
|
||||
from effects.magic_effects import MagicPlayer
|
||||
from effects.particle_effects import AnimationPlayer
|
||||
from effects.weapon_effects import Weapon
|
||||
|
||||
from entities.observer import Observer
|
||||
from entities.player import Player
|
||||
from entities.enemy import Enemy
|
||||
|
||||
from .terrain import Tile
|
||||
from .camera import Camera
|
||||
|
@ -48,6 +42,9 @@ class Level:
|
|||
self.ui = UI()
|
||||
self.upgrade = Upgrade(self.player)
|
||||
|
||||
self.get_players_enemies()
|
||||
self.get_distance_direction()
|
||||
|
||||
def create_map(self):
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
asset_path = os.path.join(
|
||||
|
@ -92,28 +89,85 @@ class Level:
|
|||
elif col == '394':
|
||||
# Player Generation
|
||||
self.player = Player(
|
||||
(x, y), [self.visible_sprites], self.obstacle_sprites, self.visible_sprites, self.attack_sprites)
|
||||
(x, y), [self.visible_sprites], self.obstacle_sprites, self.visible_sprites, self.attack_sprites, self.attackable_sprites)
|
||||
|
||||
else:
|
||||
pass
|
||||
# monster generation
|
||||
# Monster Generation
|
||||
if col == '390':
|
||||
monster_name = 'bamboo'
|
||||
elif col == '391':
|
||||
monster_name = 'spirit'
|
||||
elif col == '392':
|
||||
monster_name = 'raccoon'
|
||||
else:
|
||||
monster_name = 'squid'
|
||||
|
||||
Enemy(monster_name, (x, y), [
|
||||
self.visible_sprites, self.attackable_sprites], self.visible_sprites, self.obstacle_sprites)
|
||||
|
||||
def get_players_enemies(self):
|
||||
self.player_sprites = [sprite for sprite in self.visible_sprites.sprites(
|
||||
) if hasattr(sprite, 'sprite_type') and sprite.sprite_type in ('player')]
|
||||
|
||||
self.enemy_sprites = [sprite for sprite in self.visible_sprites.sprites(
|
||||
) if hasattr(sprite, 'sprite_type') and sprite.sprite_type in ('enemy')]
|
||||
|
||||
def get_distance_direction(self):
|
||||
for player in self.player_sprites:
|
||||
player.distance_direction_from_enemy = []
|
||||
|
||||
for enemy in self.enemy_sprites:
|
||||
enemy.distance_direction_from_player = []
|
||||
|
||||
for player in self.player_sprites:
|
||||
player_vector = pygame.math.Vector2(player.rect.center)
|
||||
for enemy in self.enemy_sprites:
|
||||
enemy_vector = pygame.math.Vector2(enemy.rect.center)
|
||||
distance = (player_vector - enemy_vector).magnitude()
|
||||
|
||||
if distance > 0:
|
||||
direction = (player_vector - enemy_vector).normalize()
|
||||
else:
|
||||
direction = pygame.math.Vector2()
|
||||
|
||||
enemy.distance_direction_from_player.append(
|
||||
(distance, direction, player))
|
||||
player.distance_direction_from_enemy.append(
|
||||
(distance, -direction, enemy))
|
||||
|
||||
def apply_damage_to_player(self):
|
||||
for enemy in self.enemy_sprites:
|
||||
for distance, _, player in enemy.distance_direction_from_player:
|
||||
if distance < enemy.stats.attack_radius and player._input.combat.vulnerable:
|
||||
player.stats.health -= enemy.stats.attack
|
||||
player._input.combat.vulnerable = False
|
||||
player._input.combat.hurt_time = pygame.time.get_ticks()
|
||||
|
||||
def toggle_menu(self):
|
||||
self.game_paused = not self.game_paused
|
||||
|
||||
def run(self):
|
||||
def run(self, who='observer'):
|
||||
# Draw the game
|
||||
if who == 'observer':
|
||||
self.visible_sprites.custom_draw(self.observer)
|
||||
self.ui.display(self.observer)
|
||||
elif who == 'player':
|
||||
self.visible_sprites.custom_draw(self.player)
|
||||
self.ui.display(self.player)
|
||||
debug(self.player.status)
|
||||
debug('v0.5')
|
||||
if not self.game_paused:
|
||||
# Update the game
|
||||
# self.player.distance_direction_to_player = self.get_state()
|
||||
for player in self.player_sprites:
|
||||
player.attack_logic()
|
||||
|
||||
self.get_players_enemies()
|
||||
self.get_distance_direction()
|
||||
self.apply_damage_to_player()
|
||||
self.visible_sprites.update()
|
||||
|
||||
# self.visible_sprites.enemy_update(self.player)
|
||||
# self.player_attack_logic()
|
||||
else:
|
||||
if self.visible_sprites.sprite_type == 'player':
|
||||
self.upgrade.display()
|
||||
|
||||
if self.player.stats.health <= 0:
|
||||
|
|
17
game/main.py
17
game/main.py
|
@ -2,10 +2,12 @@ import pygame
|
|||
import sys
|
||||
|
||||
from configs.system.window_config import WIDTH, HEIGHT, WATER_COLOR, FPS
|
||||
from utils.debug import debug
|
||||
|
||||
from level.level import Level
|
||||
|
||||
import os
|
||||
import psutil
|
||||
|
||||
|
||||
class Game:
|
||||
|
||||
|
@ -13,16 +15,17 @@ class Game:
|
|||
|
||||
pygame.init()
|
||||
|
||||
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
self.screen = pygame.display.set_mode(
|
||||
(WIDTH, HEIGHT))
|
||||
pygame.display.set_caption('Pneuma')
|
||||
self.clock = pygame.time.Clock()
|
||||
|
||||
self.level = Level()
|
||||
|
||||
# # Sound
|
||||
# main_sound = pygame.mixer.Sound('../assets/audio/main.ogg')
|
||||
# main_sound.set_volume(0.4)
|
||||
# main_sound.play(loops=-1)
|
||||
# Sound
|
||||
main_sound = pygame.mixer.Sound('../assets/audio/main.ogg')
|
||||
main_sound.set_volume(0.4)
|
||||
main_sound.play(loops=-1)
|
||||
|
||||
def run(self):
|
||||
|
||||
|
@ -35,7 +38,7 @@ class Game:
|
|||
self.level.toggle_menu()
|
||||
|
||||
self.screen.fill(WATER_COLOR)
|
||||
self.level.run()
|
||||
self.level.run('player')
|
||||
pygame.display.update()
|
||||
self.clock.tick(FPS)
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import pygame
|
||||
import sys
|
||||
import os
|
||||
|
||||
from utils.settings import *
|
||||
from utils.debug import debug
|
||||
|
@ -7,13 +8,15 @@ from utils.debug import debug
|
|||
from objects.level import Level
|
||||
|
||||
|
||||
|
||||
class Game:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
pygame.init()
|
||||
|
||||
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||
self.screen = pygame.display.set_mode(
|
||||
(WIDTH, HEIGHT))
|
||||
pygame.display.set_caption('Pneuma')
|
||||
self.clock = pygame.time.Clock()
|
||||
|
||||
|
@ -43,6 +46,5 @@ class Game:
|
|||
if __name__ == '__main__':
|
||||
|
||||
game = Game()
|
||||
figure_file = 'rl/plots/pneuma.png'
|
||||
while True:
|
||||
game.run()
|
||||
|
|
Loading…
Reference in a new issue