Ready to build AI

This commit is contained in:
Vasilis Valatsos 2023-11-13 13:34:22 +01:00
parent b0a925292e
commit ba0cc46841
10 changed files with 170 additions and 48 deletions

View file

@ -19,7 +19,7 @@
-1,-1,-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,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,394,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
-1,-1,-1,-1,-1,-1,-1,-1,-1,-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,395,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-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

1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
19 -1 -1 -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
20 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
21 -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
22 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 394 400 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
23 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 395 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
24 -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
25 -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

View file

@ -6,7 +6,7 @@ asset_path = os.path.join(
script_dir, '../../..', 'assets')
monster_data = {
'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}}
'squid': {'id': 1, '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': {'id': 2, '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': {'id': 3, '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': {'id': 4, '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}}

View file

@ -1,4 +1,23 @@
stats = {
tank_stats = {
'role_id': 1,
'health': 150,
'energy': 40,
'attack': 7,
'magic': 3,
'speed': 3
}
mage_stats = {
'role_id': 2,
'health': 70,
'energy': 80,
'attack': 3,
'magic': 6,
'speed': 5
}
warrior_stats = {
'role_id': 3,
'health': 100,
'energy': 60,
'attack': 10,

View file

@ -1,7 +1,7 @@
# game setup
WIDTH = 1280
HEIGHT = 720
FPS = 60
FPS = 500
TILESIZE = 64
HITBOX_OFFSET = {
'player': (-6, -26),

View file

@ -1,5 +1,5 @@
import pygame
from random import randint
from random import randint, choice
from configs.game.spell_config import magic_data
from configs.game.weapon_config import weapon_data
@ -11,7 +11,7 @@ from .combat import CombatHandler
class InputHandler:
# , status):
def __init__(self, sprite_type, animation_player):
def __init__(self, sprite_type, animation_player, ai_controller=False):
self.status = 'down'
self.sprite_type = sprite_type
@ -41,27 +41,27 @@ class InputHandler:
keys = pygame.key.get_pressed()
# button = randint(0, 5)
button = randint(0, 4)
self.move_time = pygame.time.get_ticks()
# Movement Input
if keys[pygame.K_w]: # button == 0: # keys[pygame.K_w]:
if button == 0: # keys[pygame.K_w]:
self.movement.direction.y = -1
self.status = 'up'
self.can_move = False
elif keys[pygame.K_s]: # button == 1: # keys[pygame.K_s]:
elif 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 keys[pygame.K_a]: # button == 2: # keys[pygame.K_a]:
if button == 2: # keys[pygame.K_a]:
self.movement.direction.x = -1
self.status = 'left'
self.can_move = False
elif keys[pygame.K_d]: # keys[pygame.K_d]:
elif button == 3: # keys[pygame.K_d]:
self.movement.direction.x = 1
self.status = 'right'
self.can_move = False
@ -72,14 +72,14 @@ class InputHandler:
if self.sprite_type == 'player':
# Combat Input
if keys[pygame.K_e] and not self.attacking: # keys[pygame.K_e]
if button == 4 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.combat.weapon_attack_sound.play()
# Magic Input
if keys[pygame.K_q]: # keys[pygame.K_q]:
if button == 5: # keys[pygame.K_q]:
self.attacking = True
self.attack_time = pygame.time.get_ticks()
@ -96,7 +96,7 @@ class InputHandler:
# Rotating Weapons
# keys[pygame.K_LSHIFT]
if keys[pygame.K_LSHIFT] and self.can_rotate_weapon:
if button == 6 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:
@ -109,7 +109,7 @@ class InputHandler:
# Swap Spells
# keys[pygame.K_LCTRL] :
if keys[pygame.K_LCTRL] and self.can_swap_magic:
if button == 7 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:

View file

@ -1,29 +1,32 @@
from configs.game.player_config import stats, max_stats, upgrade_costs
from configs.game.player_config import warrior_stats, mage_stats, tank_stats
from configs.game.monster_config import monster_data
class StatsHandler:
def __init__(self, sprite_type, monster_name=None):
def __init__(self, sprite_type, role=None, monster_name=None):
if sprite_type == 'player':
self.stats = stats
self.max_stats = max_stats
self.upgrade_costs = upgrade_costs
if role == 'warrior':
self.stats = warrior_stats
elif role == 'tank':
self.stats = tank_stats
elif role == 'mage':
self.stats = mage_stats
self.role_id = self.stats['role_id']
self.health = self.stats['health']
self.energy = self.stats['energy']
self.attack = self.stats['attack']
self.magic = self.stats['magic']
self.speed = self.stats['speed']
self.exp = 10000
self.exp = 0
if sprite_type == 'enemy':
self.monster_info = monster_data[monster_name]
self.monster_id = self.monster_info['id']
self.health = self.monster_info['health']
self.attack = self.monster_info['attack']
self.attack_type = self.monster_info['attack_type']

View file

@ -22,7 +22,6 @@ class Enemy(pygame.sprite.Sprite):
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
@ -31,13 +30,11 @@ class Enemy(pygame.sprite.Sprite):
self.sprite_type, self.animation_player)
# Setup Stats
self.stats = StatsHandler(self.sprite_type, self.name)
self.stats = StatsHandler(self.sprite_type, monster_name=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]
@ -83,9 +80,9 @@ class Enemy(pygame.sprite.Sprite):
def update(self):
self.get_action()
self.status = self.animation.status
self.animation.animate(self.status, self._input.combat.vulnerable)
self.animation.animate(self.animation.status,
self._input.combat.vulnerable)
self.image = self.animation.image
self.rect = self.animation.rect

View file

@ -13,7 +13,7 @@ from effects.particle_effects import AnimationPlayer
class Player(pygame.sprite.Sprite):
def __init__(self, position, groups, obstacle_sprites, visible_sprites, attack_sprites, attackable_sprites):
def __init__(self, position, groups, obstacle_sprites, visible_sprites, attack_sprites, attackable_sprites, role):
super().__init__(groups)
# Setup Sprites
@ -35,7 +35,8 @@ class Player(pygame.sprite.Sprite):
self.sprite_type, self.animation_player) # , self.status)
# Setup Stats
self.stats = StatsHandler(self.sprite_type)
self.role = role
self.stats = StatsHandler(self.sprite_type, self.role)
self.distance_direction_from_enemy = None

View file

@ -40,7 +40,7 @@ class Level:
# UI setup
self.ui = UI()
self.upgrade = Upgrade(self.player)
# self.upgrade = Upgrade(self.player)
self.get_players_enemies()
self.get_distance_direction()
@ -86,10 +86,20 @@ class Level:
self.observer = Observer(
(x, y), [self.visible_sprites])
elif col == '394':
elif col == '400':
# Player Generation
self.player = Player(
(x, y), [self.visible_sprites], self.obstacle_sprites, self.visible_sprites, self.attack_sprites, self.attackable_sprites)
Player(
(x, y), [self.visible_sprites], self.obstacle_sprites, self.visible_sprites, self.attack_sprites, self.attackable_sprites, 'tank')
elif col == '401':
# Player Generation
Player(
(x, y), [self.visible_sprites], self.obstacle_sprites, self.visible_sprites, self.attack_sprites, self.attackable_sprites, 'warrior')
elif col == '402':
# Player Generation
Player(
(x, y), [self.visible_sprites], self.obstacle_sprites, self.visible_sprites, self.attack_sprites, self.attackable_sprites, 'mage')
else:
# Monster Generation
@ -154,7 +164,9 @@ class Level:
elif who == 'player':
self.visible_sprites.custom_draw(self.player)
self.ui.display(self.player)
debug('v0.5')
debug('v0.6')
if not self.game_paused:
# Update the game
for player in self.player_sprites:
@ -168,7 +180,8 @@ class Level:
# self.visible_sprites.enemy_update(self.player)
# self.player_attack_logic()
else:
self.upgrade.display()
debug('PAUSED')
if self.player.stats.health <= 0:
self.__init__()
for player in self.player_sprites:
if player.stats.health <= 0:
player.kill()

View file

@ -1,13 +1,12 @@
import pygame
import sys
import numpy as np
import torch
import pygame
from configs.system.window_config import WIDTH, HEIGHT, WATER_COLOR, FPS
from level.level import Level
import os
import psutil
class Game:
@ -27,6 +26,90 @@ class Game:
main_sound.set_volume(0.4)
main_sound.play(loops=-1)
def extract_features(self):
self.features = []
for i, player in enumerate(self.level.player_sprites):
player_features = {
"player_position": player.rect.center,
"player role": player.stats.role_id,
"player_health": player.stats.health,
"player_energy": player.stats.energy,
"player_attack": player.stats.attack,
"player_magic": player.stats.magic,
"player_speed": player.stats.speed,
"player_exp": player.stats.exp,
"player_vulnerable": int(player._input.combat.vulnerable),
"player_can_move": int(player._input.can_move),
"player_attacking": int(player._input.attacking),
"player_can_rotate_weapon": int(player._input.can_rotate_weapon),
"playercan_swap_magic": int(player._input.can_swap_magic)
}
distances_directions = []
for distance, direction, enemy in player.distance_direction_from_enemy:
distances_directions.append({
"enemy_id": enemy.stats.monster_id,
"enemy_status": 0 if enemy.animation.status == "idle" else (1 if enemy.animation.status == "move" else 2),
"enemy_health": enemy.stats.health,
"enemy_attack": enemy.stats.attack,
"enemy_speed": enemy.stats.speed,
"enemy_attack_radius": enemy.stats.attack_radius,
"enemy_notice_radius": enemy.stats.notice_radius,
"enemy_exp": enemy.stats.exp,
"enemy_distance": distance,
"enemy_direction": direction
})
player_features["enemies"] = distances_directions
self.features.append(player_features)
def convert_features_to_tensor(self):
self.tensors = []
for player_features in self.features:
info_array = []
# Adding player features to tensor
player_info = [
player_features['player_position'][0],
player_features['player_position'][1],
player_features['player role'],
player_features['player_health'],
player_features['player_energy'],
player_features['player_attack'],
player_features['player_magic'],
player_features['player_speed'],
player_features['player_exp'],
player_features['player_vulnerable'],
player_features['player_can_move'],
player_features['player_attacking'],
player_features['player_can_rotate_weapon'],
player_features['playercan_swap_magic'],
]
info_array.extend(player_info)
for enemy in player_features['enemies']:
enemy_info = [
enemy['enemy_id'],
enemy['enemy_status'],
enemy['enemy_health'],
enemy['enemy_attack'],
enemy['enemy_speed'],
enemy['enemy_attack_radius'],
enemy['enemy_notice_radius'],
enemy['enemy_exp'],
enemy['enemy_distance'],
enemy['enemy_direction'][0],
enemy['enemy_direction'][1]
]
info_array.extend(enemy_info)
player_tensor = torch.tensor(
np.array(info_array, dtype=np.float32))
self.tensors.append(player_tensor)
def run(self):
for event in pygame.event.get():
@ -38,7 +121,11 @@ class Game:
self.level.toggle_menu()
self.screen.fill(WATER_COLOR)
self.level.run('player')
self.extract_features()
self.convert_features_to_tensor()
self.level.run('observer')
pygame.display.update()
self.clock.tick(FPS)
@ -46,5 +133,7 @@ class Game:
if __name__ == '__main__':
game = Game()
while True:
for _ in range(0, 10000):
game.run()
game.extract_features()
game.convert_features_to_tensor()