RapierBodyWireframe.re.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import * as RE from 'rogue-engine';
  2. import * as THREE from 'three';
  3. import RapierCollider from '../Colliders/RapierCollider';
  4. import RAPIER from '@dimforge/rapier3d-compat';
  5. import RapierBody from '../RapierBody.re';
  6. import RogueRapier from '@RE/RogueEngine/rogue-rapier/Lib/RogueRapier';
  7. export default class RapierBodyWireframe extends RE.Component {
  8. static isEditorComponent = true;
  9. selectedObjects: THREE.Object3D[] = [];
  10. colliders: (RapierCollider | RapierBody)[] = [];
  11. lines = new THREE.LineSegments(
  12. new THREE.BufferGeometry(),
  13. new THREE.LineBasicMaterial({ color: new THREE.Color("#00FF00") })
  14. );
  15. world: RAPIER.World;
  16. initializedPhysics = false;
  17. private handleOnComponentAdded = { stop: () => { } };
  18. private handleOnComponentRemoved = { stop: () => { } };
  19. private handleOnPlay = { stop: () => { } };
  20. private resetHandler = (component: RE.Component) => {
  21. component instanceof RapierCollider && this.setupImpostors();
  22. }
  23. async initPhysics() {
  24. await RAPIER.init();
  25. }
  26. start() {
  27. this.initializedPhysics = false;
  28. this.lines.geometry.computeBoundingSphere();
  29. this.lines.frustumCulled = false;
  30. this.initPhysics().then(() => {
  31. this.world = new RAPIER.World({x: 0, y: 0, z: 0});
  32. RogueRapier.world = this.world;
  33. this.initializedPhysics = true;
  34. });
  35. RE.App.currentScene.remove(this.lines);
  36. this.lines.userData.isEditorObject = true;
  37. RE.App.currentScene.add(this.lines);
  38. this.handleOnComponentAdded.stop();
  39. this.handleOnComponentRemoved.stop();
  40. this.handleOnPlay.stop();
  41. this.handleOnComponentAdded = RE.onComponentAdded(this.resetHandler);
  42. this.handleOnComponentRemoved = RE.onComponentRemoved(this.resetHandler);
  43. this.handleOnPlay = RE.Runtime.onPlay(() => {
  44. this.handleOnComponentAdded.stop();
  45. this.handleOnComponentRemoved.stop();
  46. });
  47. }
  48. resetComponents() {
  49. this.selectedObjects.forEach(selected => {
  50. if (!selected) return;
  51. selected.traverse(object => {
  52. const objComponents = RE.components[object.uuid];
  53. if (!objComponents) return;
  54. objComponents.forEach(component => {
  55. if (component instanceof RapierBody || component instanceof RapierCollider) {
  56. component.initialized = false;
  57. }
  58. });
  59. });
  60. });
  61. }
  62. afterUpdate() {
  63. this.lines.visible = false;
  64. if (!this.initializedPhysics) return;
  65. const selectedObjects = window["rogue-editor"].Project.selectedObjects as THREE.Object3D[];
  66. if (!this.arraysAreEqual(selectedObjects, this.selectedObjects)) {
  67. this.selectedObjects = selectedObjects.slice(0);
  68. this.resetComponents();
  69. this.setupImpostors();
  70. }
  71. if (!this.world || (this.world && this.world.bodies.len() === 0)) {
  72. return;
  73. }
  74. this.updateImpostors();
  75. }
  76. private updateImpostors() {
  77. this.lines.visible = true;
  78. this.world.step();
  79. const flagForRemoval: (RapierCollider | RapierBody)[] = [];
  80. this.colliders.forEach(component => {
  81. if (component instanceof RapierCollider && component.object3d && component.bodyComponent) {
  82. if (!component.enabled) {
  83. component.initialized = false;
  84. flagForRemoval.push(component);
  85. return;
  86. }
  87. const pos = component.bodyComponent.object3d.position;
  88. const rot = component.bodyComponent.object3d.quaternion;
  89. component.body.setTranslation(new RAPIER.Vector3(pos.x, pos.y, pos.z), false);
  90. component.body.setRotation(new RAPIER.Quaternion(rot.x, rot.y, rot.z, rot.w), false);
  91. component.setColliderRot();
  92. component.setColliderPos();
  93. }
  94. });
  95. flagForRemoval.forEach(component => this.colliders.splice(this.colliders.indexOf(component), 1))
  96. let buffers = this.world.debugRender();
  97. this.lines.geometry.setAttribute(
  98. "position",
  99. new THREE.BufferAttribute(buffers.vertices, 3),
  100. );
  101. this.lines.geometry.setAttribute(
  102. "color",
  103. new THREE.BufferAttribute(buffers.colors, 4),
  104. );
  105. }
  106. private async cleanupImpostors() {
  107. RogueRapier.world && RogueRapier.world.bodies.forEach(body => RogueRapier.world.removeRigidBody(body));
  108. this.lines.visible = false;
  109. RE.App.currentScene.remove(this.lines);
  110. this.colliders = [];
  111. }
  112. private async setupImpostors() {
  113. await this.cleanupImpostors();
  114. this.selectedObjects.forEach(selected => {
  115. selected.traverse(object => {
  116. const objComponents = RE.components[object.uuid];
  117. if (!objComponents) return;
  118. objComponents.forEach(component => {
  119. if (component instanceof RapierBody) {
  120. component.init();
  121. this.colliders.push(component);
  122. }
  123. if (component instanceof RapierCollider) {
  124. const bodyComponent = component.getBodyComponent(component.object3d);
  125. if (bodyComponent) {
  126. bodyComponent.init();
  127. }
  128. component.init();
  129. // component.collider &&
  130. // component.collider.setSensor(true);
  131. this.colliders.push(component);
  132. }
  133. });
  134. });
  135. });
  136. RE.App.currentScene.add(this.lines);
  137. }
  138. private arraysAreEqual(array1: any[], array2: any[]) {
  139. if (array1.length !== array2.length) return false;
  140. return array1.every((element, i) => {
  141. return array2[i] === element;
  142. });
  143. }
  144. onBeforeRemoved() {
  145. RE.App.currentScene.remove(this.lines);
  146. this.handleOnComponentAdded.stop();
  147. this.handleOnComponentRemoved.stop();
  148. this.handleOnPlay.stop();
  149. this.cleanupImpostors();
  150. }
  151. }
  152. RE.registerComponent(RapierBodyWireframe);