@@ -37,19 +37,103 @@ class PymunkException(Exception):
3737# Temp fix for https://github.com/pythonarcade/arcade/issues/2074
3838@copy_dunders_unimplemented
3939class PymunkPhysicsEngine :
40- """
41- Pymunk Physics Engine
40+ """An Arcade-specific adapter for Pymunk.
41+
42+ .. _Pymunk: https://www.pymunk.org/en/latest/index.html
43+ .. _Chipmunk2D: https://chipmunk-physics.net/
44+ .. _CONTRIBUTING.md: https://github.com/pythonarcade/arcade/blob/development/CONTRIBUTING.md
45+
46+ `Pymunk`_ is itself a Python adapter for the professional-grade
47+ `Chipmunk2D`_ engine. However, Arcade's ``PymunkPhysicsEngine``
48+ and its doc are currently in need of improvement.
49+
50+ .. note:: Arcade would welcome assistance with improving it.
51+
52+ If you are interested, please see Arcade's
53+ `CONTRIBUTING.md`_.
54+
55+ Args:
56+ gravity:
57+ The direction where gravity is pointing.
58+ See :py:attr:`pymunk.Space.gravity` to learn more.
59+ damping:
60+ The default velocity loss per tick across the
61+ :py:class:`~pymunk.Space` for all :py:attr:`DYNAMIC`
62+ objects.
63+
64+ * Override this for objects by passing different value
65+ :`add_sprite` or :py:meth:`add_spritelist`
66+ * See :py:attr:`pymunk.Space.damping` to learn more
67+
68+ maximum_incline_on_ground:
69+ The maximum incline the ground can have before
70+ :py:meth:`is_on_ground` returns ``False``.
71+
72+ * Defaults to ``0.708`` radians (a bit over 45 °)
73+ * Not a pymunk value, but an Arcade feature
4274
43- :param gravity: The direction where gravity is pointing
44- :param damping: The amount of speed which is kept to the next tick. A value of 1.0 means no speed loss,
45- while 0.9 has 10% loss of speed etc.
46- :param maximum_incline_on_ground: The maximum incline the ground can have, before is_on_ground() becomes False
47- default = 0.708 or a little bit over 45° angle
4875 """
4976
5077 DYNAMIC = pymunk .Body .DYNAMIC
78+ """A ``body_type`` for moving Pymunk-controlled objects.
79+
80+ An indirect approach is best for controlling the velocity and
81+ positioning of dynamic objects:
82+
83+ * :py:meth:`apply_force`
84+ * :py:meth:`apply_impulse`
85+
86+ .. warning:: Avoid setting velocity directly on dynamic objects!
87+
88+ If you need to set velocity directly, you may want to
89+ pass :py:attr:`KINEMATIC` as the ``body_type`` to
90+ :py:meth:`add_sprite` instead.
91+
92+ If you :py:class:`set_velocity` directly anyway, the
93+ following may occur:
94+
95+ #. Setting velocity approaches infinite acceleration
96+ #. ``f = m * a`` approaches ``f = m * infinity``
97+ #. Collisions go haywire
98+
99+ In some games, you may be able to find a way to harness this for
100+ comedic effect.
101+
102+ .. note:: This value is an alias of :py:attr:`pymunk.Body.DYNAMIC`.
103+
104+ Please see the Pymunk page linked above to learn more.
105+ """
51106 STATIC = pymunk .Body .STATIC
107+ """A ``body_type`` for objects which do not move.
108+
109+ This is best used for terrain or non-moving platforms.
110+
111+ .. note:: This value is an alias of :py:attr:`pymunk.Body.STATIC`.
112+
113+ Please see the Pymunk page linked above to learn more.
114+ """
52115 KINEMATIC = pymunk .Body .KINEMATIC
116+ """A ``body_type`` for objects controlled by your code or Arcade's.
117+
118+ When colliding, Kinematic objects:
119+
120+ * act as if they have infinite mass
121+ * prevent joined and touching objects from sleeping
122+
123+ This makes them excellent for game elements like moving platforms or
124+ hazards which move or crush game objects. You can control kinematic
125+ objects by setting their positions and velocities directly:
126+
127+ * :py:meth:`set_velocity`
128+ * :py:meth:`set_velocity_horizontal`
129+ * :py:meth:`set_velocity_vertical`
130+ * :py:meth:`set_position`
131+
132+
133+ .. note:: This value is an alias of :py:attr:`pymunk.Body.KINEMATIC`.
134+
135+ Please see the Pymunk page linked above to learn more.
136+ """
53137 MOMENT_INF = float ("inf" )
54138
55139 def __init__ (
@@ -67,7 +151,7 @@ def __init__(
67151 def add_sprite (
68152 self ,
69153 sprite : Sprite ,
70- mass : float = 1 ,
154+ mass : float = 1.0 ,
71155 friction : float = 0.2 ,
72156 elasticity : Optional [float ] = None ,
73157 moment_of_inertia : Optional [float ] = None , # correct spelling
@@ -80,23 +164,72 @@ def add_sprite(
80164 radius : float = 0 ,
81165 collision_type : Optional [str ] = "default" ,
82166 ):
83- """ Add a sprite to the physics engine.
84-
85- :param sprite: The sprite to add.
86- :param mass: The mass of the object. Defaults to 1.
87- :param friction: The friction the object has. Defaults to 0.2.
88- :param elasticity: How bouncy this object is. 0 is no bounce. Values of 1.0 and higher may behave badly.
89- :param moment_of_inertia: The moment of inertia, or force needed to change angular momentum. \
90- Providing infinite makes this object stuck in its rotation.
91- :param body_type: The type of the body. Defaults to Dynamic, meaning, the body can move, rotate etc. \
92- Providing STATIC makes it fixed to the world.
93- :param damping: See class docs.
94- :param gravity: See class docs.
95- :param max_velocity: The maximum velocity of the object.
96- :param max_horizontal_velocity: Maximum velocity on the x axis in pixels.
97- :param max_vertical_velocity: Maximum velocity on the y axis in pixels.
98- :param radius: Radius for the shape created for the sprite in pixels.
99- :param collision_type: Assign a name to the sprite, use this name when adding collision handler.
167+ """Add a sprite to the physics engine.
168+
169+ Args:
170+ sprite:
171+ A :py:class:`.Sprite` to add
172+ mass:
173+ The mass of the object (Defaults to ``1.0``).
174+ friction:
175+ How much the object resists sliding against surfaces:
176+
177+ .. list-table::
178+ :header-rows: 0
179+
180+ * - ``0.0``
181+ - Absolutely slippery with no resistance at all
182+ * - ``0.2``
183+ - Default (Waxed wood on very wet snow)
184+ * - ``friction > 1.0``
185+ - Very rough
186+
187+ *Higher values may not make a meaningful difference.*
188+
189+ See :py:attr:`pymunk.Shape.friction` to learn more.
190+
191+ elasticity:
192+ How bouncy the object is.
193+
194+ .. list-table::
195+ :header-rows: 0
196+
197+ * - ``0.0``
198+ - No bounce
199+ * - ``0.99``
200+ - Very bouncy
201+ * - ``elasticity >= 1.0``
202+ - May behave badly (breaks conservation of energy)
203+
204+ See :py:attr:`pymunk.Shape.elasticity` to learn more.
205+
206+ moment_of_inertia:
207+ How much force is needed to change the object's rotation (
208+ pass :py:attr:`MOMENT_INF` or ``float('inf')`` to "lock"
209+ its angle).
210+
211+ See :py:attr:`pymunk.Shape.moment_of_inertia` to learn more.
212+
213+ body_type:
214+ :py:attr:`DYNAMIC` (default), :py:attr:`KINEMATIC`, or
215+ :py:attr:`STATIC`.
216+ damping:
217+ Like air resistance. See the :py:class:`.PymunkPhysicsEngine`
218+ top-level doc.
219+ gravity:
220+ See the :py:class:`.PymunkPhysicsEngine` top-level doc.
221+ max_velocity:
222+ The maximum velocity of this object.
223+ max_horizontal_velocity:
224+ Clamp the velocity on the x axis to this.
225+ max_vertical_velocity:
226+ Clamp the velocity along the y axis to this.
227+ radius:
228+ The radius for the :py:class:`pymunk.Shape` created for
229+ the :py:class:`sprite <.Sprite>`.
230+ collision_type:
231+ Assign a collision name to this sprite. It will be used
232+ by :py:meth:`add_collision_handler` if called.
100233 """
101234
102235 if damping is not None :
@@ -228,7 +361,6 @@ def add_sprite_list(
228361 collision_type : Optional [str ] = None ,
229362 ):
230363 """Add all sprites in a sprite list to the physics engine."""
231-
232364 for sprite in sprite_list :
233365 self .add_sprite (
234366 sprite = sprite ,
@@ -251,7 +383,22 @@ def remove_sprite(self, sprite: Sprite):
251383 self .non_static_sprite_list .remove (sprite )
252384
253385 def get_sprite_for_shape (self , shape : Optional [pymunk .Shape ]) -> Optional [Sprite ]:
254- """Given a shape, what sprite is associated with it?"""
386+ """Try to get the sprite registered with this engine for ``shape``.
387+
388+ This method returns ``None`` when:
389+
390+ * ``shape`` is ``None``
391+ * No :py:class:`.Sprite` was to this engine for ``shape``
392+
393+ The second item may occur if you are using multiple instances of
394+ :py:class:`.PymunkPhysicsEngine`.
395+
396+ Args:
397+ shape:
398+ A Pymunk shape to perform lookup for.
399+ Returns:
400+ A sprite for the ``shape``; ``None`` if no sprite is known.
401+ """
255402 for sprite in self .sprites :
256403 if self .sprites [sprite ].shape is shape :
257404 return sprite
@@ -281,7 +428,16 @@ def apply_impulse(self, sprite: Sprite, impulse: tuple[float, float]):
281428 physics_object .body .apply_impulse_at_local_point (impulse )
282429
283430 def set_position (self , sprite : Sprite , position : Union [pymunk .Vec2d , tuple [float , float ]]):
284- """Apply an impulse force on a sprite"""
431+ """Set the position of the sprite in the engine's simulation.
432+
433+ To learn more, please see :py:attr:`pymunk.Body.position`.
434+
435+ Args:
436+ sprite:
437+ An Arcade :py:class:`.Sprite` known to the engine.
438+ position:
439+ A two-dimensional position in world space.
440+ """
285441 physics_object = self .get_physics_object (sprite )
286442 if physics_object .body is None :
287443 raise PymunkException (
@@ -298,7 +454,20 @@ def set_rotation(self, sprite: Sprite, rotation: float):
298454 physics_object .body .angle = math .radians (rotation )
299455
300456 def set_velocity (self , sprite : Sprite , velocity : tuple [float , float ]):
301- """Apply an impulse force on a sprite"""
457+ """Directly set the velocity of a sprite known to the engine.
458+
459+ .. warning:: Avoid using this on any :py:attr:`DYNAMIC` objects!
460+
461+ This function is meant for :py:attr:`KINEMATIC` objects. Using
462+ it on a sprite added as :py:attr:`DYNAMIC` can cause strange and
463+ very broken behavior.
464+
465+ To learn more, please see:
466+
467+ * Pymunk's documentation on :py:attr:`~pymunk.Body.DYNAMIC` and
468+ :py:attr:`~pymunk.Body.KINEMATIC`
469+
470+ """
302471 physics_object = self .get_physics_object (sprite )
303472 if physics_object .body is None :
304473 raise PymunkException (
@@ -440,7 +609,25 @@ def set_horizontal_velocity(self, sprite: Sprite, velocity: float):
440609 physics_object .body .velocity = new_cv
441610
442611 def set_friction (self , sprite : Sprite , friction : float ):
443- """Apply force to a Sprite."""
612+ """Set the friction a sprite experiences against other surfaces.
613+
614+ This is how "rough" a sprite is during a collision with others:
615+
616+ * ``0.0`` is the lowest value allowed (absolute slipperiness)
617+ * Higher values slide less on surfaces and other objects
618+
619+ Pymunk allows setting ``friction`` higher than ``1.0``, but very
620+ high values might not have meaningful gameplay impact.
621+
622+ .. _Simple Wikipedia's Article on Friction: https://simple.wikipedia.org/wiki/Friction
623+
624+ To learn more, please see:
625+
626+ * The :ref:`pymunk_platformer_tutorial-add_physics_engine` step
627+ of the :ref:`pymunk_platformer_tutorial`
628+ * `Simple Wikipedia's Article on Friction`_
629+ * :py:attr:`pymunk.Poly.friction`
630+ """
444631 physics_object = self .sprites [sprite ]
445632 if physics_object .shape is None :
446633 raise PymunkException (
0 commit comments