Skip to main content

CollisionInfo

Information about a single 3D collision contact point.

TypeNameInterface Description
Variablesnormal: Vector3f

Function: World-space contact normal vector.

VariablesotherObject: 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.

Variablespoint: Vector3f

Function: World-space contact point.

Functionsconstructor(point: Vector3f, normal: Vector3f, otherObject: SceneObject | null)

Examples

constructor(point: Vector3f, normal: Vector3f, otherObject: SceneObject | null)

let obj = new APJS.CollisionInfo();

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 — 3D physics collision event handler. Listens on BoxCollider/SphereCollider for Enter/Stay/Exit events.

@component()
export class CollisionHandler3D extends APJS.BasicScriptComponent {
private collider: APJS.Collider;
private inited = false;
private hitCount = 0;

private onEnter = (event: APJS.IEvent) => {
this.hitCount++;
const infos = event.args[0] as APJS.CollisionInfo[];
for (const info of infos) {
if (info.otherObject) {
console.log("[Collision] Enter #" + this.hitCount + ": " + info.otherObject.name);
console.log(" point: " + info.point.x.toFixed(2) + ", " + info.point.y.toFixed(2) + ", " + info.point.z.toFixed(2));
console.log(" normal: " + info.normal.x.toFixed(2) + ", " + info.normal.y.toFixed(2) + ", " + info.normal.z.toFixed(2));
}
}
};

private onExit = (event: APJS.IEvent) => {
console.log("[Collision] Exit");
};

// RecordStart: only the script-owned hitCount accumulator needs reset; this example
// does not move any RigidBody, so no Physics3D reset block is needed. See GameState SKILL.
private onRecordStart = (_event: APJS.IEvent) => {
this.hitCount = 0;
};

onStart(): void {
APJS.EventManager.getGlobalEmitter().on(APJS.EventType.RecordStart, this.onRecordStart);
}

onUpdate(dt: number): void {
if (!this.inited) {
const obj = this.getSceneObject();
if (!obj) return;

// Try BoxCollider first, then SphereCollider
this.collider = obj.getComponent("BoxCollider") as APJS.BoxCollider;
if (!this.collider) {
this.collider = obj.getComponent("SphereCollider") as APJS.SphereCollider;
}
if (!this.collider) return;
this.inited = true;

this.collider.emitCollisionEvent = true;

// CRITICAL: pass collider, NOT sceneObject
const emitter = APJS.EventManager.getObjectEmitter(this.collider);
emitter.on(APJS.CollisionEvent.Enter, this.onEnter, this);
emitter.on(APJS.CollisionEvent.Exit, this.onExit, this);
}
}

onDestroy(): void {
if (this.collider) {
const emitter = APJS.EventManager.getObjectEmitter(this.collider);
emitter.off(APJS.CollisionEvent.Enter, this.onEnter, this);
emitter.off(APJS.CollisionEvent.Exit, this.onExit, this);
}
APJS.EventManager.getGlobalEmitter().off(APJS.EventType.RecordStart, this.onRecordStart);
}
}
Copyright © 2026 TikTok. All rights reserved.
About TikTokHelp CenterCareersContactLegalTerms of ServicePrivacy PolicyCookies