physicsEngineComponent.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import { Nullable } from "../types";
  2. import { Logger } from "../Misc/logger";
  3. import { Observable, Observer } from "../Misc/observable";
  4. import { Vector3 } from "../Maths/math";
  5. import { Mesh } from "../Meshes/mesh";
  6. import { AbstractMesh } from "../Meshes/abstractMesh";
  7. import { ISceneComponent, SceneComponentConstants } from "../sceneComponent";
  8. import { Scene } from "../scene";
  9. import { Node } from "../node";
  10. import { IPhysicsEngine, IPhysicsEnginePlugin } from "./IPhysicsEngine";
  11. import { PhysicsEngine } from "./physicsEngine";
  12. import { PhysicsImpostor } from "./physicsImpostor";
  13. import { PhysicsJoint } from "./physicsJoint";
  14. declare module "../scene" {
  15. export interface Scene {
  16. /** @hidden (Backing field) */
  17. _physicsEngine: Nullable<IPhysicsEngine>;
  18. /**
  19. * Gets the current physics engine
  20. * @returns a IPhysicsEngine or null if none attached
  21. */
  22. getPhysicsEngine(): Nullable<IPhysicsEngine>;
  23. /**
  24. * Enables physics to the current scene
  25. * @param gravity defines the scene's gravity for the physics engine
  26. * @param plugin defines the physics engine to be used. defaults to OimoJS.
  27. * @return a boolean indicating if the physics engine was initialized
  28. */
  29. enablePhysics(gravity: Nullable<Vector3>, plugin?: IPhysicsEnginePlugin): boolean;
  30. /**
  31. * Disables and disposes the physics engine associated with the scene
  32. */
  33. disablePhysicsEngine(): void;
  34. /**
  35. * Gets a boolean indicating if there is an active physics engine
  36. * @returns a boolean indicating if there is an active physics engine
  37. */
  38. isPhysicsEnabled(): boolean;
  39. /**
  40. * Deletes a physics compound impostor
  41. * @param compound defines the compound to delete
  42. */
  43. deleteCompoundImpostor(compound: any): void;
  44. /**
  45. * An event triggered when physic simulation is about to be run
  46. */
  47. onBeforePhysicsObservable: Observable<Scene>;
  48. /**
  49. * An event triggered when physic simulation has been done
  50. */
  51. onAfterPhysicsObservable: Observable<Scene>;
  52. }
  53. }
  54. /**
  55. * Gets the current physics engine
  56. * @returns a IPhysicsEngine or null if none attached
  57. */
  58. Scene.prototype.getPhysicsEngine = function(): Nullable<IPhysicsEngine> {
  59. return this._physicsEngine;
  60. };
  61. /**
  62. * Enables physics to the current scene
  63. * @param gravity defines the scene's gravity for the physics engine
  64. * @param plugin defines the physics engine to be used. defaults to OimoJS.
  65. * @return a boolean indicating if the physics engine was initialized
  66. */
  67. Scene.prototype.enablePhysics = function(gravity: Nullable<Vector3> = null, plugin?: IPhysicsEnginePlugin): boolean {
  68. if (this._physicsEngine) {
  69. return true;
  70. }
  71. // Register the component to the scene
  72. let component = this._getComponent(SceneComponentConstants.NAME_PHYSICSENGINE) as PhysicsEngineSceneComponent;
  73. if (!component) {
  74. component = new PhysicsEngineSceneComponent(this);
  75. this._addComponent(component);
  76. }
  77. try {
  78. this._physicsEngine = new PhysicsEngine(gravity, plugin);
  79. return true;
  80. } catch (e) {
  81. Logger.Error(e.message);
  82. return false;
  83. }
  84. };
  85. /**
  86. * Disables and disposes the physics engine associated with the scene
  87. */
  88. Scene.prototype.disablePhysicsEngine = function(): void {
  89. if (!this._physicsEngine) {
  90. return;
  91. }
  92. this._physicsEngine.dispose();
  93. this._physicsEngine = null;
  94. };
  95. /**
  96. * Gets a boolean indicating if there is an active physics engine
  97. * @returns a boolean indicating if there is an active physics engine
  98. */
  99. Scene.prototype.isPhysicsEnabled = function(): boolean {
  100. return this._physicsEngine !== undefined;
  101. };
  102. /**
  103. * Deletes a physics compound impostor
  104. * @param compound defines the compound to delete
  105. */
  106. Scene.prototype.deleteCompoundImpostor = function(compound: any): void {
  107. var mesh: AbstractMesh = compound.parts[0].mesh;
  108. if (mesh.physicsImpostor) {
  109. mesh.physicsImpostor.dispose(/*true*/);
  110. mesh.physicsImpostor = null;
  111. }
  112. };
  113. /** @hidden */
  114. Scene.prototype._advancePhysicsEngineStep = function(step: number) {
  115. if (this._physicsEngine) {
  116. this.onBeforePhysicsObservable.notifyObservers(this);
  117. this._physicsEngine._step(step / 1000);
  118. this.onAfterPhysicsObservable.notifyObservers(this);
  119. }
  120. };
  121. declare module "../Meshes/abstractMesh" {
  122. export interface AbstractMesh {
  123. /** @hidden */
  124. _physicsImpostor: Nullable<PhysicsImpostor>;
  125. /**
  126. * Gets or sets impostor used for physic simulation
  127. * @see http://doc.babylonjs.com/features/physics_engine
  128. */
  129. physicsImpostor: Nullable<PhysicsImpostor>;
  130. /**
  131. * Gets the current physics impostor
  132. * @see http://doc.babylonjs.com/features/physics_engine
  133. * @returns a physics impostor or null
  134. */
  135. getPhysicsImpostor(): Nullable<PhysicsImpostor>;
  136. /** Apply a physic impulse to the mesh
  137. * @param force defines the force to apply
  138. * @param contactPoint defines where to apply the force
  139. * @returns the current mesh
  140. * @see http://doc.babylonjs.com/how_to/using_the_physics_engine
  141. */
  142. applyImpulse(force: Vector3, contactPoint: Vector3): AbstractMesh;
  143. /**
  144. * Creates a physic joint between two meshes
  145. * @param otherMesh defines the other mesh to use
  146. * @param pivot1 defines the pivot to use on this mesh
  147. * @param pivot2 defines the pivot to use on the other mesh
  148. * @param options defines additional options (can be plugin dependent)
  149. * @returns the current mesh
  150. * @see https://www.babylonjs-playground.com/#0BS5U0#0
  151. */
  152. setPhysicsLinkWith(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3, options?: any): AbstractMesh;
  153. /** @hidden */
  154. _disposePhysicsObserver: Nullable<Observer<Node>>;
  155. }
  156. }
  157. Object.defineProperty(AbstractMesh.prototype, "physicsImpostor", {
  158. get: function(this: AbstractMesh) {
  159. return this._physicsImpostor;
  160. },
  161. set: function(this: AbstractMesh, value: Nullable<PhysicsImpostor>) {
  162. if (this._physicsImpostor === value) {
  163. return;
  164. }
  165. if (this._disposePhysicsObserver) {
  166. this.onDisposeObservable.remove(this._disposePhysicsObserver);
  167. }
  168. this._physicsImpostor = value;
  169. if (value) {
  170. this._disposePhysicsObserver = this.onDisposeObservable.add(() => {
  171. // Physics
  172. if (this.physicsImpostor) {
  173. this.physicsImpostor.dispose(/*!doNotRecurse*/);
  174. this.physicsImpostor = null;
  175. }
  176. });
  177. }
  178. },
  179. enumerable: true,
  180. configurable: true
  181. });
  182. /**
  183. * Gets the current physics impostor
  184. * @see http://doc.babylonjs.com/features/physics_engine
  185. * @returns a physics impostor or null
  186. */
  187. AbstractMesh.prototype.getPhysicsImpostor = function(): Nullable<PhysicsImpostor> {
  188. return this.physicsImpostor;
  189. };
  190. /**
  191. * Apply a physic impulse to the mesh
  192. * @param force defines the force to apply
  193. * @param contactPoint defines where to apply the force
  194. * @returns the current mesh
  195. * @see http://doc.babylonjs.com/how_to/using_the_physics_engine
  196. */
  197. AbstractMesh.prototype.applyImpulse = function(force: Vector3, contactPoint: Vector3): AbstractMesh {
  198. if (!this.physicsImpostor) {
  199. return this;
  200. }
  201. this.physicsImpostor.applyImpulse(force, contactPoint);
  202. return this;
  203. };
  204. /**
  205. * Creates a physic joint between two meshes
  206. * @param otherMesh defines the other mesh to use
  207. * @param pivot1 defines the pivot to use on this mesh
  208. * @param pivot2 defines the pivot to use on the other mesh
  209. * @param options defines additional options (can be plugin dependent)
  210. * @returns the current mesh
  211. * @see https://www.babylonjs-playground.com/#0BS5U0#0
  212. */
  213. AbstractMesh.prototype.setPhysicsLinkWith = function(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3, options?: any): AbstractMesh {
  214. if (!this.physicsImpostor || !otherMesh.physicsImpostor) {
  215. return this;
  216. }
  217. this.physicsImpostor.createJoint(otherMesh.physicsImpostor, PhysicsJoint.HingeJoint, {
  218. mainPivot: pivot1,
  219. connectedPivot: pivot2,
  220. nativeParams: options
  221. });
  222. return this;
  223. };
  224. /**
  225. * Defines the physics engine scene component responsible to manage a physics engine
  226. */
  227. export class PhysicsEngineSceneComponent implements ISceneComponent {
  228. /**
  229. * The component name helpful to identify the component in the list of scene components.
  230. */
  231. public readonly name = SceneComponentConstants.NAME_PHYSICSENGINE;
  232. /**
  233. * The scene the component belongs to.
  234. */
  235. public scene: Scene;
  236. /**
  237. * Creates a new instance of the component for the given scene
  238. * @param scene Defines the scene to register the component in
  239. */
  240. constructor(scene: Scene) {
  241. this.scene = scene;
  242. this.scene.onBeforePhysicsObservable = new Observable<Scene>();
  243. this.scene.onAfterPhysicsObservable = new Observable<Scene>();
  244. // Replace the function used to get the deterministic frame time
  245. this.scene.getDeterministicFrameTime = () => {
  246. if (this.scene._physicsEngine) {
  247. return this.scene._physicsEngine.getTimeStep() * 1000;
  248. }
  249. return 1000.0 / 60.0;
  250. };
  251. }
  252. /**
  253. * Registers the component in a given scene
  254. */
  255. public register(): void {
  256. }
  257. /**
  258. * Rebuilds the elements related to this component in case of
  259. * context lost for instance.
  260. */
  261. public rebuild(): void {
  262. // Nothing to do for this component
  263. }
  264. /**
  265. * Disposes the component and the associated ressources
  266. */
  267. public dispose(): void {
  268. this.scene.onBeforePhysicsObservable.clear();
  269. this.scene.onAfterPhysicsObservable.clear();
  270. if (this.scene._physicsEngine) {
  271. this.scene.disablePhysicsEngine();
  272. }
  273. }
  274. }