logo
GravityMass

physics · physics-puzzle

GravityMass

Free

Install with the CLI:

bjs download GravityMass

GravityMass

How hard an entity pulls, and how big a target it is.

What it does

GravityMass is data with no System of its own. Each frame GravityBodySystem reads every mass where its MeshPrimitive sits and moves every GravityBody through the sum of their pulls. Gravity never moves a mass that is not also a body, so a black hole stays where the player left it.

The units make G equal 1. Each mass pulls with

a = mass · d / (|d|² + softening²)^1.5

where d runs from the body to the mass. Far away that is the plain mass / r²: a hole of 600 pulls a rock 8 units out at about 9.4 units/s². Close in, the softening keeps it finite, so a rock that skims a point mass gets a hard shove instead of a huge kick in one step.

A negative mass pushes. The same sum with the sign flipped points away from the mass, and nothing downstream changes. That is all a white hole is.

The rock and the aim line drawn ahead of it (TrajectoryPreview) are pushed by one shared function, fieldAt, which is why the line can be trusted. For level design, circularSpeed gives the speed of a circular orbit at a distance:

TypeScript
circularSpeed(600, 8); // 8.66

A rock that passes a 600 hole 8 units out at well over 8.66 units/s sails by with a bend. Well under, it falls in.

Use it in a scene

A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.

Build it from scratch with the bjs CLI:

  1. 1Scaffold a project
    npm create @babylonjsmarket/arcade@latest my-game

    World, renderer, and dev server — ready to run.

  2. 2Install dependencies
    cd my-game && npm install
  3. 3Add GravityMass
    bjs download GravityMass

    Copies its source into src/ so the scene resolves.

    First time? Run bjs login once.

  4. 4Paste the scene into src/scenes/arcade-room.ts and run
    npm run dev

    SceneLoader builds the world from the JSON; reload to rebuild.

JSON
{
  "Hole": {
    "tags": ["blackhole"],
    "components": {
      "MeshPrimitive": { "primitive": "sphere", "diameter": 2, "position": [2, 0, 6] },
      "GravityMass": { "mass": 450, "radius": 1, "absorbs": true, "softening": 0.3 }
    }
  },
  "Asteroid": {
    "tags": ["asteroid"],
    "components": {
      "MeshPrimitive": { "primitive": "sphere", "diameter": 4, "position": [2, -8, 0.5] },
      "GravityMass": { "mass": 40, "radius": 2, "softening": 0.5 }
    }
  },
  "Rock": {
    "tags": ["rock"],
    "components": {
      "MeshPrimitive": { "primitive": "sphere", "diameter": 1, "position": [-28, 0, -8] },
      "GravityBody": { "velocity": [11, 0, 0], "radius": 0.42, "maxSpeed": 45 },
      "GravityMass": { "mass": 0.3 }
    }
  }
}

The hole swallows what reaches it and the asteroid is a crash. The rock is a body and a mass at once: pulled by everything, and pulling a little itself.

Props

  • mass (number, default 1) — how hard it pulls. Negative pushes.
  • radius (number, default 0) — the surface a body hits. 0 is a point mass that pulls but can never be hit.
  • softening (number, default 0.25) — keeps the pull finite near the centre. Far out it barely matters.
  • absorbs (boolean, default false) — makes the surface an event horizon: a body that reaches it is swallowed rather than crashing.
  • lenses (boolean, default: same as absorbs) — whether a GravityLens sky bends light round this mass. Black holes lens, rocks don't.

Events

None. When a body reaches the surface, GravityBody emits gravity.body.contact naming this mass, with swallowed: true if it absorbs.

Dependencies

None in its own bundle. It needs a MeshPrimitive on the same entity for its position, and a GravityBody somewhere in the scene to read it.

Notes

  • radius is not read from the mesh. Size the sphere to match, as the example does, or let BlackHole and WhiteHole scale theirs for you.
  • mass: 0 with a radius is a wall that pulls nothing. radius: 0 is a pull nothing can hit.
  • Masses are read fresh every frame. Drag a hole and the next frame's pull follows it; park one in its pool and it stops pulling at once.
  • A body never feels its own mass. SpaceGolf rocks carry mass: 0.3, so they tug on each other in flight.
  • The scene loader starts GravityBody's System only when the scene names GravityBody somewhere, and a Pool blueprint counts. Masses on their own move nothing.

More like this

AiPilot
Animation
ArcCamera
Asteroid
AxisViewCamera
BlackHole
BoatMode
BoatWater
Bullet
Bumper
CameraFollow
CaptureZone
ContactDamage
ContactImpulse
DirectionalLight
EnemySpawner
EnvironmentTexture
FreighterCar
FreighterChain
FreighterHead
GameConfig
GravityBody
GravityLens
Hand
Health
HemisphericLight
Jump
KeyboardInput
KeyboardMover
Lifetime
LineOfSight
MachineGun
MassDriver
Mesh
MeshPrimitive
Missile
MissileLauncher
MissionDirector
MotionTrail
MouseHole
MouseInput
Movement
Obstacle
ObstacleField
OilBlob
OrbitMover
Parts
Physics
PlayerInput
PlayerWalkAnimator
PointerDrag
RespawnTimer
RoundReset
Score
Shadow
ShipLoadout
SkeletonAnimator
SpaceGolfDirector
SpaceGolfHUD
SpaceRock
SpaceShooterBullet
SpaceShooterHealth
SpaceShooterScore
Spin
Spinner
SurfacePatch
TrajectoryPreview
TwinStickEnemy
Velocity6DOF
WaveDirector
Waypoint
WaypointTrack
WhiteHole
Wormhole

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search