RigidBody2D
A 2D physics rigid body component.
| Type | Name | Interface Description |
|---|---|---|
| Variables | angularDamping: number | • Function: Gets or sets the body's angular damping coefficient. Value typically ranges from 0 (no damping) to 1 (maximum damping). Larger values make angular velocity decay faster. |
| Variables | angularVelocity: number | • Function: Gets or sets the rigid body's angular velocity in radians per second. Positive values indicate counter-clockwise rotation. Once the body is created, the getter returns the live simulator value. Setting this property changes the current runtime state only; use for startup configuration. |
| Variables | damping: number | • Function: Gets or sets the body's linear damping coefficient. Value typically ranges from 0 (no damping) to 1 (maximum damping). Larger values make linear velocity decay faster during simulation. |
| Variables | force: Vector2f | • Function: Gets or sets the continuous force applied to the rigid body in world space. Force is measured in Newtons and is applied continuously during physics simulation. Setting this replaces the previous continuous force value. This does NOT affect forces added via . To apply multiple forces cumulatively, use instead. |
| Variables | freezeX: boolean | • Function: Gets or sets whether this body is locked against horizontal movement. |
| Variables | freezeY: boolean | • Function: Gets or sets whether this body is locked against vertical movement. |
| Variables | freezeZ: boolean | • Function: Gets or sets whether this body is locked against rotation. |
| Variables | gravityScale: number | • Function: Gets or sets the multiplier applied to global 2D gravity for this body. For example, 0 disables gravity, 1 uses normal gravity, and 2 doubles it. If is false, this value is stored but not pushed to the simulator until gravity is re-enabled. |
| Variables | initialAngularVelocity: number | • Function: Gets or sets the initial angular velocity of the RigidBody2D in radians per second. This value is serialized and applied when the body is first created. To read/write runtime angular velocity, use the |
| Variables | initialVelocity: Vector2f | • Function: Gets or sets the initial linear velocity of the RigidBody2D in meters per second. This value is serialized and applied when the body is first created. To read/write runtime velocity, use the |
| Variables | mass: number | • Function: Gets or sets the body's mass in kilograms. Larger mass reduces acceleration from the same applied force and affects collision response. |
| Variables | position: Vector2f | • Function: Gets or sets the position of the RigidBody2D in world coordinates. Position represents the center of mass of the body in 2D space. Setting this property teleports the body immediately instead of moving it through simulation. Do NOT modify |
| Variables | rotation: number | • Function: Gets or sets this body's authored rotation in radians. Rotation is measured counter-clockwise from the positive X-axis. Setting this property rotates the body immediately instead of moving it through simulation. Do NOT modify |
| Variables | static: boolean | • Function: Gets or sets whether this body behaves like a non-moving physics body. When enabled, the simulator switches this body away from dynamic simulation, clears accumulated force and torque, and resets its runtime linear and angular velocity to zero. Re-enabling dynamic behavior restores the serialized initial velocity values. |
| Variables | torque: number | • Function: Gets or sets the continuous torque applied to the rigid body in world space. Torque is measured in Newton-meters and is applied continuously during physics simulation. Setting this replaces the previous continuous torque value. This does NOT affect torques added via . To apply multiple torques cumulatively, use instead. |
| Variables | useGravity: boolean | • Function: Gets or sets whether gravity affects this body. When enabled, the simulator uses this body's current . When disabled, APJS pushes a native gravity scale of |
| Variables | velocity: Vector2f | • Function: Gets or sets the rigid body's world-space linear velocity in meters per second. Once the body is created, the getter returns the live simulator velocity. Setting this property changes the current runtime state only; use for startup configuration. |
| Functions | constructor() | |
| Functions | addForce(force: Vector2f, mode?: ForceMode2D): void | • Function: Adds force to this body. Continuous modes accumulate force or acceleration until removed. Instantaneous modes apply an impulse immediately. Force modes: - Parameters • • |
| Functions | addForceAt(force: Vector2f, position: Vector2f, isLocal?: boolean, mode?: ForceMode2D): ConstantForce2D | null | • Function: Applies force at a specific point, which may also generate torque. If Parameters • • • • Returns A world-space handle for continuous modes; |
| Functions | addTorque(torque: number, mode?: ForceMode2D): void | • Function: Adds torque to this body. Continuous modes accumulate torque or angular acceleration until removed. Instantaneous modes apply angular impulse immediately. Parameters • • |
Examples
position: Vector2f
rigidBody2D.position = new Vector2f(5, 3); // teleport to (5m, 3m)
constructor()
let obj = new APJS.RigidBody2D();
addForceAt(force: Vector2f, position: Vector2f, isLocal?: boolean, mode?: ForceMode2D): ConstantForce2D | null
const pushForce = new APJS.Vector2f(10, 0); // Push right
const cornerPos = new APJS.Vector2f(0.5, 0.5); // Top-right corner in local space
rigidBody2D.addForceAt(pushForce, cornerPos, true, APJS.ForceMode2D.Impulse);
Use Case
Example 1 — Tap to drop a ball/coin that bounces multiple times on a static floor — full Physics Matter resource flow (DSL: add_builtin_resource → set_resource_properties →…
@component()
export class TapToDropBouncy extends APJS.BasicScriptComponent {
private rb: APJS.RigidBody2D | null = null;
private collider: APJS.CircleCollider2D | null = null;
private touchCallback: ((event: APJS.IEvent) => void) | null = null;
private collisionCallback: ((event: APJS.IEvent) => void) | null = null;
private dropped = false;
private bounceCount = 0;
onStart(): void {
const obj = this.getSceneObject();
this.rb = obj.getComponent("RigidBody2D") as APJS.RigidBody2D;
this.collider = obj.getComponent("CircleCollider2D") as APJS.CircleCollider2D;
if (!this.rb || !this.collider) return;
// emitCollisionEvent is APJS-runtime-only — must set in onStart, not in DSL.
this.collider.emitCollisionEvent = true;
this.touchCallback = (event: APJS.IEvent) => {
const touch = event.args[0] as APJS.TouchData;
if (touch.phase === APJS.TouchPhase.Began && !this.dropped && this.rb) {
this.dropped = true;
this.rb.static = false; // gravity now applies
}
};
APJS.EventManager.getGlobalEmitter().on(APJS.EventType.Touch, this.touchCallback);
this.collisionCallback = (event: APJS.IEvent) => {
this.bounceCount++;
// Optional: stop tracking after 5 bounces, or play SFX, or update score, etc.
if (this.bounceCount === 1) console.log("[Bouncy] first impact");
};
const emitter = APJS.EventManager.getObjectEmitter(this.collider);
emitter.on(APJS.CollisionEvent2D.Enter, this.collisionCallback, this);
}
onDestroy(): void {
if (this.touchCallback) {
APJS.EventManager.getGlobalEmitter().off(APJS.EventType.Touch, this.touchCallback);
}
if (this.collisionCallback && this.collider) {
APJS.EventManager.getObjectEmitter(this.collider).off(APJS.CollisionEvent2D.Enter, this.collisionCallback, this);
}
}
}
Example 2 — On tap, apply random upward impulse to multiple 2D physics blocks using addForce with ForceMode2D.Impulse
@component()
export class TapPushBlocks extends APJS.BasicScriptComponent {
@serializeProperty
blocks: APJS.SceneObject[] = [];
private blockStartPos: APJS.Vector2f[] = [];
private blockStartGravity: boolean[] = [];
private inited = false;
private onTouch = (event: APJS.IEvent) => {
const touch = event.args[0] as APJS.TouchData;
if (touch.phase === APJS.TouchPhase.Began) {
for (const obj of this.blocks) {
const rb = obj.getComponent("RigidBody2D") as APJS.RigidBody2D;
if (rb) {
const randomX = (Math.random() - 0.5) * 200;
const upwardY = 300 + Math.random() * 200;
rb.addForce(new APJS.Vector2f(randomX, upwardY), APJS.ForceMode2D.Impulse);
}
}
}
};
// RecordStart: pool reset per Physics2D §"RecordStart Reset for 2D Physics" — iterate
// each block, apply velocity → anchoredPosition → useGravity. Cache per-block startPos
// and startGravity flag in the lazy init below. See GameState §"RecordStart / RecordEnd Lifecycle".
private onRecordStart = (_event: APJS.IEvent) => {
if (!this.inited) return;
for (let i = 0; i < this.blocks.length; i++) {
const obj = this.blocks[i];
if (!obj) continue;
const rb = obj.getComponent("RigidBody2D") as APJS.RigidBody2D;
const st = obj.getComponent("ScreenTransform") as APJS.ScreenTransform;
if (rb) rb.velocity = new APJS.Vector2f(0, 0);
if (st && this.blockStartPos[i]) {
st.anchoredPosition = new APJS.Vector2f(this.blockStartPos[i].x, this.blockStartPos[i].y);
}
if (rb && this.blockStartGravity[i] !== undefined) {
rb.useGravity = this.blockStartGravity[i];
}
}
};
onStart(): void {
APJS.EventManager.getGlobalEmitter().on(APJS.EventType.Touch, this.onTouch);
APJS.EventManager.getGlobalEmitter().on(APJS.EventType.RecordStart, this.onRecordStart);
}
onUpdate(_dt: number): void {
if (!this.inited && this.blocks.length > 0) {
for (const obj of this.blocks) {
if (!obj) continue;
const st = obj.getComponent("ScreenTransform") as APJS.ScreenTransform;
const rb = obj.getComponent("RigidBody2D") as APJS.RigidBody2D;
if (st) {
this.blockStartPos.push(new APJS.Vector2f(st.anchoredPosition.x, st.anchoredPosition.y));
} else {
this.blockStartPos.push(new APJS.Vector2f(0, 0));
}
this.blockStartGravity.push(rb ? rb.useGravity : true);
}
this.inited = true;
}
}
onDestroy(): void {
APJS.EventManager.getGlobalEmitter().off(APJS.EventType.Touch, this.onTouch);
APJS.EventManager.getGlobalEmitter().off(APJS.EventType.RecordStart, this.onRecordStart);
}
}