pyglet-desper 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Francesco Mistri
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.1
2
+ Name: pyglet-desper
3
+ Version: 0.10.0
4
+ Summary: Extension package for desper and pyglet interoperation
5
+ Home-page: https://github.com/Ball-Man/pyglet-desper
6
+ Author: Francesco Mistri
7
+ Author-email: franc.mistri@gmail.com
8
+ License: MIT
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Classifier: Topic :: Games/Entertainment
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: desper>=1.1.1
16
+ Requires-Dist: pyglet<2.1,>=2.0.0
17
+
18
+ ![desper logo](https://github.com/Ball-Man/pyglet-desper/blob/master/assets/desper-logo-raw.png?raw=true)
19
+
20
+ # Desper + Pyglet interoperation
21
+ Combine resource and logic management of [desper](https://github.com/Ball-Man/desper]) with [pyglet](https://github.com/pyglet/pyglet)'s rendering and media.
22
+
23
+ ## Installation
24
+ Simple installation from PyPi (recommended):
25
+ ```
26
+ pip install pyglet-desper
27
+ ```
28
+ Or installation from master branch:
29
+ ```
30
+ git clone https://github.com/Ball-Man/pyglet-desper
31
+ cd pyglet-desper
32
+ pip install .
33
+ ```
34
+
35
+
36
+ ## Project status
37
+ Docs and a user guide are in the making.
@@ -0,0 +1,20 @@
1
+ ![desper logo](https://github.com/Ball-Man/pyglet-desper/blob/master/assets/desper-logo-raw.png?raw=true)
2
+
3
+ # Desper + Pyglet interoperation
4
+ Combine resource and logic management of [desper](https://github.com/Ball-Man/desper]) with [pyglet](https://github.com/pyglet/pyglet)'s rendering and media.
5
+
6
+ ## Installation
7
+ Simple installation from PyPi (recommended):
8
+ ```
9
+ pip install pyglet-desper
10
+ ```
11
+ Or installation from master branch:
12
+ ```
13
+ git clone https://github.com/Ball-Man/pyglet-desper
14
+ cd pyglet-desper
15
+ pip install .
16
+ ```
17
+
18
+
19
+ ## Project status
20
+ Docs and a user guide are in the making.
@@ -0,0 +1,3 @@
1
+ from .loop import * # NOQA
2
+ from .logic import * # NOQA
3
+ from .model import * # NOQA
@@ -0,0 +1,279 @@
1
+ import math
2
+ from typing import Optional
3
+
4
+ import desper
5
+ import pyglet
6
+ from pyglet.gl import GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
7
+
8
+ from .sync import * # NOQA
9
+
10
+ ON_CAMERA_DRAW_EVENT_NAME = 'on_camera_draw'
11
+
12
+
13
+ @desper.event_handler('on_switch_in', 'on_switch_out', 'on_add')
14
+ class Sprite(pyglet.sprite.Sprite):
15
+ """Specialized sprite for better integration into desper.
16
+
17
+ In particular, it listens to some events in order to schedule
18
+ animations correctly. See module :mod:`pyglet.sprite` to know
19
+ more about sprites.
20
+
21
+ This assumes that the default event workflow is being followed.
22
+ That is: world dispatching is disabled after creation and
23
+ enabled just when it is used as current world (i.e. with
24
+ :func:`desper.switch`).
25
+ """
26
+
27
+ def __init__(self,
28
+ img, x=0, y=0, z=0,
29
+ blend_src=GL_SRC_ALPHA,
30
+ blend_dest=GL_ONE_MINUS_SRC_ALPHA,
31
+ batch=None,
32
+ group=None,
33
+ subpixel=False):
34
+ super().__init__(img, x, y, z, blend_src, blend_dest, batch, group,
35
+ subpixel)
36
+ # Pause at creation to prevent global clock from scheduling it
37
+ if self._animation is not None:
38
+ self.paused = True
39
+
40
+ __init__.__doc__ = pyglet.sprite.Sprite.__init__.__doc__
41
+
42
+ def on_add(self, entity, world: desper.World):
43
+ """Start animation."""
44
+ if self._animation is not None:
45
+ self.paused = False
46
+
47
+ def on_switch_in(self, world_from: desper.World, world_to: desper.World):
48
+ """Start animation."""
49
+ if self._animation is not None:
50
+ self.paused = False
51
+
52
+ def on_switch_out(self, world_from: desper.World, world_to: desper.World):
53
+ """Stop animation."""
54
+ if self._animation is not None:
55
+ self.paused = True
56
+
57
+
58
+ @desper.event_handler('on_switch_in', 'on_switch_out', 'on_add')
59
+ class AdvancedSprite(pyglet.sprite.AdvancedSprite):
60
+ """Specialized advanced sprite for better integration into desper.
61
+
62
+ Being an advanced sprite, it is possible to specify its shader
63
+ program at any time through the :attr:`program` attribute (see
64
+ :class:`pyglet.sprite.AdvancedSprite`).
65
+
66
+ In particular, it listens to some events in order to schedule
67
+ animations correctly. See module :mod:`pyglet.sprite` to know
68
+ more about sprites.
69
+
70
+ This assumes that the default event workflow is being followed.
71
+ That is: world dispatching is disabled after creation and
72
+ enabled just when it is used as current world (i.e. with
73
+ :func:`desper.switch`).
74
+ """
75
+
76
+ def __init__(self,
77
+ img, x=0, y=0, z=0,
78
+ blend_src=GL_SRC_ALPHA,
79
+ blend_dest=GL_ONE_MINUS_SRC_ALPHA,
80
+ batch=None,
81
+ group=None,
82
+ subpixel=False,
83
+ program=None):
84
+ super().__init__(img, x, y, z, blend_src, blend_dest, batch, group,
85
+ subpixel, program)
86
+ # Pause at creation to prevent global clock from scheduling it
87
+ if self._animation is not None:
88
+ self.paused = True
89
+
90
+ __init__.__doc__ = pyglet.sprite.Sprite.__init__.__doc__
91
+
92
+ def on_add(self, entity, world: desper.World):
93
+ """Start animation."""
94
+ if self._animation is not None:
95
+ self.paused = False
96
+
97
+ def on_switch_in(self, world_from: desper.World, world_to: desper.World):
98
+ """Start animation."""
99
+ if self._animation is not None:
100
+ self.paused = False
101
+
102
+ def on_switch_out(self, world_from: desper.World, world_to: desper.World):
103
+ """Stop animation."""
104
+ if self._animation is not None:
105
+ self.paused = True
106
+
107
+
108
+ @desper.event_handler(ON_CAMERA_DRAW_EVENT_NAME)
109
+ class Camera:
110
+ """Render content of a :class:`pyglet.graphics.Batch`.
111
+
112
+ Apply the given projection and viewport before rendering. If
113
+ omitted, projection and viewport will be set as window defaults
114
+ (from pyglet), that is:
115
+
116
+ - orthogonal projection that maps to the window pixel size, with
117
+ origin (0, 0) at the bottom-left corner
118
+ - viewport equal to: ``0, 0, window.width, window.height``
119
+
120
+ A projection matrix can be easily obtained through
121
+ :meth:`desper.math.Mat4.orthogonal_projection` (2D) or through
122
+ :meth:`desper.math.Mat4.perspective_projection` (3D).
123
+
124
+ Viewport can be manually constructed and shall be a tuple in the
125
+ form ``(x, y, width, height)`` (:class:`desper.math.Vec4` is
126
+ supported).
127
+
128
+ A :class:`pyglet.window.Window` can be specified and shall be taken
129
+ as target of these transformations. In case of single window
130
+ applications this is unnecessary and the main window will be
131
+ automatically retrieven.
132
+ """
133
+
134
+ def __init__(self, batch: pyglet.graphics.Batch,
135
+ projection: Optional[desper.math.Mat4] = None,
136
+ viewport: Optional[tuple[int, int, int, int]] = None,
137
+ window: Optional[pyglet.window.Window] = None):
138
+ self.batch = batch
139
+
140
+ self.window: pyglet.window.Window = window
141
+ if window is None:
142
+ assert len(pyglet.app.windows), (
143
+ 'Unable to find an open window')
144
+ self.window = next(iter(pyglet.app.windows))
145
+
146
+ self.projection: desper.math.Mat4 = projection
147
+ if projection is None:
148
+ self.projection = self.window.projection
149
+
150
+ self.viewport: tuple[int, int, int, int] = viewport
151
+ if viewport is None:
152
+ self.viewport = self.window.viewport
153
+
154
+ # View transformation matrix
155
+ self.view = desper.math.Mat4()
156
+
157
+ def on_camera_draw(self):
158
+ """Event handler: apply projection, view and viewport, render."""
159
+ self.window.projection = self.projection
160
+ self.window.viewport = self.viewport
161
+ self.window.view = self.view
162
+
163
+ self.batch.draw()
164
+
165
+
166
+ @desper.event_handler('on_draw')
167
+ class CameraProcessor(desper.Processor):
168
+ """Render all cameras (:class:`Camera`).
169
+
170
+ Despite being a :class:`desper.Processor` subclass, no action
171
+ is done during :meth:`process`. The possibility to add it as a
172
+ processor in a :class:`World` is pure convenience, but adding it
173
+ as component in an entity (any entity) works just fine.
174
+
175
+ All the logic take place in the
176
+ :meth:`on_draw` method, which is a handler for the homonymous pyglet
177
+ connected event.
178
+
179
+ Rendering is done by dispatchment of
180
+ :attr:`ON_CAMERA_DRAW_EVENT_NAME` event. :class:`Camera` and
181
+ eventual custom objects handle this event and render accordingly.
182
+
183
+ A :class:`pyglet.window.Window` can be specified and shall be taken
184
+ as target of these transformations. In case of single window
185
+ applications this is unnecessary and the main window will be
186
+ automatically retrieven.
187
+ """
188
+
189
+ def __init__(self, window: Optional[pyglet.window.Window] = None):
190
+ self.window = window
191
+ if window is None:
192
+ assert len(pyglet.app.windows), (
193
+ 'Unable to find an open window')
194
+ self.window = next(iter(pyglet.app.windows))
195
+
196
+ def on_draw(self):
197
+ """Event handler: clear window and render all cameras.
198
+
199
+ Rendering is done by dispatchment of
200
+ :attr:`ON_CAMERA_DRAW_EVENT_NAME`.
201
+ """
202
+ self.window.clear()
203
+ self.world.dispatch(ON_CAMERA_DRAW_EVENT_NAME)
204
+
205
+ def process(self, dt):
206
+ """No implementation needed."""
207
+ pass
208
+
209
+
210
+ @desper.event_handler(desper.ON_POSITION_CHANGE_EVENT_NAME,
211
+ desper.ON_ROTATION_CHANGE_EVENT_NAME,
212
+ desper.ON_SCALE_CHANGE_EVENT_NAME)
213
+ class CameraTransform2D(desper.Controller):
214
+ """Synchronize :class:`Camera` with :class:`desper.Transform2D`.
215
+
216
+ A :class:`Camera`s internal :attr:`Camera.view` matrix is updated
217
+ based on the entity's :class:`desper.Transform2D`.
218
+ Requires to be in the same desper entity of both the camera and the
219
+ transform component.
220
+ """
221
+ transform: desper.Transform2D = desper.ComponentReference(
222
+ desper.Transform2D)
223
+ camera: Camera = desper.ComponentReference(Camera)
224
+
225
+ # Cached matrices for faster recalculations
226
+ _translation_matrix = desper.math.Mat4()
227
+ _rotation_matrix = desper.math.Mat4()
228
+ _scale_matrix = desper.math.Mat4()
229
+
230
+ def on_add(self, entity, world):
231
+ """Setup transform event handling."""
232
+ super().on_add(entity, world)
233
+
234
+ assert self.transform is not None and self.camera is not None, (
235
+ 'Both a Transform component and a Camera component '
236
+ 'are required to be in the same entity in order for '
237
+ f'{type(self)} to work.')
238
+
239
+ transform = self.transform
240
+ transform.add_handler(self)
241
+
242
+ self._translation_matrix = desper.math.Mat4.from_translation(
243
+ (*-transform.position, 0.))
244
+ self._rotation_matrix = desper.math.Mat4.from_rotation(
245
+ math.radians(transform.rotation), (0., 0., 1.))
246
+ self._scale_matrix = desper.math.Mat4.from_scale(
247
+ (*transform.scale, 1.))
248
+
249
+ self.camera.view = self.get_view_matrix()
250
+
251
+ def get_view_matrix(self) -> desper.math.Mat4:
252
+ """Compute view matrix.
253
+
254
+ Each query computes the matrix product between rotation,
255
+ translation and scale matrix.
256
+ """
257
+ return (self._scale_matrix @ self._translation_matrix
258
+ @ self._rotation_matrix)
259
+
260
+ def on_position_change(self, new_position: desper.math.Vec2):
261
+ """Event handler: update translation matrix and camera."""
262
+ self._translation_matrix = desper.math.Mat4.from_translation(
263
+ (*-new_position, 0.))
264
+
265
+ self.camera.view = self.get_view_matrix()
266
+
267
+ def on_rotation_change(self, new_rotation: float):
268
+ """Event handler: update rotation matrix and camera."""
269
+ self._rotation_matrix = desper.math.Mat4.from_rotation(
270
+ math.radians(new_rotation), (0., 0., 1.))
271
+
272
+ self.camera.view = self.get_view_matrix()
273
+
274
+ def on_scale_change(self, new_scale: desper.math.Vec2):
275
+ """Event handler: update scale matrix and camera."""
276
+ self._scale_matrix = desper.math.Mat4.from_scale(
277
+ (*new_scale, 1.))
278
+
279
+ self.camera.view = self.get_view_matrix()
@@ -0,0 +1,293 @@
1
+ """Synchronize pyglet graphics with desper ``Transform`` components.
2
+
3
+ High level graphic abstractions in pyglet (e.g. ``Sprite``) make use
4
+ of specific properties to handle and transform vertices. Most commonly,
5
+ positional properties (``Sprite.x``, ``Sprite.y``, etc.).
6
+ Due to the variety of existing graphical classes, the risk in handling
7
+ these properties directly is the injection in the project's
8
+ structure of strong dependencies based on pyglet objects and types.
9
+
10
+ To prevent this, a connection (or synchronization) between pyglet
11
+ classes and :class:`desper.Transform2D` is proposed (as pyglet
12
+ abstractions are mostly 2D, 3D support will be discussed in the future).
13
+ """
14
+ import desper
15
+ import pyglet
16
+
17
+
18
+ @desper.event_handler(desper.ON_REMOVE_EVENT_NAME)
19
+ class GraphicSync2D(desper.Controller):
20
+ """Base class for pyglet graphical components synchronization.
21
+
22
+ It encapsules management of position, rotation and scale by using
23
+ the most common related pyglet properites, synchronizing them
24
+ with the :class:`desper.Transform2D`. In particular:
25
+
26
+ - ``x`` and ``y`` for updating position.
27
+ - ``rotation`` for updating rotation.
28
+ - ``scale_x`` and ``scale_y`` for updating scale.
29
+
30
+ Even though all these interactions are defined, they are not
31
+ enabled. In fact, this component does nothing on its own, but
32
+ defines base behaviours that can be exploited by specialized
33
+ subclasses. This is done since not all the graphical components
34
+ support the same transformations. Actually, most of them only
35
+ support repositioning with ``x`` and ``y``, or with
36
+ the ``position`` tuple.
37
+
38
+ In particular, to enable a connection
39
+ with :class:`desper.Transform2D` it is advisable to subclass this
40
+ component and apply to it the :func:`desper.event_handler`
41
+ decorator, enabling the desired event connections (any of
42
+ :attr:`desper.ON_POSITION_CHANGE_EVENT_NAME`,
43
+ :attr:`desper.ON_ROTATION_CHANGE_EVENT_NAME`,
44
+ :attr:`desper.ON_SCALE_CHANGE_EVENT_NAME`, i.e.
45
+ ``'on_position_change'``, ``'on_rotation_change'``,
46
+ ``'on_scale_change'``). Override homonymous methods to define
47
+ custom behaviour.
48
+
49
+ Moreover, the :attr:`desper.ON_REMOVE_EVENT_NAME`
50
+ (i.e. ``'on_remove'``) event is automatically handled, calling on
51
+ the referred graphical component the :func:`delete` method
52
+ (e.g. :meth:`pyglet.Sprite.delete`), which is fundamental to
53
+ correctly delete vertices of graphical components when removed in
54
+ real time.
55
+ """
56
+ deleted = False
57
+
58
+ def __init__(self, component_type: type):
59
+ self.component_type = component_type
60
+
61
+ def on_add(self, entity, world: desper.World):
62
+ """Subscribe to :class:`desper.Transform2D` for events."""
63
+ super().on_add(entity, world)
64
+
65
+ transform = world.get_component(entity, desper.Transform2D)
66
+ assert transform is not None, (
67
+ 'A Transform2D component must be added first '
68
+ f'for {self.__class__} to work')
69
+ transform.add_handler(self)
70
+
71
+ # Apply immediately supported transformations
72
+ if desper.ON_POSITION_CHANGE_EVENT_NAME in self.__events__:
73
+ self.on_position_change(transform.position)
74
+
75
+ if desper.ON_ROTATION_CHANGE_EVENT_NAME in self.__events__:
76
+ self.on_rotation_change(transform.rotation)
77
+
78
+ if desper.ON_SCALE_CHANGE_EVENT_NAME in self.__events__:
79
+ self.on_scale_change(transform.scale)
80
+
81
+ def on_remove(self, entity, world: desper.World):
82
+ """Clear vertices from memory."""
83
+ if not self.deleted:
84
+ self.deleted = True
85
+ self.get_component(self.component_type).delete()
86
+
87
+ def on_position_change(self, new_position: desper.math.Vec2):
88
+ """Event handler: update graphical component position."""
89
+ self.get_component(self.component_type).position = new_position
90
+
91
+ def on_rotation_change(self, new_rotation: float):
92
+ """Event handler: update graphical component rotation."""
93
+ self.get_component(self.component_type).rotation = new_rotation
94
+
95
+ def on_scale_change(self, new_scale: desper.math.Vec2):
96
+ """Event handler: update graphical component's scale.
97
+
98
+ Possibly only supported by :class:`pyglet.sprite.Sprite`.
99
+ """
100
+ self.get_component(self.component_type).update(scale_x=new_scale[0],
101
+ scale_y=new_scale[1])
102
+
103
+
104
+ @desper.event_handler(desper.ON_POSITION_CHANGE_EVENT_NAME,
105
+ desper.ON_ROTATION_CHANGE_EVENT_NAME,
106
+ desper.ON_SCALE_CHANGE_EVENT_NAME)
107
+ class SpriteSync(GraphicSync2D):
108
+ """Synchronize :class:`desper.Transform2D` with pyglet ``Sprite``.
109
+
110
+ Handles all transformation events.
111
+
112
+ The :attr:`desper.ON_REMOVE_EVENT_NAME`
113
+ (i.e. ``'on_remove'``) event is automatically handled, calling on
114
+ the referred ``Sprite`` component the :func:`delete` method,
115
+ which is fundamental to correctly delete vertices of graphical
116
+ components when removed in real time.
117
+
118
+ This also means that ideally a ``Sprite`` instance and its
119
+ associated ``SpriteSync`` shall be added, removed from the world in
120
+ an entangled fashion.
121
+
122
+ Target class (``component_type``) defaults to
123
+ :class:`pyglet.sprite.Sprite`, but can be specialized to get
124
+ extra performance during component resolution (e.g. by specifying
125
+ :class:`pyglet-desper.Sprite`).
126
+
127
+ See :class:`GraphicSync2D` for more info.
128
+ """
129
+
130
+ def __init__(self, component_type: type = pyglet.sprite.Sprite):
131
+ super().__init__(component_type)
132
+
133
+ def on_add(self, entity, world):
134
+ """Custom handler for better performance."""
135
+ self.entity = entity
136
+ self.world = world
137
+
138
+ transform = world.get_component(entity, desper.Transform2D)
139
+ assert transform is not None, (
140
+ 'A Transform2D component must be added first '
141
+ f'for {self.__class__} to work')
142
+ transform.add_handler(self)
143
+
144
+ # Apply immediately supported transformations
145
+ # Stack them and apply in one go for better performance
146
+ transformations = {}
147
+
148
+ transformations['x'] = transform.position[0]
149
+ transformations['y'] = transform.position[1]
150
+
151
+ transformations['rotation'] = transform.rotation
152
+
153
+ transformations['scale_x'] = transform.scale[0]
154
+ transformations['scale_y'] = transform.scale[1]
155
+
156
+ self.get_component(self.component_type).update(**transformations)
157
+
158
+ def on_position_change(self, new_position: desper.math.Vec2):
159
+ """Event handler: update graphical component position."""
160
+ self.get_component(self.component_type).position = (*new_position, 0.)
161
+
162
+
163
+ @desper.event_handler(desper.ON_POSITION_CHANGE_EVENT_NAME)
164
+ class PositionSync2D(GraphicSync2D):
165
+ """Synchronize :class:`desper.Transform2D` position with graphics.
166
+
167
+ Handles the :attr:`desper.ON_POSITION_CHANGE_EVENT_NAME` event.
168
+
169
+ The :attr:`desper.ON_REMOVE_EVENT_NAME`
170
+ (i.e. ``'on_remove'``) event is automatically handled, calling on
171
+ the referred graphical component the :func:`delete` method,
172
+ which is fundamental to correctly delete vertices of graphical
173
+ components when removed in real time.
174
+
175
+ This also means that ideally a graphical instance and its
176
+ associated ``PositionSync2D`` shall be added, removed from the world
177
+ in an entangled fashion.
178
+
179
+ See :class:`GraphicSync2D` for more info.
180
+ """
181
+
182
+
183
+ @desper.event_handler(desper.ON_POSITION_CHANGE_EVENT_NAME,
184
+ desper.ON_ROTATION_CHANGE_EVENT_NAME)
185
+ class PositionRotationSync2D(GraphicSync2D):
186
+ """Same as :class:`PositionSync2D` but also synchronizes rotation.
187
+
188
+ See :class:`PositionSync2D`.
189
+ """
190
+
191
+
192
+ def arc_sync_component() -> PositionRotationSync2D:
193
+ """Get a sync component for :class:`pyglet.shapes.Arc`s.
194
+
195
+ See :class:`PositionRotationSync2D`.
196
+ """
197
+ return PositionRotationSync2D(pyglet.shapes.Arc)
198
+
199
+
200
+ def circle_sync_component() -> PositionSync2D:
201
+ """Get a sync component for :class:`pyglet.shapes.Circle`s.
202
+
203
+ See :class:`PositionSync2D`.
204
+ """
205
+ return PositionSync2D(pyglet.shapes.Circle)
206
+
207
+
208
+ def ellipse_sync_component() -> PositionRotationSync2D:
209
+ """Get a sync component for :class:`pyglet.shapes.Ellipse`s.
210
+
211
+ See :class:`PositionRotationSync2D`.
212
+ """
213
+ return PositionRotationSync2D(pyglet.shapes.Ellipse)
214
+
215
+
216
+ def sector_sync_component() -> PositionRotationSync2D:
217
+ """Get a sync component for :class:`pyglet.shapes.Sector`s.
218
+
219
+ See :class:`PositionRotationSync2D`.
220
+ """
221
+ return PositionRotationSync2D(pyglet.shapes.Sector)
222
+
223
+
224
+ def line_sync_component() -> PositionSync2D:
225
+ """Get a sync component for :class:`pyglet.shapes.Line`s.
226
+
227
+ See :class:`PositionSync2D`.
228
+ """
229
+ return PositionSync2D(pyglet.shapes.Line)
230
+
231
+
232
+ def rectangle_sync_component() -> PositionRotationSync2D:
233
+ """Get a sync component for :class:`pyglet.shapes.Rectangle`s.
234
+
235
+ See :class:`PositionRotationSync2D`.
236
+ """
237
+ return PositionRotationSync2D(pyglet.shapes.Rectangle)
238
+
239
+
240
+ def borderedrectangle_sync_component() -> PositionRotationSync2D:
241
+ """Get a sync component for :class:`pyglet.shapes.BorderedRectangle`s.
242
+
243
+ See :class:`PositionRotationSync2D`.
244
+ """
245
+ return PositionRotationSync2D(pyglet.shapes.BorderedRectangle)
246
+
247
+
248
+ def triangle_sync_component() -> PositionSync2D:
249
+ """Get a sync component for :class:`pyglet.shapes.Triangle`s.
250
+
251
+ See :class:`PositionSync2D`.
252
+ """
253
+ return PositionSync2D(pyglet.shapes.Triangle)
254
+
255
+
256
+ def star_sync_component() -> PositionRotationSync2D:
257
+ """Get a sync component for :class:`pyglet.shapes.Star`s.
258
+
259
+ See :class:`PositionRotationSync2D`.
260
+ """
261
+ return PositionRotationSync2D(pyglet.shapes.Star)
262
+
263
+
264
+ def polygon_sync_component() -> PositionRotationSync2D:
265
+ """Get a sync component for :class:`pyglet.shapes.Polygon`s.
266
+
267
+ See :class:`PositionRotationSync2D`.
268
+ """
269
+ return PositionRotationSync2D(pyglet.shapes.Polygon)
270
+
271
+
272
+ def htmllabel_sync_component() -> PositionRotationSync2D:
273
+ """Get a sync component for :class:`pyglet.text.HTMLLabel`.
274
+
275
+ See :class:`PositionRotationSync2D`.
276
+ """
277
+ return PositionRotationSync2D(pyglet.text.HTMLLabel)
278
+
279
+
280
+ def documentlabel_sync_component() -> PositionRotationSync2D:
281
+ """Get a sync component for :class:`pyglet.text.DocumentLabel`.
282
+
283
+ See :class:`PositionRotationSync2D`.
284
+ """
285
+ return PositionRotationSync2D(pyglet.text.DocumentLabel)
286
+
287
+
288
+ def label_sync_component() -> PositionRotationSync2D:
289
+ """Get a sync component for :class:`pyglet.text.Label`.
290
+
291
+ See :class:`PositionRotationSync2D`.
292
+ """
293
+ return PositionRotationSync2D(pyglet.text.Label)