106 lines
3.1 KiB
TypeScript
106 lines
3.1 KiB
TypeScript
import { PhysicsTicking } from '../physics/ticking';
|
|
import type Rapier from '@dimforge/rapier3d';
|
|
import { PhysicalObject } from './physical.object';
|
|
import { Quaternion, Vector3 } from 'three';
|
|
import { EditorProperty } from '../decorators/property';
|
|
import { GameObject } from '../types/game-object';
|
|
|
|
export class PhysicsObject extends PhysicalObject implements PhysicsTicking {
|
|
public objectType = 'PhysicsObject';
|
|
isTickingObject = true;
|
|
|
|
protected collider?: Rapier.Collider;
|
|
public rigidBody?: Rapier.RigidBody;
|
|
protected physicsWorldRef?: Rapier.World;
|
|
|
|
@EditorProperty({ type: Boolean })
|
|
public canCollide = true;
|
|
|
|
@EditorProperty({ type: Boolean })
|
|
public anchored = true;
|
|
|
|
@EditorProperty({ type: Number })
|
|
public mass = 1;
|
|
|
|
@EditorProperty({ type: Number })
|
|
public friction = 0.2;
|
|
|
|
private _tempVec = new Vector3();
|
|
private _tempQuat = new Quaternion();
|
|
private _tempQuat2 = new Quaternion();
|
|
|
|
initialize(physicsEngine: typeof Rapier, physicsWorld: Rapier.World): void {
|
|
if (this.virtual) return;
|
|
this.physicsWorldRef = physicsWorld;
|
|
|
|
// This object has effecively no physics:
|
|
// doesn't move, doesn't collide
|
|
if (this.anchored && !this.canCollide) return;
|
|
|
|
let bodyDesc: Rapier.RigidBodyDesc;
|
|
if (this.anchored) bodyDesc = physicsEngine.RigidBodyDesc.fixed();
|
|
else bodyDesc = physicsEngine.RigidBodyDesc.dynamic();
|
|
|
|
const position = this.position.clone();
|
|
const rotation = this.quaternion.clone();
|
|
this.getWorldPosition(position);
|
|
this.getWorldQuaternion(rotation);
|
|
|
|
bodyDesc
|
|
.setTranslation(...position.toArray())
|
|
.setRotation(rotation)
|
|
.setAdditionalMass(this.mass)
|
|
.setLinearDamping(this.friction)
|
|
.setAngularDamping(this.friction);
|
|
|
|
const body = physicsWorld.createRigidBody(bodyDesc);
|
|
|
|
let collider: Rapier.Collider | undefined;
|
|
if (this.canCollide) {
|
|
collider = this.createCollider(physicsEngine, physicsWorld, body);
|
|
}
|
|
|
|
this.collider = collider;
|
|
this.rigidBody = body;
|
|
}
|
|
|
|
tick(dt: number): void {
|
|
if (!this.rigidBody || this.virtual) return;
|
|
this._tempVec.copy(this.rigidBody.translation() as any);
|
|
this._tempQuat.copy(this.rigidBody.rotation() as any);
|
|
if ((this.parent as GameObject)?.objectType !== 'World') {
|
|
this.parent?.worldToLocal(this._tempVec);
|
|
this.parent?.getWorldQuaternion(this._tempQuat2);
|
|
this._tempQuat2.invert();
|
|
this._tempQuat.premultiply(this._tempQuat2);
|
|
}
|
|
this.position.copy(this._tempVec);
|
|
this.quaternion.copy(this._tempQuat);
|
|
}
|
|
|
|
dispose(): void {
|
|
if (this.collider && !this.rigidBody) {
|
|
this.physicsWorldRef?.removeCollider(this.collider, false);
|
|
}
|
|
|
|
if (this.rigidBody) {
|
|
this.physicsWorldRef?.removeRigidBody(this.rigidBody);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create collision shape for physics object.
|
|
* @internal
|
|
* @param factory Physics engine
|
|
* @param world Physics world
|
|
* @param body RigidBody
|
|
*/
|
|
protected createCollider(
|
|
factory: typeof Rapier,
|
|
world: Rapier.World,
|
|
body?: Rapier.RigidBody
|
|
): Rapier.Collider | undefined {
|
|
return undefined;
|
|
}
|
|
}
|