@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in
261 lines • 9.94 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Mesh, Vector3 } from "three";
import { addComponent } from "../engine/engine_components.js";
import { serializable } from "../engine/engine_serialization_decorator.js";
import { getWorldScale } from "../engine/engine_three_utils.js";
import { validate } from "../engine/engine_util_decorator.js";
import { unwatchWrite, watchWrite } from "../engine/engine_utils.js";
import { NEEDLE_progressive } from "../engine/extensions/NEEDLE_progressive.js";
import { Behaviour } from "./Component.js";
import { Rigidbody } from "./RigidBody.js";
/**
* Collider is the base class for all colliders. A collider is a physical shape that is used to detect collisions with other objects in the scene.
* Colliders are used in combination with a Rigidbody to create physical interactions between objects.
* Colliders are registered with the physics engine when they are enabled and removed when they are disabled.
* @category Physics
* @group Components
*/
export class Collider extends Behaviour {
/** @internal */
get isCollider() {
return true;
}
/**
* The Rigidbody that this collider is attached to.
*/
attachedRigidbody = null;
/**
* When `true` the collider will not be used for collision detection but will still trigger events.
*/
isTrigger = false;
/**
* The physics material that is used for the collider. This material defines physical properties of the collider such as friction and bounciness.
*/
sharedMaterial;
/**
* The layers that the collider is assigned to.
*/
membership = [0];
/**
* The layers that the collider will interact with.
* @inheritdoc
*/
filter;
/** @internal */
awake() {
super.awake();
if (!this.attachedRigidbody)
this.attachedRigidbody = this.gameObject.getComponentInParent(Rigidbody);
}
/** @internal */
start() {
if (!this.attachedRigidbody)
this.attachedRigidbody = this.gameObject.getComponentInParent(Rigidbody);
}
/** @internal */
onEnable() {
// a rigidbody is not assigned if we export an asset
if (!this.attachedRigidbody)
this.attachedRigidbody = this.gameObject.getComponentInParent(Rigidbody);
}
/** @internal */
onDisable() {
this.context.physics.engine?.removeBody(this);
}
/** Returns the underlying physics body from the physics engine (if any) - the component must be enabled and active in the scene */
get body() {
return this.context.physics.engine?.getBody(this);
}
/**
* Apply the collider properties to the physics engine.
*/
updateProperties = () => {
this.context.physics.engine?.updateProperties(this);
};
/** Requests an update of the physics material in the physics engine */
updatePhysicsMaterial() {
this.context.physics.engine?.updatePhysicsMaterial(this);
}
}
__decorate([
serializable(Rigidbody)
], Collider.prototype, "attachedRigidbody", void 0);
__decorate([
serializable()
], Collider.prototype, "isTrigger", void 0);
__decorate([
serializable()
], Collider.prototype, "sharedMaterial", void 0);
__decorate([
serializable()
], Collider.prototype, "membership", void 0);
__decorate([
serializable()
], Collider.prototype, "filter", void 0);
/**
* SphereCollider is a collider that represents a sphere shape.
* @category Physics
* @group Components
*/
export class SphereCollider extends Collider {
radius = .5;
center = new Vector3(0, 0, 0);
onEnable() {
super.onEnable();
this.context.physics.engine?.addSphereCollider(this);
watchWrite(this.gameObject.scale, this.updateProperties);
}
onDisable() {
super.onDisable();
unwatchWrite(this.gameObject.scale, this.updateProperties);
}
onValidate() {
this.updateProperties();
}
}
__decorate([
validate(),
serializable()
], SphereCollider.prototype, "radius", void 0);
__decorate([
serializable(Vector3)
], SphereCollider.prototype, "center", void 0);
/**
* BoxCollider is a collider that represents a box shape.
* @category Physics
* @group Components
*/
export class BoxCollider extends Collider {
static add(obj, opts) {
const collider = new BoxCollider();
if (!obj.geometry.boundingBox)
obj.geometry.computeBoundingBox();
const bb = obj.geometry.boundingBox;
collider.size = bb.getSize(new Vector3()) || new Vector3(1, 1, 1);
collider.center = bb.getCenter(new Vector3()) || new Vector3(0, 0, 0);
addComponent(obj, collider);
if (opts?.rigidbody === true) {
addComponent(obj, Rigidbody, { isKinematic: false });
}
return collider;
}
size = new Vector3(1, 1, 1);
center = new Vector3(0, 0, 0);
onEnable() {
super.onEnable();
this.context.physics.engine?.addBoxCollider(this, this.size);
watchWrite(this.gameObject.scale, this.updateProperties);
}
onDisable() {
super.onDisable();
unwatchWrite(this.gameObject.scale, this.updateProperties);
}
onValidate() {
this.updateProperties();
}
}
__decorate([
validate(),
serializable(Vector3)
], BoxCollider.prototype, "size", void 0);
__decorate([
serializable(Vector3)
], BoxCollider.prototype, "center", void 0);
/**
* MeshCollider is a collider that represents a mesh shape.
* The mesh collider can be used to create a collider from a mesh.
* @category Physics
* @group Components
*/
export class MeshCollider extends Collider {
/**
* The mesh that is used for the collider.
*/
sharedMesh;
/** When `true` the collider won't have holes or entrances.
* If you wan't this mesh collider to be able to *contain* other objects this should be set to `false` */
convex = false;
onEnable() {
super.onEnable();
if (!this.context.physics.engine)
return;
if (!this.sharedMesh?.isMesh) {
// HACK using the renderer mesh
if (this.gameObject instanceof Mesh) {
this.sharedMesh = this.gameObject;
}
}
const LOD = 0;
if (this.sharedMesh?.isMesh) {
this.context.physics.engine.addMeshCollider(this, this.sharedMesh, this.convex, getWorldScale(this.gameObject));
NEEDLE_progressive.assignMeshLOD(this.sharedMesh, LOD).then(res => {
if (res && this.activeAndEnabled && this.context.physics.engine && this.sharedMesh) {
this.context.physics.engine.removeBody(this);
this.sharedMesh.geometry = res;
this.context.physics.engine.addMeshCollider(this, this.sharedMesh, this.convex, getWorldScale(this.gameObject));
}
});
}
else {
const group = this.sharedMesh;
if (group?.isGroup) {
console.warn(`MeshCollider mesh is a group \"${this.sharedMesh?.name || this.gameObject.name}\", adding all children as colliders. This is currently not fully supported (colliders can not be removed from world again)`, this);
const promises = new Array();
for (const ch in group.children) {
const child = group.children[ch];
if (child.isMesh) {
this.context.physics.engine.addMeshCollider(this, child, this.convex, getWorldScale(this.gameObject));
promises.push(NEEDLE_progressive.assignMeshLOD(child, LOD));
}
}
Promise.all(promises).then(res => {
if (res.some(r => r) == false)
return;
this.context.physics.engine?.removeBody(this);
const mesh = new Mesh();
for (const r of res) {
if (r && this.activeAndEnabled) {
mesh.geometry = r;
this.context.physics.engine?.addMeshCollider(this, mesh, this.convex, getWorldScale(this.gameObject));
}
}
});
}
}
}
}
__decorate([
serializable(Mesh)
], MeshCollider.prototype, "sharedMesh", void 0);
__decorate([
serializable()
], MeshCollider.prototype, "convex", void 0);
/**
* CapsuleCollider is a collider that represents a capsule shape.
* @category Physics
* @group Components
*/
export class CapsuleCollider extends Collider {
center = new Vector3(0, 0, 0);
radius = .5;
height = 2;
onEnable() {
super.onEnable();
this.context.physics.engine?.addCapsuleCollider(this, this.height, this.radius);
}
}
__decorate([
serializable(Vector3)
], CapsuleCollider.prototype, "center", void 0);
__decorate([
serializable()
], CapsuleCollider.prototype, "radius", void 0);
__decorate([
serializable()
], CapsuleCollider.prototype, "height", void 0);
//# sourceMappingURL=Collider.js.map