babylon.freeCamera.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. module BABYLON {
  2. export class FreeCamera extends TargetCamera {
  3. @serializeAsVector3()
  4. public ellipsoid = new Vector3(0.5, 1, 0.5);
  5. @serialize()
  6. public checkCollisions = false;
  7. @serialize()
  8. public applyGravity = false;
  9. public inputs : FreeCameraInputsManager;
  10. //-- begin properties for backward compatibility for inputs
  11. public get angularSensibility(): number {
  12. var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
  13. if (mouse)
  14. return mouse.angularSensibility;
  15. return 0;
  16. }
  17. public set angularSensibility(value: number) {
  18. var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
  19. if (mouse)
  20. mouse.angularSensibility = value;
  21. }
  22. public get keysUp(): number[] {
  23. var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  24. if (keyboard)
  25. return keyboard.keysUp;
  26. return [];
  27. }
  28. public set keysUp(value: number[]) {
  29. var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  30. if (keyboard)
  31. keyboard.keysUp = value;
  32. }
  33. public get keysDown(): number[] {
  34. var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  35. if (keyboard)
  36. return keyboard.keysDown;
  37. return [];
  38. }
  39. public set keysDown(value: number[]) {
  40. var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  41. if (keyboard)
  42. keyboard.keysDown = value;
  43. }
  44. public get keysLeft(): number[] {
  45. var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  46. if (keyboard)
  47. return keyboard.keysLeft;
  48. return [];
  49. }
  50. public set keysLeft(value: number[]) {
  51. var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  52. if (keyboard)
  53. keyboard.keysLeft = value;
  54. }
  55. public get keysRight(): number[] {
  56. var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  57. if (keyboard)
  58. return keyboard.keysRight;
  59. return [];
  60. }
  61. public set keysRight(value: number[]) {
  62. var keyboard = <FreeCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  63. if (keyboard)
  64. keyboard.keysRight = value;
  65. }
  66. //-- end properties for backward compatibility for inputs
  67. public onCollide: (collidedMesh: AbstractMesh) => void;
  68. private _collider: Collider;
  69. private _needMoveForGravity = false;
  70. private _oldPosition = Vector3.Zero();
  71. private _diffPosition = Vector3.Zero();
  72. private _newPosition = Vector3.Zero();
  73. public _localDirection: Vector3;
  74. public _transformedDirection: Vector3;
  75. constructor(name: string, position: Vector3, scene: Scene) {
  76. super(name, position, scene);
  77. this.inputs = new FreeCameraInputsManager(this);
  78. this.inputs.addKeyboard().addMouse();
  79. }
  80. // Controls
  81. public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
  82. this.inputs.attachElement(element, noPreventDefault);
  83. }
  84. public detachControl(element: HTMLElement): void {
  85. this.inputs.detachElement(element);
  86. this.cameraDirection = new Vector3(0, 0, 0);
  87. this.cameraRotation = new Vector2(0, 0);
  88. }
  89. // Collisions
  90. private _collisionMask = -1;
  91. public get collisionMask(): number {
  92. return this._collisionMask;
  93. }
  94. public set collisionMask(mask: number) {
  95. this._collisionMask = !isNaN(mask) ? mask : -1;
  96. }
  97. public _collideWithWorld(displacement: Vector3): void {
  98. var globalPosition: Vector3;
  99. if (this.parent) {
  100. globalPosition = Vector3.TransformCoordinates(this.position, this.parent.getWorldMatrix());
  101. } else {
  102. globalPosition = this.position;
  103. }
  104. globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
  105. if (!this._collider) {
  106. this._collider = new Collider();
  107. }
  108. this._collider.radius = this.ellipsoid;
  109. this._collider.collisionMask = this._collisionMask;
  110. //no need for clone, as long as gravity is not on.
  111. var actualDisplacement = displacement;
  112. //add gravity to the direction to prevent the dual-collision checking
  113. if (this.applyGravity) {
  114. //this prevents mending with cameraDirection, a global variable of the free camera class.
  115. actualDisplacement = displacement.add(this.getScene().gravity);
  116. }
  117. this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, actualDisplacement, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
  118. }
  119. private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
  120. //TODO move this to the collision coordinator!
  121. if (this.getScene().workerCollisions)
  122. newPosition.multiplyInPlace(this._collider.radius);
  123. var updatePosition = (newPos: Vector3) => {
  124. this._newPosition.copyFrom(newPos);
  125. this._newPosition.subtractToRef(this._oldPosition, this._diffPosition);
  126. if (this._diffPosition.length() > Engine.CollisionsEpsilon) {
  127. this.position.addInPlace(this._diffPosition);
  128. if (this.onCollide && collidedMesh) {
  129. this.onCollide(collidedMesh);
  130. }
  131. }
  132. }
  133. updatePosition(newPosition);
  134. }
  135. public _checkInputs(): void {
  136. if (!this._localDirection) {
  137. this._localDirection = Vector3.Zero();
  138. this._transformedDirection = Vector3.Zero();
  139. }
  140. this.inputs.checkInputs();
  141. super._checkInputs();
  142. }
  143. public _decideIfNeedsToMove(): boolean {
  144. return this._needMoveForGravity || Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
  145. }
  146. public _updatePosition(): void {
  147. if (this.checkCollisions && this.getScene().collisionsEnabled) {
  148. this._collideWithWorld(this.cameraDirection);
  149. } else {
  150. super._updatePosition();
  151. }
  152. }
  153. public dispose(): void {
  154. this.inputs.clear();
  155. super.dispose();
  156. }
  157. public getClassName(): string {
  158. return "FreeCamera";
  159. }
  160. }
  161. }