pyxora.camera

  1from .display import Display
  2from .wrapper.functions import vector
  3from .wrapper import Text,Image,Shape
  4
  5from math import log2
  6from typing import Tuple
  7
  8import pygame
  9
 10class Camera:
 11    """
 12    Camera class for the pyxora display environment.
 13    Handles position, zoom, and rendering of shapes, text, and images with camera-relative coordinates.
 14
 15    Note: Every Scene has a camera instance by default. You can create multiple instances but it's not recommended.
 16    """
 17
 18    def __init__(self) -> None:
 19        """Initialize the camera position, offset, zoom, and set initial zoom."""
 20        self._pos = vector(0, 0)
 21        self._offset = vector(0, 0)
 22        self._zoom_scale = 1
 23        self._zoom_factor = 0
 24        self._zoom_direction = 0
 25        self.__max_zoom_factor = 3
 26        self.zoom(1)
 27
 28    @property
 29    def surface(self) -> pygame.Surface:
 30        """Property to the current drawing surface."""
 31        return Display.surface
 32
 33    @property
 34    def position(self) -> pygame.math.Vector2:
 35        """Property to get a copy of the position of the camera."""
 36        return self._pos.copy()
 37
 38    @property
 39    def rect(self) -> pygame.Rect:
 40        """Property to get the camera's rectangle area as a pygame.Rect."""
 41        rect = pygame.Rect(self._pos + self._offset, Display._res)
 42        rect.width = int(rect.width / self.zoom_scale)
 43        rect.height = int(rect.height / self.zoom_scale)
 44        return rect
 45
 46    @property
 47    def zoom_scale(self) -> float:
 48        """Property to get the current zoom scale factor"""
 49        return self._zoom_scale
 50
 51    @property
 52    def zoom_factor(self) -> float:
 53        """Property to get the current log2 zoom factor"""
 54        return self._zoom_factor
 55
 56    @property
 57    def zoom_direction(self) -> float:
 58        """Property to get the current zoom direction."""
 59        return self._zoom_direction
 60
 61    @property
 62    def zoom_level(self) -> float:
 63        """Property to get the current zoom level."""
 64        if self.zoom_direction == 0 and self.zoom_factor == 0:
 65            return 1
 66        elif self.zoom_factor == 0:
 67            return 1
 68        elif self.zoom_factor >= 1:
 69            return self.zoom_factor + 1
 70        else:
 71            return self.zoom_factor - 1
 72
 73    def set_max_zoom(self, factor: float) -> None:
 74        """
 75        Set the maximum zoom factor for the camera.
 76
 77        Args:
 78            factor: The maximum zoom factor to set.
 79        """
 80        self.__max_zoom_factor = factor
 81
 82    def get_max_zoom(self) -> float:
 83        """
 84        Get the maximum zoom factor for the camera.
 85
 86        Returns:
 87            The maximum zoom factor.
 88        """
 89        return self.__max_zoom_factor
 90
 91    def is_visible(self, obj) -> bool:
 92        """
 93        Check if an object is at least partially visible on the screen (Requires object to have a rect attribute).
 94
 95        Args:
 96            obj: The object to check visibility for.
 97
 98        Returns:
 99            True if the object is visible, False otherwise.
100        """
101        return self.rect.colliderect(obj.rect)
102
103    def move(self, offset: Tuple[int | float, int | float] | pygame.math.Vector2) -> None:
104        """
105        Move the camera by a given offset (tuple or vector).
106
107        Args:
108            offset: The offset to move the camera by.
109        """
110        self._pos.x += offset[0]
111        self._pos.y += offset[1]
112
113    def move_at(self, new_pos: Tuple[int | float, int | float] | pygame.math.Vector2) -> None:
114        """
115        Move the camera to a specific position (centered).
116
117        Args:
118            new_pos: The new position to move the camera to.
119        """
120        self._pos.x = new_pos[0] + Display._res[0] / 2
121        self._pos.y = new_pos[1] + Display._res[1] / 2
122
123    def zoom(self, factor: int) -> None:
124        """
125        Zoom the camera by a given step, adjusting its scale.
126
127        Args:
128            factor: The zoom factor to apply.
129        """
130        if factor == 0:
131            return
132        factor = (factor + 1) if factor < 0 else (factor - 1)
133        scale = 2 ** (self.zoom_factor + factor)
134        self.zoom_at(scale)
135
136    def zoom_at(self, scale: float) -> None:
137        """
138        Set the camera zoom to a specific scale, centering the view.
139
140        Args:
141            scale: The scale to set the camera zoom to.
142        """
143        if not scale:
144            return
145        min_scale = 2 ** -self.__max_zoom_factor
146        max_scale = 2 ** self.__max_zoom_factor
147        scale = max(min_scale, min(max_scale, scale))
148        factor = log2(scale)
149        direction = factor - self._zoom_factor
150
151        # Center the camera based on the new zoom scale
152        sign = 1 if scale < 0 else -1
153        self._offset.x = 1 / scale * Display._res[0] / 2 * sign + Display._res[0] / 2
154        self._offset.y = 1 / scale * Display._res[1] / 2 * sign + Display._res[1] / 2
155
156        self._zoom_scale = scale
157        self._zoom_factor = factor
158        self._zoom_direction = direction
159
160    def draw_shape(self, Shape: Shape, fill: int = 0) -> None:
161        """Draw a shape on the camera's surface if it is visible."""
162        if not self.is_visible(Shape):
163            return
164
165        Shape._pos -= self._pos + self._offset
166        Shape._pos *= self._zoom_scale
167        Shape.draw(self.surface, fill, self._zoom_scale)
168        Shape._pos /= self._zoom_scale
169        Shape._pos += self._offset + self._pos
170
171    def draw_text(self, Txt: Text) -> None:
172        """Draw text on the camera's surface if it is visible."""
173        if not self.is_visible(Txt):
174            return
175
176        Txt._pos -= self._pos + self._offset
177        Txt._pos *= self._zoom_scale
178        Txt.draw(self.surface, self._zoom_scale)
179        Txt._pos /= self._zoom_scale
180        Txt._pos += self._offset + self._pos
181
182    def draw_image(self, Image: Image) -> None:
183        """Draw an image on the camera's surface if it is visible."""
184        if not self.is_visible(Image):
185            return
186
187        Image._pos -= self._pos + self._offset
188        Image._pos *= self._zoom_scale
189        Image.draw(self.surface, self._zoom_scale)
190        Image._pos /= self._zoom_scale
191        Image._pos += self._offset + self._pos
192
193    def _dynamic_zoom(self) -> None:
194        """Dynamically adjust the zoom based on the display's resolution."""
195        scale = min((Display._res[0] / Display._new_res[0]),(Display._res[1] / Display._new_res[1]))
196        self.zoom_at(scale)
class Camera:
 11class Camera:
 12    """
 13    Camera class for the pyxora display environment.
 14    Handles position, zoom, and rendering of shapes, text, and images with camera-relative coordinates.
 15
 16    Note: Every Scene has a camera instance by default. You can create multiple instances but it's not recommended.
 17    """
 18
 19    def __init__(self) -> None:
 20        """Initialize the camera position, offset, zoom, and set initial zoom."""
 21        self._pos = vector(0, 0)
 22        self._offset = vector(0, 0)
 23        self._zoom_scale = 1
 24        self._zoom_factor = 0
 25        self._zoom_direction = 0
 26        self.__max_zoom_factor = 3
 27        self.zoom(1)
 28
 29    @property
 30    def surface(self) -> pygame.Surface:
 31        """Property to the current drawing surface."""
 32        return Display.surface
 33
 34    @property
 35    def position(self) -> pygame.math.Vector2:
 36        """Property to get a copy of the position of the camera."""
 37        return self._pos.copy()
 38
 39    @property
 40    def rect(self) -> pygame.Rect:
 41        """Property to get the camera's rectangle area as a pygame.Rect."""
 42        rect = pygame.Rect(self._pos + self._offset, Display._res)
 43        rect.width = int(rect.width / self.zoom_scale)
 44        rect.height = int(rect.height / self.zoom_scale)
 45        return rect
 46
 47    @property
 48    def zoom_scale(self) -> float:
 49        """Property to get the current zoom scale factor"""
 50        return self._zoom_scale
 51
 52    @property
 53    def zoom_factor(self) -> float:
 54        """Property to get the current log2 zoom factor"""
 55        return self._zoom_factor
 56
 57    @property
 58    def zoom_direction(self) -> float:
 59        """Property to get the current zoom direction."""
 60        return self._zoom_direction
 61
 62    @property
 63    def zoom_level(self) -> float:
 64        """Property to get the current zoom level."""
 65        if self.zoom_direction == 0 and self.zoom_factor == 0:
 66            return 1
 67        elif self.zoom_factor == 0:
 68            return 1
 69        elif self.zoom_factor >= 1:
 70            return self.zoom_factor + 1
 71        else:
 72            return self.zoom_factor - 1
 73
 74    def set_max_zoom(self, factor: float) -> None:
 75        """
 76        Set the maximum zoom factor for the camera.
 77
 78        Args:
 79            factor: The maximum zoom factor to set.
 80        """
 81        self.__max_zoom_factor = factor
 82
 83    def get_max_zoom(self) -> float:
 84        """
 85        Get the maximum zoom factor for the camera.
 86
 87        Returns:
 88            The maximum zoom factor.
 89        """
 90        return self.__max_zoom_factor
 91
 92    def is_visible(self, obj) -> bool:
 93        """
 94        Check if an object is at least partially visible on the screen (Requires object to have a rect attribute).
 95
 96        Args:
 97            obj: The object to check visibility for.
 98
 99        Returns:
100            True if the object is visible, False otherwise.
101        """
102        return self.rect.colliderect(obj.rect)
103
104    def move(self, offset: Tuple[int | float, int | float] | pygame.math.Vector2) -> None:
105        """
106        Move the camera by a given offset (tuple or vector).
107
108        Args:
109            offset: The offset to move the camera by.
110        """
111        self._pos.x += offset[0]
112        self._pos.y += offset[1]
113
114    def move_at(self, new_pos: Tuple[int | float, int | float] | pygame.math.Vector2) -> None:
115        """
116        Move the camera to a specific position (centered).
117
118        Args:
119            new_pos: The new position to move the camera to.
120        """
121        self._pos.x = new_pos[0] + Display._res[0] / 2
122        self._pos.y = new_pos[1] + Display._res[1] / 2
123
124    def zoom(self, factor: int) -> None:
125        """
126        Zoom the camera by a given step, adjusting its scale.
127
128        Args:
129            factor: The zoom factor to apply.
130        """
131        if factor == 0:
132            return
133        factor = (factor + 1) if factor < 0 else (factor - 1)
134        scale = 2 ** (self.zoom_factor + factor)
135        self.zoom_at(scale)
136
137    def zoom_at(self, scale: float) -> None:
138        """
139        Set the camera zoom to a specific scale, centering the view.
140
141        Args:
142            scale: The scale to set the camera zoom to.
143        """
144        if not scale:
145            return
146        min_scale = 2 ** -self.__max_zoom_factor
147        max_scale = 2 ** self.__max_zoom_factor
148        scale = max(min_scale, min(max_scale, scale))
149        factor = log2(scale)
150        direction = factor - self._zoom_factor
151
152        # Center the camera based on the new zoom scale
153        sign = 1 if scale < 0 else -1
154        self._offset.x = 1 / scale * Display._res[0] / 2 * sign + Display._res[0] / 2
155        self._offset.y = 1 / scale * Display._res[1] / 2 * sign + Display._res[1] / 2
156
157        self._zoom_scale = scale
158        self._zoom_factor = factor
159        self._zoom_direction = direction
160
161    def draw_shape(self, Shape: Shape, fill: int = 0) -> None:
162        """Draw a shape on the camera's surface if it is visible."""
163        if not self.is_visible(Shape):
164            return
165
166        Shape._pos -= self._pos + self._offset
167        Shape._pos *= self._zoom_scale
168        Shape.draw(self.surface, fill, self._zoom_scale)
169        Shape._pos /= self._zoom_scale
170        Shape._pos += self._offset + self._pos
171
172    def draw_text(self, Txt: Text) -> None:
173        """Draw text on the camera's surface if it is visible."""
174        if not self.is_visible(Txt):
175            return
176
177        Txt._pos -= self._pos + self._offset
178        Txt._pos *= self._zoom_scale
179        Txt.draw(self.surface, self._zoom_scale)
180        Txt._pos /= self._zoom_scale
181        Txt._pos += self._offset + self._pos
182
183    def draw_image(self, Image: Image) -> None:
184        """Draw an image on the camera's surface if it is visible."""
185        if not self.is_visible(Image):
186            return
187
188        Image._pos -= self._pos + self._offset
189        Image._pos *= self._zoom_scale
190        Image.draw(self.surface, self._zoom_scale)
191        Image._pos /= self._zoom_scale
192        Image._pos += self._offset + self._pos
193
194    def _dynamic_zoom(self) -> None:
195        """Dynamically adjust the zoom based on the display's resolution."""
196        scale = min((Display._res[0] / Display._new_res[0]),(Display._res[1] / Display._new_res[1]))
197        self.zoom_at(scale)

Camera class for the pyxora display environment. Handles position, zoom, and rendering of shapes, text, and images with camera-relative coordinates.

Note: Every Scene has a camera instance by default. You can create multiple instances but it's not recommended.

Camera()
19    def __init__(self) -> None:
20        """Initialize the camera position, offset, zoom, and set initial zoom."""
21        self._pos = vector(0, 0)
22        self._offset = vector(0, 0)
23        self._zoom_scale = 1
24        self._zoom_factor = 0
25        self._zoom_direction = 0
26        self.__max_zoom_factor = 3
27        self.zoom(1)

Initialize the camera position, offset, zoom, and set initial zoom.

surface: pygame.surface.Surface
29    @property
30    def surface(self) -> pygame.Surface:
31        """Property to the current drawing surface."""
32        return Display.surface

Property to the current drawing surface.

position: pygame.math.Vector2
34    @property
35    def position(self) -> pygame.math.Vector2:
36        """Property to get a copy of the position of the camera."""
37        return self._pos.copy()

Property to get a copy of the position of the camera.

rect: pygame.rect.Rect
39    @property
40    def rect(self) -> pygame.Rect:
41        """Property to get the camera's rectangle area as a pygame.Rect."""
42        rect = pygame.Rect(self._pos + self._offset, Display._res)
43        rect.width = int(rect.width / self.zoom_scale)
44        rect.height = int(rect.height / self.zoom_scale)
45        return rect

Property to get the camera's rectangle area as a pygame.Rect.

zoom_scale: float
47    @property
48    def zoom_scale(self) -> float:
49        """Property to get the current zoom scale factor"""
50        return self._zoom_scale

Property to get the current zoom scale factor

zoom_factor: float
52    @property
53    def zoom_factor(self) -> float:
54        """Property to get the current log2 zoom factor"""
55        return self._zoom_factor

Property to get the current log2 zoom factor

zoom_direction: float
57    @property
58    def zoom_direction(self) -> float:
59        """Property to get the current zoom direction."""
60        return self._zoom_direction

Property to get the current zoom direction.

zoom_level: float
62    @property
63    def zoom_level(self) -> float:
64        """Property to get the current zoom level."""
65        if self.zoom_direction == 0 and self.zoom_factor == 0:
66            return 1
67        elif self.zoom_factor == 0:
68            return 1
69        elif self.zoom_factor >= 1:
70            return self.zoom_factor + 1
71        else:
72            return self.zoom_factor - 1

Property to get the current zoom level.

def set_max_zoom(self, factor: float) -> None:
74    def set_max_zoom(self, factor: float) -> None:
75        """
76        Set the maximum zoom factor for the camera.
77
78        Args:
79            factor: The maximum zoom factor to set.
80        """
81        self.__max_zoom_factor = factor

Set the maximum zoom factor for the camera.

Arguments:
  • factor: The maximum zoom factor to set.
def get_max_zoom(self) -> float:
83    def get_max_zoom(self) -> float:
84        """
85        Get the maximum zoom factor for the camera.
86
87        Returns:
88            The maximum zoom factor.
89        """
90        return self.__max_zoom_factor

Get the maximum zoom factor for the camera.

Returns:

The maximum zoom factor.

def is_visible(self, obj) -> bool:
 92    def is_visible(self, obj) -> bool:
 93        """
 94        Check if an object is at least partially visible on the screen (Requires object to have a rect attribute).
 95
 96        Args:
 97            obj: The object to check visibility for.
 98
 99        Returns:
100            True if the object is visible, False otherwise.
101        """
102        return self.rect.colliderect(obj.rect)

Check if an object is at least partially visible on the screen (Requires object to have a rect attribute).

Arguments:
  • obj: The object to check visibility for.
Returns:

True if the object is visible, False otherwise.

def move( self, offset: Union[Tuple[int | float, int | float], pygame.math.Vector2]) -> None:
104    def move(self, offset: Tuple[int | float, int | float] | pygame.math.Vector2) -> None:
105        """
106        Move the camera by a given offset (tuple or vector).
107
108        Args:
109            offset: The offset to move the camera by.
110        """
111        self._pos.x += offset[0]
112        self._pos.y += offset[1]

Move the camera by a given offset (tuple or vector).

Arguments:
  • offset: The offset to move the camera by.
def move_at( self, new_pos: Union[Tuple[int | float, int | float], pygame.math.Vector2]) -> None:
114    def move_at(self, new_pos: Tuple[int | float, int | float] | pygame.math.Vector2) -> None:
115        """
116        Move the camera to a specific position (centered).
117
118        Args:
119            new_pos: The new position to move the camera to.
120        """
121        self._pos.x = new_pos[0] + Display._res[0] / 2
122        self._pos.y = new_pos[1] + Display._res[1] / 2

Move the camera to a specific position (centered).

Arguments:
  • new_pos: The new position to move the camera to.
def zoom(self, factor: int) -> None:
124    def zoom(self, factor: int) -> None:
125        """
126        Zoom the camera by a given step, adjusting its scale.
127
128        Args:
129            factor: The zoom factor to apply.
130        """
131        if factor == 0:
132            return
133        factor = (factor + 1) if factor < 0 else (factor - 1)
134        scale = 2 ** (self.zoom_factor + factor)
135        self.zoom_at(scale)

Zoom the camera by a given step, adjusting its scale.

Arguments:
  • factor: The zoom factor to apply.
def zoom_at(self, scale: float) -> None:
137    def zoom_at(self, scale: float) -> None:
138        """
139        Set the camera zoom to a specific scale, centering the view.
140
141        Args:
142            scale: The scale to set the camera zoom to.
143        """
144        if not scale:
145            return
146        min_scale = 2 ** -self.__max_zoom_factor
147        max_scale = 2 ** self.__max_zoom_factor
148        scale = max(min_scale, min(max_scale, scale))
149        factor = log2(scale)
150        direction = factor - self._zoom_factor
151
152        # Center the camera based on the new zoom scale
153        sign = 1 if scale < 0 else -1
154        self._offset.x = 1 / scale * Display._res[0] / 2 * sign + Display._res[0] / 2
155        self._offset.y = 1 / scale * Display._res[1] / 2 * sign + Display._res[1] / 2
156
157        self._zoom_scale = scale
158        self._zoom_factor = factor
159        self._zoom_direction = direction

Set the camera zoom to a specific scale, centering the view.

Arguments:
  • scale: The scale to set the camera zoom to.
def draw_shape(self, Shape: pyxora.wrapper.shapes.Shape, fill: int = 0) -> None:
161    def draw_shape(self, Shape: Shape, fill: int = 0) -> None:
162        """Draw a shape on the camera's surface if it is visible."""
163        if not self.is_visible(Shape):
164            return
165
166        Shape._pos -= self._pos + self._offset
167        Shape._pos *= self._zoom_scale
168        Shape.draw(self.surface, fill, self._zoom_scale)
169        Shape._pos /= self._zoom_scale
170        Shape._pos += self._offset + self._pos

Draw a shape on the camera's surface if it is visible.

def draw_text(self, Txt: pyxora.wrapper.text.Text) -> None:
172    def draw_text(self, Txt: Text) -> None:
173        """Draw text on the camera's surface if it is visible."""
174        if not self.is_visible(Txt):
175            return
176
177        Txt._pos -= self._pos + self._offset
178        Txt._pos *= self._zoom_scale
179        Txt.draw(self.surface, self._zoom_scale)
180        Txt._pos /= self._zoom_scale
181        Txt._pos += self._offset + self._pos

Draw text on the camera's surface if it is visible.

def draw_image(self, Image: pyxora.wrapper.image.Image) -> None:
183    def draw_image(self, Image: Image) -> None:
184        """Draw an image on the camera's surface if it is visible."""
185        if not self.is_visible(Image):
186            return
187
188        Image._pos -= self._pos + self._offset
189        Image._pos *= self._zoom_scale
190        Image.draw(self.surface, self._zoom_scale)
191        Image._pos /= self._zoom_scale
192        Image._pos += self._offset + self._pos

Draw an image on the camera's surface if it is visible.