Skip to content

Physics ​

Bare has two optional physics engines. Neither is included in your build unless you import it.

Arcade physics ​

Simple rectangle and circle collisions, good for platformers and top-down games. Import from bare-engine/arcade and register it in your scene:

ts
import { ArcadeObject, ArcadePhysicsController } from 'bare-engine/arcade';

export class Game extends Scene
{
    OnAwake()
    {
        bare.AddClass(ArcadeObject);
        bare.AddClass(ArcadePhysicsController);
    }
}

Then give your prefabs "baseClass": "ArcadeObject":

json
{
  "name": "player",
  "baseClass": "ArcadeObject",
  "texture": "player"
},
{
  "name": "block",
  "baseClass": "ArcadeObject",
  "texture": "block",
  "static": true
}

Set gravity at the top level of settingsData.json:

json
{
  "gravity": 5000
}

Example: the Platformer registers arcade physics, sets gravity, and makes its prefabs ArcadeObjects.

ArcadeObject ​

PropertyDefaultDescription
velocity{ x: 0, y: 0 }Speed in units per second (Vec2).
staticfalseDoesn't move; other objects collide with it.
collidetrueTakes part in collisions.
sensorfalseReports collisions but doesn't block, and ignores stayInBounds. Use it for triggers, like coins or checkpoints.
drag0Fraction of the velocity lost every 1/60 second, from 0 to 1.
restitution0Bounciness, from 0 to 1. Two objects bounce with the lower value of the two.
stayInBoundstrueKeep the object inside the level.
removeOnOutOfBoundsfalseRemove the object when it's fully outside the level.
hitboxthe imageRectangle as { x1, y1, x2, y2 }. Values between 0 and 1 are a fraction of the image size, larger ones are pixels. "FULL" covers the whole image.
hitboxType / hitboxRadius"Rectangle""Rectangle" or "Circle", and the circle's radius.

A child ArcadeObject always acts as a sensor, so it reports collisions without pushing anything.

MethodDescription
SetVelocity(vec) / SetVelocityXY(x, y) / ResetVelocity()Change velocity.
IsGrounded()Standing on something. Same as IsBlocked(BlockedState.Down).
IsBlocked(direction)Blocked in a direction: BlockedState.Up, Down, Left or Right.
IsMoving()Has velocity.

Examples: the Platformer's player moves with velocity and checks IsGrounded, and RPG enemies roam with SetVelocity. The Showcase has an arcade physics demo.

Collisions ​

Handle collisions in a component:

ts
export class CoinComponent extends Component<ArcadeObject>
{
    OnCollisionStart(other: GameObject)
    {
        if (other.name == 'player')
            this.go.Remove();
    }
}

OnCollisionUpdate runs every frame during contact, and OnCollisionEnd when it ends.

Examples: Platformer coins are collected on collision, and Shmup ships take damage from bullets.

Collision layers ​

By default, every object collides with every other object.

WARNING

That default only holds when your layers list includes "objects". If it doesn't, the engine adds an objects layer itself, and only objects on that layer collide, with each other. Add "objects" to layers, or use collidesWith.

To choose which layers collide, give them collidesWith in layersInfo:

json
"layers": ["enemies", "bulletsEnemy", "bulletsPlayer", "player"],
"layersInfo": {
  "bulletsPlayer": {
    "collidesWith": ["enemies"]
  },
  "bulletsEnemy": {
    "collidesWith": ["player"]
  },
  "enemies": {
    "collidesWith": ["player"]
  }
}

Now your bullets hit enemies, enemy bullets and enemies hit you, and nothing else collides. Bullets don't hit each other, and enemies don't push each other around.

  • A pair collides when either layer lists the other, so you only need to write it once.
  • As soon as one layer has collidesWith, layers without it don't collide with anything. List every pair that should collide, including a layer with itself if needed, like "collidesWith": ["objects"] for objects.
  • Children count as being on their root object's layer.

Example: this is the Shmup's layersInfo.

Realistic physics ​

Rigid-body physics with rotation, friction, mass and joints, based on Sopiro/Physics. Use it when objects should tumble, stack, swing or roll. It works, but it isn't as well supported as arcade physics yet.

Import it from bare-engine/sopiro and register the controller. That also registers all its body and joint classes:

ts
import { SopiroPhysicsController } from 'bare-engine/sopiro';

export class Game extends Scene
{
    OnAwake()
    {
        bare.AddClass(SopiroPhysicsController);
    }
}

Gravity is read from gravity in settingsData.json, like arcade physics. Without it, realistic physics uses a gravity of 1200.

Bodies ​

Set one of these as a prefab's baseClass:

ClassShape
BoxA rectangle, the size of the object.
CircleA circle.
PolygonAny convex shape, from polygonVertices: a flat list of points, [x1, y1, x2, y2, …].
json
{
  "name": "crate",
  "baseClass": "Box",
  "texture": "crate",
  "restitution": 0.5
},
{
  "name": "ground",
  "baseClass": "Box",
  "texture": "ground",
  "static": true
}
PropertyDescription
staticDoesn't move; other bodies collide with it.
mass / densityHow heavy the body is. Set one, the other follows from its size.
restitutionBounciness, from 0 to 1.
frictionHow much it grips other bodies.
surfaceSpeedMoves whatever touches it along its surface, like a conveyor belt.
linearVelocity / angularVelocityCurrent movement and spin.

You can also create bodies in code. They're GameObjects, so add them like any other:

ts
import { Circle, Type } from 'bare-engine/sopiro';

const ball = new Circle(this, 36, Type.Dynamic);
ball.restitution = 0.8;
this.AddGameObject(ball);
ball.SetPosition(x, y);

Collisions fire the collision_start, collision_update and collision_end events.

Joints ​

Joints connect two bodies. Place a joint object in the level editor where two bodies overlap, and it connects them. Placed on a single body, it pins that body to the spot instead. Joints are invisible in the game.

ClassWhat it does
RevoluteJointObjectA hinge: the bodies rotate freely around the point, like a wheel or a door.
WeldJointObjectGlues the bodies together.
AngleJointObjectKeeps the angle between the bodies, but lets them move.
DistanceJointObjectKeeps the bodies at a distance, like a rope or spring. Set mode to Pull for a rope that can go slack, and distance for its length. It draws a line in lineColor and lineWidth.
LineJointObjectLets a body slide along a line, like a piston. lockRotation stops it from rotating.
MotorJointObjectDrives a body: set angularSpeed to spin it, or linearOffset and angularOffset to move it, with maxForce and maxTorque as limits.

Every joint also has frequency and dampingRatio, to make it stiff or springy, and jointMass. They're inspector fields, so you can tweak them in the Chrome extension while the game runs.

To use a joint, make a prefab for it:

json
{
  "name": "hinge",
  "baseClass": "RevoluteJointObject",
  "texture": "PIXEL",
  "scale": {
    "x": 32,
    "y": 32
  },
  "pivot": "CENTER"
}

Example: the Showcase's realistic physics demo has a prefab for every body and joint, and creates a ball wherever you click.

Bare Engine is open source under the MIT license.