221 lines
5.4 KiB
Python
221 lines
5.4 KiB
Python
|
|
|
|
import pygame
|
|
|
|
from typing import List, Dict
|
|
|
|
|
|
|
|
class RenderEntities:
|
|
|
|
def __init__(self, tile_size: int = 64):
|
|
|
|
self.tile_size = tile_size
|
|
|
|
self.entity_sprites = {}
|
|
|
|
self.animations = {}
|
|
|
|
|
|
|
|
def draw_entities(self, surface: pygame.Surface, entities: List[Dict], camera: Dict) -> None:
|
|
|
|
if not entities:
|
|
|
|
return
|
|
|
|
|
|
|
|
camera_x = camera.get('x', 0)
|
|
|
|
camera_y = camera.get('y', 0)
|
|
|
|
zoom = camera.get('zoom', 1.0)
|
|
|
|
|
|
|
|
for entity in entities:
|
|
|
|
if 'x' in entity and 'y' in entity:
|
|
|
|
screen_x = (entity['x'] - camera_x) * zoom
|
|
|
|
screen_y = (entity['y'] - camera_y) * zoom
|
|
|
|
|
|
|
|
sprite = self._get_entity_sprite(entity)
|
|
|
|
if sprite:
|
|
|
|
scaled_width = int(sprite.get_width() * zoom)
|
|
|
|
scaled_height = int(sprite.get_height() * zoom)
|
|
|
|
scaled_sprite = pygame.transform.scale(sprite, (scaled_width, scaled_height))
|
|
|
|
surface.blit(scaled_sprite, (screen_x - scaled_width // 2, screen_y - scaled_height // 2))
|
|
|
|
|
|
|
|
self._draw_health_bar(surface, entity, screen_x, screen_y, scaled_width if 'sprite' in locals() else self.tile_size, zoom)
|
|
|
|
self._draw_selection(surface, entity, screen_x, screen_y, scaled_width if 'sprite' in locals() else self.tile_size, zoom)
|
|
|
|
|
|
|
|
def animate_entity(self, entity: Dict, dt: float) -> None:
|
|
|
|
entity_id = entity.get('id')
|
|
|
|
if entity_id not in self.animations:
|
|
|
|
self.animations[entity_id] = {'frame': 0, 'time': 0}
|
|
|
|
|
|
|
|
animation = self.animations[entity_id]
|
|
|
|
animation['time'] += dt
|
|
|
|
|
|
|
|
if animation['time'] >= 0.1:
|
|
|
|
animation['frame'] = (animation['frame'] + 1) % 4
|
|
|
|
animation['time'] = 0
|
|
|
|
|
|
|
|
def _get_entity_sprite(self, entity: Dict) -> pygame.Surface:
|
|
|
|
entity_type = entity.get('type')
|
|
|
|
entity_name = entity.get('name', '').lower()
|
|
|
|
|
|
|
|
if entity_id := entity.get('id'):
|
|
|
|
self.animate_entity(entity, 0.016)
|
|
|
|
frame = self.animations[entity_id]['frame']
|
|
|
|
else:
|
|
|
|
frame = 0
|
|
|
|
|
|
|
|
sprite_key = f"{entity_type}_{entity_name}_{frame}"
|
|
|
|
|
|
|
|
if sprite_key not in self.entity_sprites:
|
|
|
|
self.entity_sprites[sprite_key] = self._create_entity_sprite(entity, frame)
|
|
|
|
|
|
|
|
return self.entity_sprites[sprite_key]
|
|
|
|
|
|
|
|
def _create_entity_sprite(self, entity: Dict, frame: int) -> pygame.Surface:
|
|
|
|
entity_type = entity.get('type')
|
|
|
|
size = self.tile_size
|
|
|
|
|
|
|
|
if entity_type == 'unit':
|
|
|
|
color = (0, 0, 255) if entity.get('owner') == 'player' else (255, 0, 0)
|
|
|
|
surface = pygame.Surface((size // 2, size // 2), pygame.SRCALPHA)
|
|
|
|
pygame.draw.circle(surface, color, (size // 4, size // 4), size // 4)
|
|
|
|
if frame % 2 == 0:
|
|
|
|
pygame.draw.circle(surface, (255, 255, 255), (size // 4, size // 4), size // 8)
|
|
|
|
|
|
|
|
elif entity_type == 'building':
|
|
|
|
color = (0, 100, 200) if entity.get('owner') == 'player' else (200, 0, 0)
|
|
|
|
surface = pygame.Surface((size, size), pygame.SRCALPHA)
|
|
|
|
pygame.draw.rect(surface, color, (0, 0, size, size))
|
|
|
|
if not entity.get('completed', True):
|
|
|
|
progress = entity.get('build_progress', 0) / entity.get('build_time', 1)
|
|
|
|
pygame.draw.rect(surface, (100, 100, 100), (0, size * (1 - progress), size, size * progress))
|
|
|
|
|
|
|
|
elif entity_type == 'resource':
|
|
|
|
surface = pygame.Surface((size, size), pygame.SRCALPHA)
|
|
|
|
pygame.draw.circle(surface, (255, 255, 0), (size // 2, size // 2), size // 3)
|
|
|
|
|
|
|
|
else:
|
|
|
|
surface = pygame.Surface((size, size), pygame.SRCALPHA)
|
|
|
|
pygame.draw.rect(surface, (200, 200, 200), (0, 0, size, size))
|
|
|
|
|
|
|
|
return surface
|
|
|
|
|
|
|
|
def _draw_health_bar(self, surface: pygame.Surface, entity: Dict, x: float, y: float, width: int, zoom: float) -> None:
|
|
|
|
if 'health' in entity and 'max_health' in entity and entity['max_health'] > 0:
|
|
|
|
health_ratio = entity['health'] / entity['max_health']
|
|
|
|
bar_width = width
|
|
|
|
bar_height = max(4, int(6 * zoom))
|
|
|
|
bar_x = x - bar_width // 2
|
|
|
|
bar_y = y - width // 2 - bar_height - 2
|
|
|
|
|
|
|
|
background_rect = pygame.Rect(bar_x, bar_y, bar_width, bar_height)
|
|
|
|
health_rect = pygame.Rect(bar_x, bar_y, int(bar_width * health_ratio), bar_height)
|
|
|
|
|
|
|
|
pygame.draw.rect(surface, (255, 0, 0), background_rect)
|
|
|
|
pygame.draw.rect(surface, (0, 255, 0), health_rect)
|
|
|
|
|
|
|
|
def _draw_selection(self, surface: pygame.Surface, entity: Dict, x: float, y: float, width: int, zoom: float) -> None:
|
|
|
|
if entity.get('selected', False):
|
|
|
|
selection_size = width + int(10 * zoom)
|
|
|
|
selection_rect = pygame.Rect(x - selection_size // 2, y - selection_size // 2, selection_size, selection_size)
|
|
|
|
pygame.draw.rect(surface, (255, 255, 0), selection_rect, int(2 * zoom))
|
|
|