123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884 |
- import { Nullable } from "../types";
- import { Logger } from "../Misc/logger";
- import { Vector3 } from "../Maths/math";
- import { AbstractMesh } from "../Meshes/abstractMesh";
- import { Mesh } from "../Meshes/mesh";
- import { SphereBuilder } from "../Meshes/Builders/sphereBuilder";
- import { CylinderBuilder } from "../Meshes/Builders/cylinderBuilder";
- import { Ray } from "../Culling/ray";
- import { Scene } from "../scene";
- import { IPhysicsEngine } from "./IPhysicsEngine";
- import { PhysicsEngine } from "./physicsEngine";
- import { PhysicsImpostor } from "./physicsImpostor";
- /**
- * A helper for physics simulations
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export class PhysicsHelper {
- private _scene: Scene;
- private _physicsEngine: Nullable<IPhysicsEngine>;
- /**
- * Initializes the Physics helper
- * @param scene Babylon.js scene
- */
- constructor(scene: Scene) {
- this._scene = scene;
- this._physicsEngine = this._scene.getPhysicsEngine();
- if (!this._physicsEngine) {
- Logger.Warn('Physics engine not enabled. Please enable the physics before you can use the methods.');
- return;
- }
- }
- /**
- * Applies a radial explosion impulse
- * @param origin the origin of the explosion
- * @param radiusOrEventOptions the radius or the options of radial explosion
- * @param strength the explosion strength
- * @param falloff possible options: Constant & Linear. Defaults to Constant
- * @returns A physics radial explosion event, or null
- */
- public applyRadialExplosionImpulse(origin: Vector3, radiusOrEventOptions: number | PhysicsRadialExplosionEventOptions, strength?: number, falloff?: PhysicsRadialImpulseFalloff): Nullable<PhysicsRadialExplosionEvent> {
- if (!this._physicsEngine) {
- Logger.Warn('Physics engine not enabled. Please enable the physics before you call this method.');
- return null;
- }
- var impostors = this._physicsEngine.getImpostors();
- if (impostors.length === 0) {
- return null;
- }
- if (typeof radiusOrEventOptions === 'number') {
- radiusOrEventOptions = new PhysicsRadialExplosionEventOptions();
- radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
- radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
- radiusOrEventOptions.falloff = falloff || radiusOrEventOptions.falloff;
- }
- var event = new PhysicsRadialExplosionEvent(this, this._scene, radiusOrEventOptions);
- impostors.forEach((impostor) => {
- var impostorForceAndContactPoint = event.getImpostorForceAndContactPoint(impostor, origin);
- if (!impostorForceAndContactPoint) {
- return;
- }
- impostor.applyImpulse(impostorForceAndContactPoint.force, impostorForceAndContactPoint.contactPoint);
- });
- event.dispose(false);
- return event;
- }
- /**
- * Applies a radial explosion force
- * @param origin the origin of the explosion
- * @param radiusOrEventOptions the radius or the options of radial explosion
- * @param strength the explosion strength
- * @param falloff possible options: Constant & Linear. Defaults to Constant
- * @returns A physics radial explosion event, or null
- */
- public applyRadialExplosionForce(origin: Vector3, radiusOrEventOptions: number | PhysicsRadialExplosionEventOptions, strength?: number, falloff?: PhysicsRadialImpulseFalloff): Nullable<PhysicsRadialExplosionEvent> {
- if (!this._physicsEngine) {
- Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
- return null;
- }
- var impostors = this._physicsEngine.getImpostors();
- if (impostors.length === 0) {
- return null;
- }
- if (typeof radiusOrEventOptions === 'number') {
- radiusOrEventOptions = new PhysicsRadialExplosionEventOptions();
- radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
- radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
- radiusOrEventOptions.falloff = falloff || radiusOrEventOptions.falloff;
- }
- var event = new PhysicsRadialExplosionEvent(this, this._scene, radiusOrEventOptions);
- impostors.forEach((impostor) => {
- var impostorForceAndContactPoint = event.getImpostorForceAndContactPoint(impostor, origin);
- if (!impostorForceAndContactPoint) {
- return;
- }
- impostor.applyForce(impostorForceAndContactPoint.force, impostorForceAndContactPoint.contactPoint);
- });
- event.dispose(false);
- return event;
- }
- /**
- * Creates a gravitational field
- * @param origin the origin of the explosion
- * @param radiusOrEventOptions the radius or the options of radial explosion
- * @param strength the explosion strength
- * @param falloff possible options: Constant & Linear. Defaults to Constant
- * @returns A physics gravitational field event, or null
- */
- public gravitationalField(origin: Vector3, radiusOrEventOptions: number | PhysicsRadialExplosionEventOptions, strength?: number, falloff?: PhysicsRadialImpulseFalloff): Nullable<PhysicsGravitationalFieldEvent> {
- if (!this._physicsEngine) {
- Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
- return null;
- }
- var impostors = this._physicsEngine.getImpostors();
- if (impostors.length === 0) {
- return null;
- }
- if (typeof radiusOrEventOptions === 'number') {
- radiusOrEventOptions = new PhysicsRadialExplosionEventOptions();
- radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
- radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
- radiusOrEventOptions.falloff = falloff || radiusOrEventOptions.falloff;
- }
- var event = new PhysicsGravitationalFieldEvent(this, this._scene, origin, radiusOrEventOptions);
- event.dispose(false);
- return event;
- }
- /**
- * Creates a physics updraft event
- * @param origin the origin of the updraft
- * @param radiusOrEventOptions the radius or the options of the updraft
- * @param strength the strength of the updraft
- * @param height the height of the updraft
- * @param updraftMode possible options: Center & Perpendicular. Defaults to Center
- * @returns A physics updraft event, or null
- */
- public updraft(origin: Vector3, radiusOrEventOptions: number | PhysicsUpdraftEventOptions, strength?: number, height?: number, updraftMode?: PhysicsUpdraftMode): Nullable<PhysicsUpdraftEvent> {
- if (!this._physicsEngine) {
- Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
- return null;
- }
- if (this._physicsEngine.getImpostors().length === 0) {
- return null;
- }
- if (typeof radiusOrEventOptions === 'number') {
- radiusOrEventOptions = new PhysicsUpdraftEventOptions();
- radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
- radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
- radiusOrEventOptions.height = height || radiusOrEventOptions.height;
- radiusOrEventOptions.updraftMode = updraftMode || radiusOrEventOptions.updraftMode;
- }
- var event = new PhysicsUpdraftEvent(this, this._scene, origin, radiusOrEventOptions);
- event.dispose(false);
- return event;
- }
- /**
- * Creates a physics vortex event
- * @param origin the of the vortex
- * @param radiusOrEventOptions the radius or the options of the vortex
- * @param strength the strength of the vortex
- * @param height the height of the vortex
- * @returns a Physics vortex event, or null
- * A physics vortex event or null
- */
- public vortex(origin: Vector3, radiusOrEventOptions: number | PhysicsVortexEventOptions, strength?: number, height?: number): Nullable<PhysicsVortexEvent> {
- if (!this._physicsEngine) {
- Logger.Warn('Physics engine not enabled. Please enable the physics before you call the PhysicsHelper.');
- return null;
- }
- if (this._physicsEngine.getImpostors().length === 0) {
- return null;
- }
- if (typeof radiusOrEventOptions === 'number') {
- radiusOrEventOptions = new PhysicsVortexEventOptions();
- radiusOrEventOptions.radius = <number><any>radiusOrEventOptions;
- radiusOrEventOptions.strength = strength || radiusOrEventOptions.strength;
- radiusOrEventOptions.height = height || radiusOrEventOptions.height;
- }
- var event = new PhysicsVortexEvent(this, this._scene, origin, radiusOrEventOptions);
- event.dispose(false);
- return event;
- }
- }
- /**
- * Represents a physics radial explosion event
- */
- class PhysicsRadialExplosionEvent {
- private _sphere: Mesh; // create a sphere, so we can get the intersecting meshes inside
- private _dataFetched: boolean = false; // check if the data has been fetched. If not, do cleanup
- /**
- * Initializes a radial explosioin event
- * @param _physicsHelper A physics helper
- * @param _scene BabylonJS scene
- * @param _options The options for the vortex event
- */
- constructor(private _physicsHelper: PhysicsHelper, private _scene: Scene, private _options: PhysicsRadialExplosionEventOptions) {
- this._options = {...(new PhysicsRadialExplosionEventOptions()), ...this._options};
- }
- /**
- * Returns the data related to the radial explosion event (sphere).
- * @returns The radial explosion event data
- */
- public getData(): PhysicsRadialExplosionEventData {
- this._dataFetched = true;
- return {
- sphere: this._sphere,
- };
- }
- /**
- * Returns the force and contact point of the impostor or false, if the impostor is not affected by the force/impulse.
- * @param impostor A physics imposter
- * @param origin the origin of the explosion
- * @returns {Nullable<PhysicsForceAndContactPoint>} A physics force and contact point, or null
- */
- public getImpostorForceAndContactPoint(impostor: PhysicsImpostor, origin: Vector3): Nullable<PhysicsForceAndContactPoint> {
- if (impostor.mass === 0) {
- return null;
- }
- if (!this._intersectsWithSphere(impostor, origin, this._options.radius)) {
- return null;
- }
- if (impostor.object.getClassName() !== 'Mesh' && impostor.object.getClassName() !== 'InstancedMesh') {
- return null;
- }
- var impostorObjectCenter = impostor.getObjectCenter();
- var direction = impostorObjectCenter.subtract(origin);
- var ray = new Ray(origin, direction, this._options.radius);
- var hit = ray.intersectsMesh(<AbstractMesh>impostor.object);
- var contactPoint = hit.pickedPoint;
- if (!contactPoint) {
- return null;
- }
- var distanceFromOrigin = Vector3.Distance(origin, contactPoint);
- if (distanceFromOrigin > this._options.radius) {
- return null;
- }
- var multiplier = this._options.falloff === PhysicsRadialImpulseFalloff.Constant
- ? this._options.strength
- : this._options.strength * (1 - (distanceFromOrigin / this._options.radius));
- var force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
- return { force: force, contactPoint: contactPoint };
- }
- /**
- * Disposes the sphere.
- * @param force Specifies if the sphere should be disposed by force
- */
- public dispose(force: boolean = true) {
- if (force) {
- this._sphere.dispose();
- } else {
- setTimeout(() => {
- if (!this._dataFetched) {
- this._sphere.dispose();
- }
- }, 0);
- }
- }
- /*** Helpers ***/
- private _prepareSphere(): void {
- if (!this._sphere) {
- this._sphere = SphereBuilder.CreateSphere("radialExplosionEventSphere", this._options.sphere, this._scene);
- this._sphere.isVisible = false;
- }
- }
- private _intersectsWithSphere(impostor: PhysicsImpostor, origin: Vector3, radius: number): boolean {
- var impostorObject = <AbstractMesh>impostor.object;
- this._prepareSphere();
- this._sphere.position = origin;
- this._sphere.scaling = new Vector3(radius * 2, radius * 2, radius * 2);
- this._sphere._updateBoundingInfo();
- this._sphere.computeWorldMatrix(true);
- return this._sphere.intersectsMesh(impostorObject, true);
- }
- }
- /**
- * Represents a gravitational field event
- */
- class PhysicsGravitationalFieldEvent {
- private _tickCallback: any;
- private _sphere: Mesh;
- private _dataFetched: boolean = false; // check if the has been fetched the data. If not, do cleanup
- /**
- * Initializes the physics gravitational field event
- * @param _physicsHelper A physics helper
- * @param _scene BabylonJS scene
- * @param _origin The origin position of the gravitational field event
- * @param _options The options for the vortex event
- */
- constructor(private _physicsHelper: PhysicsHelper, private _scene: Scene, private _origin: Vector3, private _options: PhysicsRadialExplosionEventOptions) {
- this._options = {...(new PhysicsRadialExplosionEventOptions()), ...this._options};
- this._tickCallback = this._tick.bind(this);
- this._options.strength = this._options.strength * -1;
- }
- /**
- * Returns the data related to the gravitational field event (sphere).
- * @returns A gravitational field event
- */
- public getData(): PhysicsGravitationalFieldEventData {
- this._dataFetched = true;
- return {
- sphere: this._sphere,
- };
- }
- /**
- * Enables the gravitational field.
- */
- public enable() {
- this._tickCallback.call(this);
- this._scene.registerBeforeRender(this._tickCallback);
- }
- /**
- * Disables the gravitational field.
- */
- public disable() {
- this._scene.unregisterBeforeRender(this._tickCallback);
- }
- /**
- * Disposes the sphere.
- * @param force The force to dispose from the gravitational field event
- */
- public dispose(force: boolean = true) {
- if (force) {
- this._sphere.dispose();
- } else {
- setTimeout(() => {
- if (!this._dataFetched) {
- this._sphere.dispose();
- }
- }, 0);
- }
- }
- private _tick() {
- // Since the params won't change, we fetch the event only once
- if (this._sphere) {
- this._physicsHelper.applyRadialExplosionForce(this._origin, this._options);
- } else {
- var radialExplosionEvent = this._physicsHelper.applyRadialExplosionForce(this._origin, this._options);
- if (radialExplosionEvent) {
- this._sphere = <Mesh>radialExplosionEvent.getData().sphere.clone('radialExplosionEventSphereClone');
- }
- }
- }
- }
- /**
- * Represents a physics updraft event
- */
- class PhysicsUpdraftEvent {
- private _physicsEngine: PhysicsEngine;
- private _originTop: Vector3 = Vector3.Zero(); // the most upper part of the cylinder
- private _originDirection: Vector3 = Vector3.Zero(); // used if the updraftMode is perpendicular
- private _tickCallback: any;
- private _cylinder: Mesh;
- private _cylinderPosition: Vector3 = Vector3.Zero(); // to keep the cylinders position, because normally the origin is in the center and not on the bottom
- private _dataFetched: boolean = false; // check if the has been fetched the data. If not, do cleanup
- /**
- * Initializes the physics updraft event
- * @param _physicsHelper A physics helper
- * @param _scene BabylonJS scene
- * @param _origin The origin position of the updraft
- * @param _options The options for the updraft event
- */
- constructor(private _physicsHelper: PhysicsHelper, private _scene: Scene, private _origin: Vector3, private _options: PhysicsUpdraftEventOptions) {
- this._physicsEngine = <PhysicsEngine>this._scene.getPhysicsEngine();
- this._options = {...(new PhysicsUpdraftEventOptions()), ...this._options};
- this._origin.addToRef(new Vector3(0, this._options.height / 2, 0), this._cylinderPosition);
- this._origin.addToRef(new Vector3(0, this._options.height, 0), this._originTop);
- if (this._options.updraftMode === PhysicsUpdraftMode.Perpendicular) {
- this._originDirection = this._origin.subtract(this._originTop).normalize();
- }
- this._tickCallback = this._tick.bind(this);
- this._prepareCylinder();
- }
- /**
- * Returns the data related to the updraft event (cylinder).
- * @returns A physics updraft event
- */
- public getData(): PhysicsUpdraftEventData {
- this._dataFetched = true;
- return {
- cylinder: this._cylinder,
- };
- }
- /**
- * Enables the updraft.
- */
- public enable() {
- this._tickCallback.call(this);
- this._scene.registerBeforeRender(this._tickCallback);
- }
- /**
- * Disables the updraft.
- */
- public disable() {
- this._scene.unregisterBeforeRender(this._tickCallback);
- }
- /**
- * Disposes the cylinder.
- * @param force Specifies if the updraft should be disposed by force
- */
- public dispose(force: boolean = true) {
- if (!this._cylinder) {
- return;
- }
- if (force) {
- this._cylinder.dispose();
- } else {
- setTimeout(() => {
- if (!this._dataFetched) {
- this._cylinder.dispose();
- }
- }, 0);
- }
- }
- private getImpostorForceAndContactPoint(impostor: PhysicsImpostor): Nullable<PhysicsForceAndContactPoint> {
- if (impostor.mass === 0) {
- return null;
- }
- if (!this._intersectsWithCylinder(impostor)) {
- return null;
- }
- var impostorObjectCenter = impostor.getObjectCenter();
- if (this._options.updraftMode === PhysicsUpdraftMode.Perpendicular) {
- var direction = this._originDirection;
- } else {
- var direction = impostorObjectCenter.subtract(this._originTop);
- }
- var multiplier = this._options.strength * -1;
- var force = direction.multiplyByFloats(multiplier, multiplier, multiplier);
- return { force: force, contactPoint: impostorObjectCenter };
- }
- private _tick() {
- this._physicsEngine.getImpostors().forEach((impostor) => {
- var impostorForceAndContactPoint = this.getImpostorForceAndContactPoint(impostor);
- if (!impostorForceAndContactPoint) {
- return;
- }
- impostor.applyForce(impostorForceAndContactPoint.force, impostorForceAndContactPoint.contactPoint);
- });
- }
- /*** Helpers ***/
- private _prepareCylinder(): void {
- if (!this._cylinder) {
- this._cylinder = CylinderBuilder.CreateCylinder("updraftEventCylinder", {
- height: this._options.height,
- diameter: this._options.radius * 2,
- }, this._scene);
- this._cylinder.isVisible = false;
- }
- }
- private _intersectsWithCylinder(impostor: PhysicsImpostor): boolean {
- var impostorObject = <AbstractMesh>impostor.object;
- this._cylinder.position = this._cylinderPosition;
- return this._cylinder.intersectsMesh(impostorObject, true);
- }
- }
- /**
- * Represents a physics vortex event
- */
- class PhysicsVortexEvent {
- private _physicsEngine: PhysicsEngine;
- private _originTop: Vector3 = Vector3.Zero(); // the most upper part of the cylinder
- private _tickCallback: any;
- private _cylinder: Mesh;
- private _cylinderPosition: Vector3 = Vector3.Zero(); // to keep the cylinders position, because normally the origin is in the center and not on the bottom
- private _dataFetched: boolean = false; // check if the has been fetched the data. If not, do cleanup
- /**
- * Initializes the physics vortex event
- * @param _physicsHelper A physics helper
- * @param _scene The BabylonJS scene
- * @param _origin The origin position of the vortex
- * @param _options The options for the vortex event
- */
- constructor(private _physicsHelper: PhysicsHelper, private _scene: Scene, private _origin: Vector3, private _options: PhysicsVortexEventOptions) {
- this._physicsEngine = <PhysicsEngine>this._scene.getPhysicsEngine();
- this._options = {...(new PhysicsVortexEventOptions()), ...this._options};
- this._origin.addToRef(new Vector3(0, this._options.height / 2, 0), this._cylinderPosition);
- this._origin.addToRef(new Vector3(0, this._options.height, 0), this._originTop);
- this._tickCallback = this._tick.bind(this);
- this._prepareCylinder();
- }
- /**
- * Returns the data related to the vortex event (cylinder).
- * @returns The physics vortex event data
- */
- public getData(): PhysicsVortexEventData {
- this._dataFetched = true;
- return {
- cylinder: this._cylinder,
- };
- }
- /**
- * Enables the vortex.
- */
- public enable() {
- this._tickCallback.call(this);
- this._scene.registerBeforeRender(this._tickCallback);
- }
- /**
- * Disables the cortex.
- */
- public disable() {
- this._scene.unregisterBeforeRender(this._tickCallback);
- }
- /**
- * Disposes the sphere.
- * @param force
- */
- public dispose(force: boolean = true) {
- if (force) {
- this._cylinder.dispose();
- } else {
- setTimeout(() => {
- if (!this._dataFetched) {
- this._cylinder.dispose();
- }
- }, 0);
- }
- }
- private getImpostorForceAndContactPoint(impostor: PhysicsImpostor): Nullable<PhysicsForceAndContactPoint> {
- if (impostor.mass === 0) {
- return null;
- }
- if (!this._intersectsWithCylinder(impostor)) {
- return null;
- }
- if (impostor.object.getClassName() !== 'Mesh' && impostor.object.getClassName() !== 'InstancedMesh') {
- return null;
- }
- var impostorObjectCenter = impostor.getObjectCenter();
- var originOnPlane = new Vector3(this._origin.x, impostorObjectCenter.y, this._origin.z); // the distance to the origin as if both objects were on a plane (Y-axis)
- var originToImpostorDirection = impostorObjectCenter.subtract(originOnPlane);
- var ray = new Ray(originOnPlane, originToImpostorDirection, this._options.radius);
- var hit = ray.intersectsMesh(<AbstractMesh>impostor.object);
- var contactPoint = hit.pickedPoint;
- if (!contactPoint) {
- return null;
- }
- var absoluteDistanceFromOrigin = hit.distance / this._options.radius;
- var directionToOrigin = contactPoint.normalize();
- if (absoluteDistanceFromOrigin > this._options.centripetalForceThreshold) {
- directionToOrigin = directionToOrigin.negate();
- }
- if (absoluteDistanceFromOrigin > this._options.centripetalForceThreshold) {
- var forceX = directionToOrigin.x * this._options.centripetalForceMultiplier;
- var forceY = directionToOrigin.y * this._options.updraftForceMultiplier;
- var forceZ = directionToOrigin.z * this._options.centripetalForceMultiplier;
- } else {
- var perpendicularDirection = Vector3.Cross(originOnPlane, impostorObjectCenter).normalize();
- var forceX = (perpendicularDirection.x + directionToOrigin.x) * this._options.centrifugalForceMultiplier;
- var forceY = this._originTop.y * this._options.updraftForceMultiplier;
- var forceZ = (perpendicularDirection.z + directionToOrigin.z) * this._options.centrifugalForceMultiplier;
- }
- var force = new Vector3(forceX, forceY, forceZ);
- force = force.multiplyByFloats(this._options.strength, this._options.strength, this._options.strength);
- return { force: force, contactPoint: impostorObjectCenter };
- }
- private _tick() {
- this._physicsEngine.getImpostors().forEach((impostor) => {
- var impostorForceAndContactPoint = this.getImpostorForceAndContactPoint(impostor);
- if (!impostorForceAndContactPoint) {
- return;
- }
- impostor.applyForce(impostorForceAndContactPoint.force, impostorForceAndContactPoint.contactPoint);
- });
- }
- /*** Helpers ***/
- private _prepareCylinder(): void {
- if (!this._cylinder) {
- this._cylinder = CylinderBuilder.CreateCylinder("vortexEventCylinder", {
- height: this._options.height,
- diameter: this._options.radius * 2,
- }, this._scene);
- this._cylinder.isVisible = false;
- }
- }
- private _intersectsWithCylinder(impostor: PhysicsImpostor): boolean {
- var impostorObject = <AbstractMesh>impostor.object;
- this._cylinder.position = this._cylinderPosition;
- return this._cylinder.intersectsMesh(impostorObject, true);
- }
- }
- /**
- * Options fot the radial explosion event
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export class PhysicsRadialExplosionEventOptions {
- /**
- * The radius of the sphere for the radial explosion.
- */
- radius: number = 5;
- /**
- * The strenth of the explosion.
- */
- strength: number = 10;
- /**
- * The strenght of the force in correspondence to the distance of the affected object
- */
- falloff: PhysicsRadialImpulseFalloff = PhysicsRadialImpulseFalloff.Constant;
- /**
- * Sphere options for the radial explosion.
- */
- sphere: { segments: number, diameter: number } = { segments: 32, diameter: 1 };
- }
- /**
- * Options fot the updraft event
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export class PhysicsUpdraftEventOptions {
- /**
- * The radius of the cylinder for the vortex
- */
- radius: number = 5;
- /**
- * The strenth of the updraft.
- */
- strength: number = 10;
- /**
- * The height of the cylinder for the updraft.
- */
- height: number = 10;
- /**
- * The mode for the the updraft.
- */
- updraftMode: PhysicsUpdraftMode = PhysicsUpdraftMode.Center;
- }
- /**
- * Options fot the vortex event
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export class PhysicsVortexEventOptions {
- /**
- * The radius of the cylinder for the vortex
- */
- radius: number = 5;
- /**
- * The strenth of the vortex.
- */
- strength: number = 10;
- /**
- * The height of the cylinder for the vortex.
- */
- height: number = 10;
- /**
- * At which distance, relative to the radius the centripetal forces should kick in? Range: 0-1
- */
- centripetalForceThreshold: number = 0.7;
- /**
- * This multiplier determines with how much force the objects will be pushed sideways/around the vortex, when below the treshold.
- */
- centripetalForceMultiplier: number = 5;
- /**
- * This multiplier determines with how much force the objects will be pushed sideways/around the vortex, when above the treshold.
- */
- centrifugalForceMultiplier: number = 0.5;
- /**
- * This multiplier determines with how much force the objects will be pushed upwards, when in the vortex.
- */
- updraftForceMultiplier: number = 0.02;
- }
- /**
- * The strenght of the force in correspondence to the distance of the affected object
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export enum PhysicsRadialImpulseFalloff {
- /** Defines that impulse is constant in strength across it's whole radius */
- Constant,
- /** Defines that impulse gets weaker if it's further from the origin */
- Linear
- }
- /**
- * The strength of the force in correspondence to the distance of the affected object
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export enum PhysicsUpdraftMode {
- /** Defines that the upstream forces will pull towards the top center of the cylinder */
- Center,
- /** Defines that once a impostor is inside the cylinder, it will shoot out perpendicular from the ground of the cylinder */
- Perpendicular
- }
- /**
- * Interface for a physics force and contact point
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export interface PhysicsForceAndContactPoint {
- /**
- * The force applied at the contact point
- */
- force: Vector3;
- /**
- * The contact point
- */
- contactPoint: Vector3;
- }
- /**
- * Interface for radial explosion event data
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export interface PhysicsRadialExplosionEventData {
- /**
- * A sphere used for the radial explosion event
- */
- sphere: Mesh;
- }
- /**
- * Interface for gravitational field event data
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export interface PhysicsGravitationalFieldEventData {
- /**
- * A sphere mesh used for the gravitational field event
- */
- sphere: Mesh;
- }
- /**
- * Interface for updraft event data
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export interface PhysicsUpdraftEventData {
- /**
- * A cylinder used for the updraft event
- */
- cylinder: Mesh;
- }
- /**
- * Interface for vortex event data
- * @see https://doc.babylonjs.com/how_to/using_the_physics_engine#further-functionality-of-the-impostor-class
- */
- export interface PhysicsVortexEventData {
- /**
- * A cylinder used for the vortex event
- */
- cylinder: Mesh;
- }
|