CollisionInfo2D
* Information about a single 2D collision contact point.
| Type | Name | Interface Description |
|---|---|---|
| Variables | normal: Vector2f | • Function: World-space contact normal vector. |
| Variables | otherObject: SceneObject | null | • Function: The SceneObject that owns the other collider in this collision pair. This is null if APJS cannot resolve that collider back to a SceneObject. |
| Variables | point: Vector2f | • Function: World-space contact point. |
| Functions | constructor(point: Vector2f, normal: Vector2f, otherObject: SceneObject | null) |
Examples
constructor(point: Vector2f, normal: Vector2f, otherObject: SceneObject | null)
let obj = new APJS.CollisionInfo2D();
Use Case
Example 1 — Track score via 2D collision events: enable emitCollisionEvent on CircleCollider2D, listen to CollisionEvent2D.Enter via getObjectEmitter, toggle RigidBody2D.st…
@component()
export class CollisionScoreTracker extends APJS.BasicScriptComponent {
@serializeProperty
private playerObject: APJS.SceneObject;
@serializeProperty
private scoreTextObject: APJS.SceneObject;
private rigidBody: APJS.RigidBody2D;
private collider: APJS.CircleCollider2D;
private scoreText: APJS.Text;
private score: number = 0;
private released: boolean = false;
onStart(): void {
this.rigidBody = this.playerObject.getComponent("RigidBody2D") as APJS.RigidBody2D;
this.collider = this.playerObject.getComponent("CircleCollider2D") as APJS.CircleCollider2D;
this.scoreText = this.scoreTextObject.getComponent("Text") as APJS.Text;
if (this.rigidBody) this.rigidBody.static = true;
if (this.collider) {
this.collider.emitCollisionEvent = true;
const emitter = APJS.EventManager.getObjectEmitter(this.collider);
emitter.on(APJS.CollisionEvent2D.Enter, this.onCollision);
}
APJS.EventManager.getGlobalEmitter().on(APJS.EventType.Touch, this.onTouch);
APJS.EventManager.getGlobalEmitter().on(APJS.EventType.RecordStart, this.onRecordStart);
}
private onTouch = (event: APJS.IEvent) => {
const touch = event.args[0] as APJS.TouchData;
if (touch.phase === APJS.TouchPhase.Began && !this.released) {
this.released = true;
if (this.rigidBody) this.rigidBody.static = false;
}
};
private onCollision = (event: APJS.IEvent) => {
const infos = event.args[0] as APJS.CollisionInfo2D[];
for (const info of infos) {
const other = info.otherObject as APJS.SceneObject;
if (other) {
this.score++;
if (this.scoreText) this.scoreText.text = `Score: ${this.score}`;
}
}
};
private onRecordStart = () => {
this.score = 0;
this.released = false;
if (this.rigidBody) this.rigidBody.static = true;
if (this.scoreText) this.scoreText.text = "Score: 0";
};
onDestroy(): void {
APJS.EventManager.getGlobalEmitter().off(APJS.EventType.Touch, this.onTouch);
APJS.EventManager.getGlobalEmitter().off(APJS.EventType.RecordStart, this.onRecordStart);
if (this.collider) {
this.collider.emitCollisionEvent = false;
const emitter = APJS.EventManager.getObjectEmitter(this.collider);
emitter.off(APJS.CollisionEvent2D.Enter, this.onCollision);
}
}
}
Example 2 — Detect 2D collision and reverse velocity to bounce off obstacles
@component()
export class CollisionBounce extends APJS.BasicScriptComponent {
private collisionCallback: (event: APJS.IEvent) => void;
private collider: APJS.BoxCollider2D;
private velocity: APJS.Vector2f = new APJS.Vector2f(100, 100);
private startVelocity: APJS.Vector2f = new APJS.Vector2f(100, 100);
private startPos!: APJS.Vector2f;
private startGravityOn = true;
private rb!: APJS.RigidBody2D;
private inited = false;
// RecordStart: reset bouncing ball per Physics2D §"RecordStart Reset for 2D Physics"
// (single-body block): velocity → script accumulators (this.velocity) → anchoredPosition
// → useGravity. Listener wiring per GameState §"RecordStart / RecordEnd Lifecycle".
private onRecordStart = (_event: APJS.IEvent) => {
if (!this.inited) return;
this.rb.velocity = new APJS.Vector2f(0, 0);
this.velocity = new APJS.Vector2f(this.startVelocity.x, this.startVelocity.y);
const obj = this.getSceneObject();
const st = obj.getComponent("ScreenTransform") as APJS.ScreenTransform;
if (st && this.startPos) {
st.anchoredPosition = new APJS.Vector2f(this.startPos.x, this.startPos.y);
}
this.rb.useGravity = this.startGravityOn;
};
onStart(): void {
this.collider = this.getSceneObject().getComponent("BoxCollider2D") as APJS.BoxCollider2D;
if (!this.collider) return;
this.collider.emitCollisionEvent = true;
this.collisionCallback = (event: APJS.IEvent) => {
const infos = event.args[0] as APJS.CollisionInfo2D[];
for (const info of infos) {
// Reflect velocity based on collision normal
const normal = info.normal;
const dot = this.velocity.x * normal.x + this.velocity.y * normal.y;
this.velocity = new APJS.Vector2f(
this.velocity.x - 2 * dot * normal.x,
this.velocity.y - 2 * dot * normal.y
);
}
};
const emitter = APJS.EventManager.getObjectEmitter(this.collider);
emitter.on(APJS.CollisionEvent2D.Enter, this.collisionCallback, this);
APJS.EventManager.getGlobalEmitter().on(APJS.EventType.RecordStart, this.onRecordStart);
}
onUpdate(deltaTime: number): void {
const rb = this.getSceneObject().getComponent("RigidBody2D") as APJS.RigidBody2D;
if (!rb) return;
if (!this.inited) {
this.rb = rb;
const st = this.getSceneObject().getComponent("ScreenTransform") as APJS.ScreenTransform;
if (st) this.startPos = new APJS.Vector2f(st.anchoredPosition.x, st.anchoredPosition.y);
this.startGravityOn = rb.useGravity;
this.inited = true;
}
const pos = rb.position;
rb.position = new APJS.Vector2f(
pos.x + this.velocity.x * deltaTime,
pos.y + this.velocity.y * deltaTime
);
}
onDestroy(): void {
if (this.collisionCallback && this.collider) {
const emitter = APJS.EventManager.getObjectEmitter(this.collider);
emitter.off(APJS.CollisionEvent2D.Enter, this.collisionCallback, this);
}
APJS.EventManager.getGlobalEmitter().off(APJS.EventType.RecordStart, this.onRecordStart);
}
}