pocketpy/docs/modules/box2d.md
blueloveTH ddba3678d1 ...
2023-08-06 18:13:57 +08:00

4.9 KiB

icon label
package box2d

Box2D by Erin Catto, the world's best 2D physics engine now becomes a built-in module in pkpy v1.1.3 and later.

Setup

box2d module will be enabled by default for CMake users. All platforms are supported, including desktop, mobile and web.

You can set option PK_USE_BOX2D to OFF in CMakeLists.txt if you don't want to use it.

Overview

The box2d module in pkpy provides a high-level, also simplified, interface to Box2D engine, which is suitable for most use cases. There are two classes in box2d module: World and Body.

World is the world of Box2D, it is the container of all Bodys. In most cases, you only need one World instance. World class provides methods to create, destroy and query Bodys and also methods to step the simulation.

A Body instance is a physical entity in the world. A Body can only have one shape at a time. For example, a circle, a rectangle, a polygon, etc. You are allowed to change the shape of a Body at runtime. Bodys can be static, dynamic or kinematic. A static Body is not affected by forces or collisions. A dynamic Body is fully simulated. A kinematic Body moves according to its velocity. Body class provides methods to set its properties, such as position, velocity, etc. It also provides methods to apply forces and impulses to it.

!!! A box2d.Body in pkpy is an unified wrapper of Box2D's b2Body, b2Shape and b2Fixture. It hides the details of Box2D's API and provides a high-level interface. !!!

API list

from linalg import vec2, vec4
from typing import Iterable

class _NodeLike:    # duck-type protocol
    def on_contact_begin(self, other: 'Body'): ...
    def on_contact_end(self, other: 'Body'): ...

class _DrawLike:    # duck-type protocol
    def draw_polygon(self, vertices: list[vec2], color: vec4): ...
    def draw_solid_polygon(self, vertices: list[vec2], color: vec4): ...
    def draw_circle(self, center: vec2, radius: float, color: vec4): ...
    def draw_solid_circle(self, center: vec2, radius: float, axis: vec2, color: vec4): ...
    def draw_segment(self, p1: vec2, p2: vec2, color: vec4): ...
    def draw_transform(self, position: vec2, rotation: float): ...
    def draw_point(self, p: vec2, size: float, color: vec4): ...

class World:
    gravity: vec2       # gravity of the world, by default vec2(0, 0)

    def get_bodies(self) -> Iterable['Body']:
        """return all bodies in the world."""

    def ray_cast(self, start: vec2, end: vec2) -> list['Body']:
        """raycast from start to end"""

    def box_cast(self, lower: vec2, upper: vec2) -> list['Body']:
        """query bodies in the AABB region."""

    def step(self, dt: float, velocity_iterations: int, position_iterations: int) -> None:
        """step the simulation, e.g. world.step(1/60, 8, 3)"""

	# enum
	# {
	# 	e_shapeBit				= 0x0001,	///< draw shapes
	# 	e_jointBit				= 0x0002,	///< draw joint connections
	# 	e_aabbBit				= 0x0004,	///< draw axis aligned bounding boxes
	# 	e_pairBit				= 0x0008,	///< draw broad-phase pairs
	# 	e_centerOfMassBit		= 0x0010	///< draw center of mass frame
	# };
    def debug_draw(self, flags: int):
        """draw debug shapes of all bodies in the world."""

    def set_debug_draw(self, draw: _DrawLike):
        """set the debug draw object."""

class Body:
    type: int           # 0-static, 1-kinematic, 2-dynamic, by default 2
    gravity_scale: float
    fixed_rotation: bool
    enabled: bool
    bullet: bool        # whether to use continuous collision detection

    @property
    def mass(self) -> float: ...
    @property
    def inertia(self) -> float: ...

    position: vec2
    rotation: float     # in radians (counter-clockwise)
    velocity: vec2      # linear velocity
    angular_velocity: float
    damping: float      # linear damping
    angular_damping: float

    # fixture settings
    density: float
    friction: float
    restitution: float
    restitution_threshold: float
    is_trigger: bool

    def __new__(cls, world: World, node: _NodeLike = None):
        """create a body in the world."""

    def set_box_shape(self, hx: float, hy: float): ...
    def set_circle_shape(self, radius: float): ...
    def set_polygon_shape(self, points: list[vec2]): ...
    def set_chain_shape(self, points: list[vec2]): ...

    def apply_force(self, force: vec2, point: vec2): ...
    def apply_force_to_center(self, force: vec2): ...
    def apply_torque(self, torque: float): ...
    def apply_impulse(self, impulse: vec2, point: vec2): ...
    def apply_impulse_to_center(self, impulse: vec2): ...
    def apply_angular_impulse(self, impulse: float): ...

    def get_node(self) -> _NodeLike:
        """return the node that is attached to this body."""

    def get_contacts(self) -> list['Body']:
        """return all bodies that are in contact with this body."""

    def destroy(self):
        """destroy this body."""

Example

import box2d

world = box2d.World()
body = box2d.Body(world)