pneuma-pygame/level/level.py

230 lines
8.9 KiB
Python
Raw Normal View History

import os
import pygame
import numpy as np
2023-10-04 02:37:28 +00:00
from random import choice
from configs.system.window_config import TILESIZE
from utils.debug import debug
from utils.resource_loader import import_csv_layout, import_folder
from interface.ui import UI
from entities.observer import Observer
from entities.player import Player
2023-10-04 02:37:28 +00:00
from entities.enemy import Enemy
from .terrain import Tile
from .camera import Camera
class Level:
def __init__(self, n_players, reset=False):
# General Settings
self.game_paused = False
2023-11-17 02:19:03 +00:00
self.done = False
2023-11-14 21:44:43 +00:00
# Get display surface
self.display_surface = pygame.display.get_surface()
# Sprite Group setup
self.visible_sprites = Camera()
self.obstacle_sprites = pygame.sprite.Group()
self.attack_sprites = pygame.sprite.Group()
self.attackable_sprites = pygame.sprite.Group()
# Sprite setup and entity generation
self.create_map(n_players)
2023-11-14 21:44:43 +00:00
self.get_players_enemies()
self.get_distance_direction()
2023-11-19 03:27:47 +00:00
if not reset:
for player in self.player_sprites:
player.get_max_num_states()
player.setup_agent()
else:
for player in self.player_sprites:
player.get_max_num_states()
self.dead_players = np.zeros(len(self.player_sprites))
# UI setup
self.ui = UI()
2023-10-04 02:37:28 +00:00
def create_map(self, n_players):
2023-11-14 21:44:43 +00:00
player_id = 0
script_dir = os.path.dirname(os.path.abspath(__file__))
asset_path = os.path.join(
2023-11-14 21:44:43 +00:00
script_dir, '..', 'assets')
layouts = {
'boundary': import_csv_layout(f"{asset_path}/map/FloorBlocks.csv"),
'grass': import_csv_layout(f"{asset_path}/map/Grass.csv"),
'objects': import_csv_layout(f"{asset_path}/map/Objects.csv"),
'entities': import_csv_layout(f"{asset_path}/map/Entities.csv")
}
graphics = {
'grass': import_folder(f"{asset_path}/graphics/grass"),
'objects': import_folder(f"{asset_path}/graphics/objects")
}
for style, layout in layouts.items():
for row_index, row in enumerate(layout):
for col_index, col in enumerate(row):
if col != '-1':
x = col_index * TILESIZE
y = row_index * TILESIZE
if style == 'boundary':
Tile((x, y), [self.obstacle_sprites], 'invisible')
if style == 'grass':
random_grass_image = choice(graphics['grass'])
Tile((x, y), [self.visible_sprites, self.obstacle_sprites,
self.attackable_sprites], 'grass', random_grass_image)
2023-11-19 03:27:47 +00:00
#
# if style == 'objects':
# surf = graphics['objects'][int(col)]
# Tile((x, y), [self.visible_sprites,
# self.obstacle_sprites], 'object', surf)
2023-11-17 02:19:03 +00:00
if style == 'entities':
# The numbers represent their IDs in .csv files generated from TILED.
if col == '500':
self.observer = Observer(
(x, y), [self.visible_sprites])
elif col == '400':
if choice([0, 1]) == 1 and player_id <= n_players:
# Player Generation
Player(
(x, y),
[self.visible_sprites],
self.obstacle_sprites,
self.visible_sprites,
self.attack_sprites,
self.attackable_sprites,
'tank',
player_id)
player_id += 1
2023-11-17 02:19:03 +00:00
elif col == '401':
# Player Generation
Player(
2023-11-24 23:26:47 +00:00
(x, y),
[self.visible_sprites],
self.obstacle_sprites,
self.visible_sprites,
self.attack_sprites,
self.attackable_sprites,
'warrior',
player_id)
2023-11-17 02:19:03 +00:00
player_id += 1
elif col == '402':
# Player Generation
Player(
2023-11-24 23:26:47 +00:00
(x, y),
[self.visible_sprites],
self.obstacle_sprites,
self.visible_sprites,
self.attack_sprites,
self.attackable_sprites,
'mage',
player_id)
2023-11-14 21:44:43 +00:00
player_id += 1
else:
2023-10-04 02:37:28 +00:00
# Monster Generation
if col == '390':
monster_name = 'bamboo'
elif col == '391':
monster_name = 'spirit'
elif col == '392':
monster_name = 'raccoon'
2023-11-24 23:26:47 +00:00
elif col == ' 393':
2023-10-04 02:37:28 +00:00
monster_name = 'squid'
2023-11-24 23:26:47 +00:00
Enemy(monster_name,
(x, y),
[
self.visible_sprites,
self.attackable_sprites
],
self.visible_sprites,
self.obstacle_sprites)
2023-10-04 02:37:28 +00:00
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
2023-10-04 02:37:28 +00:00
def run(self, who='observer'):
# Draw the game
2023-10-04 02:37:28 +00:00
if who == 'observer':
self.visible_sprites.custom_draw(self.observer)
self.ui.display(self.observer)
2023-11-24 23:26:47 +00:00
else:
self.visible_sprites.custom_draw(self.player)
self.ui.display(self.aaa)
2023-11-13 12:34:22 +00:00
debug('v0.8')
2023-11-13 12:34:22 +00:00
if not self.game_paused:
# Update the game
2023-10-04 02:37:28 +00:00
for player in self.player_sprites:
player.attack_logic()
self.get_players_enemies()
self.get_distance_direction()
self.visible_sprites.update()
2023-11-23 15:37:02 +00:00
self.apply_damage_to_player()
2023-10-04 02:37:28 +00:00
else:
2023-11-13 12:34:22 +00:00
debug('PAUSED')
2023-11-23 15:37:02 +00:00
for player in self.player_sprites:
if player.is_dead():
self.dead_players[player.player_id] = True
self.done = True if self.dead_players.all() == 1 else False