simvx.core.physics.material

Combine modes

Friction and restitution combine INDEPENDENTLY, each with one of Unity’s four modes (AVERAGE / MIN / MAX / MULTIPLY). Godot and Jolt hardcode a single rule for both; two independent modes is the deliberate difference.

When the two contacting materials request DIFFERENT modes for the same coefficient, the higher-priority mode wins (Unity’s documented priority order): MAX > MIN > MULTIPLY > AVERAGE. The least-surprising authoring behaviour: a deliberately grippy / bouncy surface dominates a neutral one. See :func:_combine.

Every place a mode is accepted also accepts its NAME, so a scene file and a call site can both say friction_combine="max" and never import the enum.

PhysicsMaterial: the surface half of a body’s physics, as a shareable resource.

A body’s knobs live in three homes, and this module is one of them:

  • Material (here), per CONTACT: friction, restitution, and how two of them combine. It describes a SURFACE, so one FROZEN instance is shared by every body made of that surface – ice, rubber, wood – and is serialised into a .py scene as one nested value rather than as four loose numbers per body.

  • Body, per body: linear and angular damping, gravity scale, mass, and can_sleep. See :meth:~simvx.core.physics.world.PhysicsWorld.create_body.

  • World: gravity, solver iterations and the sleep thresholds. See

    class:

    ~simvx.core.physics.world.PhysicsWorld.

Restitution defaults to 0.0, not to a bouncy value: giving a body a material must never silently start bouncing a scene that was inelastic before.

Module Contents

Classes

CombineMode

How two materials’ coefficients combine at a contact (Unity’s four modes).

PhysicsMaterial

Surface material: friction + restitution + per-coefficient combine modes.

Data

API

simvx.core.physics.material.__all__

[‘CombineMode’, ‘PhysicsMaterial’]

class simvx.core.physics.material.CombineMode[source]

Bases: enum.Enum

How two materials’ coefficients combine at a contact (Unity’s four modes).

String values (parity with :class:~simvx.core.physics.world.BodyMode), so it serialises and inspects cleanly. NOT an IntEnum: the differing-mode priority is an explicit dict (:data:_PRIORITY), never the enum ordinal, so reordering the members can never silently change priority.

A mode is accepted by NAME anywhere it is accepted at all – CombineMode("max"), PhysicsMaterial(friction_combine="max") – because a scene file and a quick call site should not have to import an enum to say something this small. The canonical spellings are Unity’s full words ("average", "minimum", "maximum", "multiply"), which are what a serialised scene carries; "min" / "max" are accepted as the obvious short forms, and matching is case-insensitive.

AVERAGE

‘average’

MIN

‘minimum’

MAX

‘maximum’

MULTIPLY

‘multiply’

__new__(value)
__repr__()
__str__()
__dir__()
__format__(format_spec)
__hash__()
__reduce_ex__(proto)
__deepcopy__(memo)
__copy__()
name()
value()
class simvx.core.physics.material.PhysicsMaterial[source]

Surface material: friction + restitution + per-coefficient combine modes.

An IMMUTABLE value resource, and being frozen is what makes sharing it safe: one ICE instance assigned to fifty bodies is one surface, and no body can edit what the other forty-nine are made of. It is a VALUE – two materials holding the same four numbers describe the same surface – so giving a live body a different surface means assigning it a material whose VALUES differ::

from dataclasses import replace

body.material = replace(body.material, friction=0.1)

Assigning an equal-valued material is a no-op, which is the honest answer: the surface did not change. Nothing in the seam holds a reference to the resource – a world is handed the four numbers, never the object – so a shared material stays a plain Python value with no backend lifetime. Immutability also makes it hashable, so it can key a dict or sit in a set.

Data:

DEFAULT_PHYSICS_MATERIAL is the shared fallback for a body with no material set.

Both combine modes accept a NAME as well as a member (PhysicsMaterial(friction_combine="max")); the stored value is always the

Class:

CombineMode member, so identity comparisons downstream hold.

Attributes: friction: Coulomb friction coefficient mu (>= 0; no hard upper bound). 0 is frictionless; ~0.5 is a sensible default. restitution: Bounciness in [0, 1]. 0 is fully inelastic (the engine default: adding a material never starts bouncing an existing scene); 1 is a perfectly elastic bounce. friction_combine: How this material’s friction combines with a contacting material’s (see :class:CombineMode). restitution_combine: How this material’s restitution combines, independent of friction_combine (the Godot / Jolt-beating differentiator).

Raises: ValueError: If friction is negative, restitution is outside [0, 1], or either combine mode is not a recognised spelling. Caller input is validated with a real exception rather than an assert, which python -O deletes. dataclasses.FrozenInstanceError: On any attribute assignment after construction.

friction: float

0.5

restitution: float

0.0

friction_combine: simvx.core.physics.material.CombineMode

None

restitution_combine: simvx.core.physics.material.CombineMode

None

__post_init__() None[source]
simvx.core.physics.material.DEFAULT_PHYSICS_MATERIAL

‘PhysicsMaterial(…)’