pneuma-pygame/level.py
2024-05-22 08:44:04 +02:00

297 lines
11 KiB
Python

import os
import pygame
import numpy as np
from random import choice
from config.system.window import TILESIZE
from utils.debug import debug
from utils.resource_loader import import_csv_layout, import_folder
from interface.ui import UI
from entities.player import Player
from entities.enemy import Enemy
from entities.terrain import Terrain
from camera import Camera
class Level:
def __init__(self, n_players):
self.paused = False
self.done = False
# Get display surface
self.display_surface = pygame.display.get_surface()
# Setup Sprite groups
self.visible_sprites = Camera()
self.obstacle_sprites = pygame.sprite.Group()
self.attack_sprites = pygame.sprite.Group()
self.attackable_sprites = pygame.sprite.Group()
# Map generation
self.n_players = n_players
self.generate_map()
# Handle generated entities
self.get_entities()
self.get_distance_direction()
self.dead_players = np.zeros(self.n_players)
# Setup UI
self.ui = UI()
def generate_map(self):
self.possible_player_locations = []
self.layouts = {
'boundary': import_csv_layout(os.path.join('map',
'FloorBlocks.csv')),
'grass': import_csv_layout(os.path.join('map',
'Grass.csv')),
'objects': import_csv_layout(os.path.join('map',
'Objects.csv')),
'entities': import_csv_layout(os.path.join('map',
'Entities.csv'))
}
self.graphics = {
'grass': import_folder(os.path.join('graphics', 'grass')),
'objects': import_folder(os.path.join('graphics', 'objects'))
}
for style, layout in self.layouts.items():
for row_index, row in enumerate(layout):
for col_index, col in enumerate(row):
if int(col) != -1:
x = col_index * TILESIZE
y = row_index * TILESIZE
# Generate unpassable terrain
if style == 'boundary':
if col == '600':
self.map_edge = (x, y)
elif col != '700':
Terrain((x, y),
[self.obstacle_sprites],
'invisible')
elif col == '700' and self.n_players > 1:
print(f"Prison set at:{(x, y)}")
# # Generate grass
# if style == 'grass':
# random_grass_image = choice(self.graphics['grass'])
#
# Terrain((x, y), [
# self.visible_sprites,
# self.obstacle_sprites,
# self.attackable_sprites
# ],
# 'grass',
# random_grass_image)
#
# # Generate objects like trees and statues
# if style == 'objects':
# surface = self.graphics['objects'][int(col)]
# Terrain((x, y), [
# self.visible_sprites,
# self.obstacle_sprites
# ],
# 'object',
# surface)
# Generate observer, players and monsters
if style == 'entities':
# Generate player(s)
if col == '400':
self.possible_player_locations.append((x, y))
# Monster generation
elif col in ['390', '391', '392', '393']:
if col == '390':
monster_name = 'bamboo'
elif col == '391':
monster_name = 'spirit'
elif col == '392':
monster_name = 'raccoon'
elif col == '393':
monster_name = 'squid'
Enemy(name=monster_name,
position=(x, y),
groups=[self.visible_sprites,
self.attackable_sprites],
visible_sprites=self.visible_sprites,
obstacle_sprites=self.obstacle_sprites)
for player_id in range(self.n_players):
Player(
player_id,
'tank',
choice(self.possible_player_locations),
self.map_edge,
[self.visible_sprites],
self.obstacle_sprites,
self.visible_sprites,
self.attack_sprites,
self.attackable_sprites
)
def reset(self):
for grass in self.grass_sprites:
grass.kill()
for enemy in self.enemy_sprites:
enemy.kill()
for style, layout in self.layouts.items():
for row_index, row in enumerate(layout):
for col_index, col in enumerate(row):
if int(col) != -1:
x = col_index * TILESIZE
y = row_index * TILESIZE
# # Regenerate grass
# if style == 'grass':
# random_grass_image = choice(
# self.graphics['grass'])
#
# Terrain((x, y), [
# self.visible_sprites,
# self.obstacle_sprites,
# self.attackable_sprites
# ],
# 'grass',
# random_grass_image)
if style == 'entities':
if col in ['390', '391', '392', '393']:
if col == '390':
monster_name = 'bamboo'
elif col == '391':
monster_name = 'spirit'
elif col == '392':
monster_name = 'raccoon'
elif col == '393':
monster_name = 'squid'
Enemy(monster_name,
(x, y),
[self.visible_sprites,
self.attackable_sprites],
self.visible_sprites,
self.obstacle_sprites)
for player in self.player_sprites:
player.import_assets(
choice(self.possible_player_locations))
player.health\
= player.stats['health']
player.energy\
= player.stats['energy']
player.exp = 0
self.get_entities()
self.get_distance_direction()
self.dead_players = np.zeros(self.n_players)
self.done = False
def get_entities(self):
self.player_sprites = [sprite
for sprite in self.visible_sprites.sprites()
if sprite.sprite_type == 'player']
self.enemy_sprites = [sprite
for sprite in self.visible_sprites.sprites()
if sprite.sprite_type == 'enemy']
self.grass_sprites = [sprite
for sprite in self.visible_sprites.sprites()
if sprite.sprite_type == 'grass']
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:
if not player.is_dead():
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.attack_radius
and player.vulnerable):
player.health -= enemy.attack
player.vulnerable = False
player.hurt_time = pygame.time.get_ticks()
def toggle_pause(self):
self.paused = not self.paused
def run(self):
# Draw the game
self.visible_sprites.custom_draw()
self.ui.display()
if not self.paused:
# Update the game
for player in self.player_sprites:
if player.health > 0:
player.attack_logic()
self.get_entities()
self.get_distance_direction()
self.visible_sprites.update()
self.apply_damage_to_player()
else:
debug('PAUSED')
for player in self.player_sprites:
if player.is_dead():
print(f"\nPlayer {player.player_id} is dead\n")
self.dead_players[player.player_id] = player.is_dead()
self.done = True if (self.dead_players.all() == 1
or self.enemy_sprites == []) else False