NotQuiteParadise2

Source code for nqp.world.view

from __future__ import annotations

from typing import Optional, TYPE_CHECKING

import pygame

from nqp.core import systems
from nqp.world_elements.camera import Camera

if TYPE_CHECKING:
    from nqp.core.game import Game
    from nqp.world.model import WorldModel


__all__ = ["WorldView"]


[docs]class WorldView: """ Render Terrain and game entities Attributes: camera: Used to show portions of the game world * Do not modify the state of the game, entities, terrain, etc. * Only draw the state of the game, nothing else The view should query the model or controller and make changes based on that info. The view should not collect input from the user. """
[docs] def __init__(self, game: Game, model: WorldModel): self._game = game self._model = model self._has_centered_camera: bool = False # interface self.camera = Camera(game.window.base_resolution) self.debug_pathfinding: bool = False self.clamp_primary_terrain: bool = True
[docs] def update(self, delta_time: float): self._update_camera(delta_time)
[docs] def draw(self, surface: pygame.Surface): if self.clamp_primary_terrain: self.camera.clamp(self._model.boundaries) else: next_boundaries = self._model.next_boundaries if next_boundaries.contains(self.camera.get_rect()): self.camera.clamp(next_boundaries) else: self.camera.clamp(self._model.total_boundaries) _surface = None if self.camera.zoom != 0.0: _surface = surface area = self.camera.get_rect() surface = pygame.Surface(area.size) offset = self.camera.render_offset() self._model.terrain.draw(surface, offset) if not self.clamp_primary_terrain: next_offset = pygame.Vector2(offset.x + self._model.terrain.boundaries.width, offset.y + 0) self._model.next_terrain.draw(surface, next_offset) self._draw_units(surface, offset) self._model.projectiles.draw(surface, offset) self._model.particles.draw(surface, offset) if self.debug_pathfinding: self._draw_path_debug(surface) if _surface is not None: pygame.transform.scale(surface, _surface.get_size(), _surface)
[docs] def reset_camera(self): self._has_centered_camera = False self._update_camera(0)
def _update_camera(self, delta_time: float): """ Update the camera's position to follow the player's Units """ target_pos = self.get_team_center("player") if target_pos: self.camera.set_target_position(target_pos) self.camera.update(delta_time) # prevent camera from panning from 0,0 if not self._has_centered_camera: self.camera.reset_movement() self._has_centered_camera = True def _draw_units(self, surface: pygame.Surface, offset: pygame.Vector2): units = self._model.get_all_units() systems.draw_entities(surface, shift=offset) # # organize entities for layered rendering # entity_list = [] # for unit in units: # for entity in unit.entities + unit.dead_entities: # entity_list.append((entity.pos[1] + entity.img.get_height() // 2, len(entity_list), entity)) # # entity_list.sort() # # for entity in entity_list: # entity[2].draw(surface, shift=offset) for unit in units: if unit.team == "player": unit.draw_banner(surface, offset) if unit.is_selected: unit.draw_border(surface, offset) def _draw_path_debug(self, surface: pygame.Surface): """ Draw lines to indicate the pathfinding """ # FIXME - update to align to ecs for entity in self._model.get_all_entities(): if entity._parent_unit.default_behaviour != "swarm": if entity.behaviour.current_path and len(entity.behaviour.current_path): points = [ (p[0] + self.camera.render_offset()[0], p[1] + self.camera.render_offset()[1]) for p in ([entity.pos] + entity.behaviour.current_path) ] pygame.draw.lines(surface, (255, 0, 0), False, points)
[docs] def get_team_center(self, team) -> Optional[pygame.Vector2]: """ Get centre coordinates for the team """ count = 0 pos_totals = pygame.Vector2() for unit in self._model.get_all_units(): if unit.team == team: pos_totals += unit.pos count += 1 if count: return pygame.Vector2(pos_totals / count) else: return None
[docs] def view_to_point(self, point: pygame.Vector2): """ Return map pixel coords under the point * Point must be relative to the topleft corner of the view """ offset = self.camera.render_offset() return pygame.Vector2(point) - offset