Source: extern/physics.js

  1. import register from "../util/register.js";
  2. import m_phy_fact from "../intern/physics.js";
  3. import m_print_fact from "../intern/print.js";
  4. import * as m_util from "../intern/util.js";
  5. import m_nmesh_fact from "../intern/navmesh.js";
  6. /**
  7. * Physics module. Provides API to uranium.js physics engine.
  8. * @see https://www.blend4web.com/doc/en/physics.html
  9. * @module physics
  10. * @local CollisionCallback
  11. * @local CollisionImpulseCallback
  12. * @local RayTestCallback
  13. * @local RayTestCallbackPosNorm
  14. * @local CharacterMoveType
  15. * @local NavmeshDistanceCallback
  16. * @local NavmeshPathOptions
  17. */
  18. function Physics(ns, exports) {
  19. /**
  20. * Navmesh distance callback. Used to determine start and end polygon of navmesh
  21. * @callback NavmeshDistanceCallback
  22. * @param {Vec3} position Position to which we must calculate a distance
  23. * @param {Vec3} centroid Center of current polygon
  24. * @param {Uint32Array} vertex_ids Indices of polygon vertices
  25. * @param {Array} vertices Vertex array
  26. * @param {number} current_max_distance Current maximum distance
  27. */
  28. var m_phy = m_phy_fact(ns);
  29. var m_print = m_print_fact(ns);
  30. var m_nmesh = m_nmesh_fact(ns);
  31. /**
  32. * Collision result callback.
  33. * @callback CollisionCallback
  34. * @param {boolean} result Collision result flag.
  35. * @param {?Object3D} coll_obj The target collision object, i.e the object
  36. * the source object collides with (null for no collision or when this object
  37. * is represented by collision material).
  38. * @param {?Vec3} coll_pos Position of collision point.
  39. * @param {?Vec3} coll_norm Normal of collision point.
  40. * @param {?number} coll_dist Distance between collision points of colliding
  41. * objects.
  42. * @cc_externs coll_obj coll_pos coll_norm coll_dist
  43. */
  44. /**
  45. * Collision impulse result callback.
  46. * @callback CollisionImpulseCallback
  47. * @param {number} impulse Impulse applied on collision point.
  48. */
  49. /**
  50. * Ray test callback.
  51. * @callback RayTestCallback
  52. * @param {number} id Ray Test ID
  53. * @param {number} hit_fract Fraction of ray length where hit has occurred (0-1)
  54. * or -1 if there is no hit anymore
  55. * @param {?Object3D} obj_hit Hit Object 3D
  56. * @param {number} hit_time Time the hit happened.
  57. * @cc_externs hit_fract obj_hit hit_time
  58. */
  59. /**
  60. * Ray test callback with additional position/normal.
  61. * @callback RayTestCallbackPosNorm
  62. * @param {number} id Ray Test ID
  63. * @param {number} hit_fract Fraction of ray length where hit has occurred (0-1)
  64. * or -1 if there is no hit anymore
  65. * @param {?Object3D} obj_hit Hit Object 3D
  66. * @param {number} hit_time Time the hit happened.
  67. * @param {Vec3} hit_pos Hit position in world space
  68. * @param {Vec3} hit_norm Hit normal in world space
  69. * @cc_externs hit_fract obj_hit hit_time hit_pos hit_norm
  70. */
  71. /**
  72. * Configurable options of navmesh path.
  73. * @typedef {Object} NavmeshPathOptions
  74. * @property {number} [island=0] ID; see {@link module:physics.navmesh_get_island|physics.navmesh_get_island}
  75. * @property {number} [allowed_distance=Number.MAX_VALUE] Distance limit from
  76. * start/target position to navmesh
  77. * @property {boolean} [do_not_pull_string=false] Returns centroids path instead of pulled string
  78. * @property {boolean} [return_normals=false] Return path normals in PathInformation.
  79. * @property {NavmeshDistanceCallback} [distance_to_closest] Callback for distance
  80. * calculation to determine closest node
  81. * @property {NavmeshDistanceCallback} [distance_to_farthest] Callback for distance
  82. * calculation to determine farthest node
  83. * @cc_externs island allowed_distance do_not_pull_string return_normals
  84. * @cc_externs distance_to_closest distance_to_farthest
  85. */
  86. /**
  87. * Navmesh path information.
  88. * @typedef {Object} PathInformation
  89. * @property {Float32Array} positions Positions of path points - plane array of
  90. * Vec3-type positions
  91. * @property {?Float32Array} normals Normals of path points - plane array of
  92. * Vec3-type normals
  93. * @cc_externs positions normals
  94. */
  95. /**
  96. * Character's type of movement enum. One of CM_*.
  97. * @typedef {number} CharacterMoveType
  98. */
  99. /**
  100. * The character's type of movement is "walk".
  101. * @const {CharacterMoveType} module:physics.CM_WALK
  102. */
  103. exports.CM_WALK = 0;
  104. /**
  105. * The character's type of movement is "run".
  106. * @const {CharacterMoveType} module:physics.CM_RUN
  107. */
  108. exports.CM_RUN = 1;
  109. /**
  110. * The character's type of movement is "climb".
  111. * @const {CharacterMoveType} module:physics.CM_CLIMB
  112. */
  113. exports.CM_CLIMB = 2;
  114. /**
  115. * The character's type of movement is "fly".
  116. * @const {CharacterMoveType} module:physics.CM_FLY
  117. */
  118. exports.CM_FLY = 3;
  119. /**
  120. * Enable physics simulation.
  121. * @method module:physics.enable_simulation
  122. * @param {Object3D} obj Object 3D
  123. */
  124. exports.enable_simulation = function(obj) {
  125. if (!m_phy.obj_has_physics(obj)) {
  126. m_print.error_once("No physics for object " + obj.name);
  127. return;
  128. }
  129. m_phy.enable_simulation(obj);
  130. }
  131. /**
  132. * Disable physics simulation.
  133. * @method module:physics.disable_simulation
  134. * @param {Object3D} obj Object 3D
  135. */
  136. exports.disable_simulation = function(obj) {
  137. if (!m_phy.obj_has_physics(obj)) {
  138. m_print.error_once("No physics for object " + obj.name);
  139. return;
  140. }
  141. m_phy.disable_simulation(obj);
  142. }
  143. /**
  144. * Check if the object has any physics
  145. * @method module:physics.has_physics
  146. * @param {Object3D} obj Object 3D
  147. * @returns {boolean} Check result
  148. */
  149. exports.has_physics = function(obj) {
  150. return m_phy.obj_has_physics(obj);
  151. }
  152. /**
  153. * Check if the object has any simulated physics
  154. * @method module:physics.has_simulated_physics
  155. * @param {Object3D} obj Object 3D
  156. * @returns {boolean} Check result
  157. */
  158. exports.has_simulated_physics = function(obj) {
  159. return m_phy.has_simulated_physics(obj);
  160. }
  161. /**
  162. * Check if the object has dynamic simulated physics
  163. * @method module:physics.has_dynamic_physics
  164. * @param {Object3D} obj Object 3D
  165. * @returns {boolean} Check result
  166. */
  167. exports.has_dynamic_physics = function(obj) {
  168. return m_phy.has_dynamic_physics(obj);
  169. }
  170. /**
  171. * Set the object's gravity.
  172. * @method module:physics.set_gravity
  173. * @param {Object3D} obj Object 3D
  174. * @param {number} gravity Object gravity value along the Z axis.
  175. * @deprecated [17.10] Use {@link module:physics.set_object_gravity} instead
  176. */
  177. exports.set_gravity = function(obj, gravity) {
  178. m_print.error_deprecated("set_gravity", "set_object_gravity");
  179. if (!m_phy.obj_has_physics(obj)) {
  180. m_print.error_once("No physics for object " + obj.name);
  181. return;
  182. }
  183. // handling old behavior when positive gravity aligned with negative Z.
  184. m_phy.set_gravity(obj, 0, 0, -gravity);
  185. }
  186. /**
  187. * Set the object's gravity.
  188. * @method module:physics.set_object_gravity
  189. * @param {Object3D} obj Object 3D
  190. * @param {Vec3} gravity Gravity vector.
  191. * @example var m_phy = require("physics");
  192. * var m_scenes = require("scenes");
  193. *
  194. * var my_cube = m_scenes.get_object_by_name("Cube");
  195. * var gravity_vec = new Float32Array([0, 0, 1]);
  196. * m_phy.set_object_gravity(my_cube, gravity_vec);
  197. */
  198. exports.set_object_gravity = function(obj, gravity) {
  199. if (!m_phy.obj_has_physics(obj)) {
  200. m_print.error_once("No physics for object " + obj.name);
  201. return;
  202. }
  203. m_phy.set_gravity(obj, gravity[0], gravity[1], gravity[2]);
  204. }
  205. /**
  206. * Set the object's transform (for static/kinematic objects)
  207. * @method module:physics.set_transform
  208. * @param {Object3D} obj Object 3D
  209. * @param {Vec3} trans Translation vector
  210. * @param {Quat} quat Rotation quaternion
  211. */
  212. exports.set_transform = function(obj, trans, quat) {
  213. if (!m_phy.obj_has_physics(obj)) {
  214. m_print.error_once("No physics for object " + obj.name);
  215. return;
  216. }
  217. m_phy.set_transform(obj, trans, quat);
  218. }
  219. /**
  220. * Sync the object's transform (for static/kinematic objects)
  221. * @method module:physics.sync_transform
  222. * @param {Object3D} obj Object 3D
  223. */
  224. exports.sync_transform = function(obj) {
  225. if (!m_phy.obj_has_physics(obj)) {
  226. m_print.error_once("No physics for object " + obj.name);
  227. return;
  228. }
  229. m_phy.sync_transform(obj);
  230. }
  231. /**
  232. * Apply velocity to the object (in the local space)
  233. * @method module:physics.apply_velocity
  234. * @param {Object3D} obj Object 3D
  235. * @param {number} vx_local Vx local space velocity
  236. * @param {number} vy_local Vy local space velocity
  237. * @param {number} vz_local Vz local space velocity
  238. */
  239. exports.apply_velocity = function(obj, vx_local, vy_local, vz_local) {
  240. if (!m_phy.obj_has_physics(obj)) {
  241. m_print.error_once("No physics for object " + obj.name);
  242. return;
  243. }
  244. m_phy.apply_velocity(obj, vx_local, vy_local, vz_local);
  245. }
  246. /**
  247. * Apply velocity to the object (in the world space)
  248. * @method module:physics.apply_velocity_world
  249. * @param {Object3D} obj Object 3D
  250. * @param {number} vx Vx world space velocity
  251. * @param {number} vy Vy world space velocity
  252. * @param {number} vz Vz world space velocity
  253. */
  254. exports.apply_velocity_world = function(obj, vx, vy, vz) {
  255. if (!m_phy.obj_has_physics(obj)) {
  256. m_print.error_once("No physics for object " + obj.name);
  257. return;
  258. }
  259. m_phy.apply_velocity_world(obj, vx, vy, vz);
  260. }
  261. /**
  262. * Apply a constant force to the object (in the local space).
  263. * Pass zero values to remove applied force.
  264. * @method module:physics.apply_force
  265. * @param {Object3D} obj Object 3D
  266. * @param {number} fx_local Fx force in the local space
  267. * @param {number} fy_local Fy force in the local space
  268. * @param {number} fz_local Fz force in the local space
  269. */
  270. exports.apply_force = function(obj, fx_local, fy_local, fz_local) {
  271. if (!m_phy.obj_has_physics(obj)) {
  272. m_print.error_once("No physics for object " + obj.name);
  273. return;
  274. }
  275. m_phy.apply_force(obj, fx_local, fy_local, fz_local, false);
  276. }
  277. /**
  278. * Apply a constant force to the object (in the world space).
  279. * Pass zero values to remove applied force.
  280. * @method module:physics.apply_force_world
  281. * @param {Object3D} obj Object 3D
  282. * @param {number} fx_world Fx force in the world space
  283. * @param {number} fy_world Fy force in the world space
  284. * @param {number} fz_world Fz force in the world space
  285. */
  286. exports.apply_force_world = function(obj, fx_world, fy_world, fz_world) {
  287. if (!m_phy.obj_has_physics(obj)) {
  288. m_print.error_once("No physics for object " + obj.name);
  289. return;
  290. }
  291. m_phy.apply_force(obj, fx_world, fy_world, fz_world, true);
  292. }
  293. /**
  294. * Apply constant torque to the object (in the local space).
  295. * Pass zero values to remove applied torque.
  296. * @method module:physics.apply_torque
  297. * @param {Object3D} obj Object 3D
  298. * @param {number} tx_local Tx torque
  299. * @param {number} ty_local Ty torque
  300. * @param {number} tz_local Tz torque
  301. */
  302. exports.apply_torque = function(obj, tx_local, ty_local, tz_local) {
  303. if (!m_phy.obj_has_physics(obj)) {
  304. m_print.error_once("No physics for object " + obj.name);
  305. return;
  306. }
  307. m_phy.apply_torque(obj, tx_local, ty_local, tz_local);
  308. }
  309. /**
  310. * Set object's angular velocity.
  311. * @method module:physics.set_angular_velocity
  312. * @param {Object3D} obj Object 3D
  313. * @param {number} av_x X projection of angular velocity in the local space
  314. * @param {number} av_y Y projection of angular velocity in the local space
  315. * @param {number} av_z Z projection of angular velocity in the local space
  316. * @example var m_physics = require("physics");
  317. *
  318. * var obj = m_scenes.get_object_by_name("Cube");
  319. * m_physics.set_angular_velocity(obj, 0.0, 0.0, 0.5);
  320. */
  321. exports.set_angular_velocity = function(obj, av_x, av_y, av_z) {
  322. if (!m_phy.obj_has_physics(obj)) {
  323. m_print.error_once("No physics for object " + obj.name);
  324. return;
  325. }
  326. m_phy.set_angular_velocity(obj, av_x, av_y, av_z);
  327. }
  328. /**
  329. * Apply throttle to vehicle.
  330. * @method module:physics.vehicle_throttle
  331. * @param {Object3D} obj Object 3D
  332. * @param {number} engine_force Engine force (-1..1)
  333. */
  334. exports.vehicle_throttle = function(obj, engine_force) {
  335. if (!m_phy.obj_has_physics(obj)) {
  336. m_print.error_once("No physics for object " + obj.name);
  337. return;
  338. }
  339. if (!m_phy.is_vehicle_chassis(obj) && !m_phy.is_vehicle_hull(obj))
  340. m_print.error("Wrong object");
  341. m_phy.vehicle_throttle(obj, m_util.clamp(engine_force, -1, 1));
  342. }
  343. /**
  344. * Increment vehicle throttle.
  345. * @method module:physics.vehicle_throttle_inc
  346. * @param {Object3D} obj Object 3D
  347. * @param {number} engine_force_inc Engine force increment (0..1)
  348. * @param {number} dir Throttling direction -1,0,1
  349. */
  350. exports.vehicle_throttle_inc = function(obj, engine_force_inc, dir) {
  351. if (!m_phy.obj_has_physics(obj)) {
  352. m_print.error_once("No physics for object " + obj.name);
  353. return;
  354. }
  355. if (!m_phy.is_vehicle_chassis(obj) && !m_phy.is_vehicle_hull(obj))
  356. m_print.error("Wrong object");
  357. engine_force_inc = m_util.clamp(engine_force_inc, 0, 1);
  358. var vehicle = obj.vehicle;
  359. var force = vehicle.engine_force;
  360. if (dir == -1 || dir == 1) {
  361. force += dir * engine_force_inc;
  362. force = Math.max(-1, Math.min(force, 1));
  363. } else if (dir == 0 && force >= 0) {
  364. force -= engine_force_inc;
  365. force = Math.max(0, force);
  366. } else if (dir == 0 && force < 0) {
  367. force += engine_force_inc;
  368. force = Math.min(0, force);
  369. } else
  370. m_print.error("Wrong steering direction");
  371. m_phy.vehicle_throttle(obj, m_util.clamp(force, -1, 1));
  372. }
  373. /**
  374. * Change vehicle steering.
  375. * @method module:physics.vehicle_steer
  376. * @param {Object3D} obj Object 3D
  377. * @param {number} steering_value Steering value (-1..1)
  378. */
  379. exports.vehicle_steer = function(obj, steering_value) {
  380. if (!m_phy.obj_has_physics(obj)) {
  381. m_print.error_once("No physics for object " + obj.name);
  382. return;
  383. }
  384. if (!m_phy.is_vehicle_chassis(obj) && !m_phy.is_vehicle_hull(obj))
  385. m_print.error("Wrong object");
  386. m_phy.vehicle_steer(obj, m_util.clamp(steering_value, -1, 1));
  387. }
  388. /**
  389. * Increment vehicle steering.
  390. * @method module:physics.vehicle_steer_inc
  391. * @param {Object3D} obj Object 3D
  392. * @param {number} steering_value_inc Steering value increment (0..1)
  393. * @param {number} dir Steering direction -1,0,1
  394. */
  395. exports.vehicle_steer_inc = function(obj, steering_value_inc, dir) {
  396. if (!m_phy.obj_has_physics(obj)) {
  397. m_print.error_once("No physics for object " + obj.name);
  398. return;
  399. }
  400. if (!m_phy.is_vehicle_chassis(obj) && !m_phy.is_vehicle_hull(obj))
  401. m_print.error("Wrong object");
  402. steering_value_inc = m_util.clamp(steering_value_inc, 0, 1);
  403. var vehicle = obj.vehicle;
  404. var steering = vehicle.steering;
  405. if (dir == -1 || dir == 1) {
  406. steering += dir * steering_value_inc;
  407. steering = Math.max(-1, Math.min(steering, 1));
  408. } else if (dir == 0 && steering >= 0) {
  409. steering -= steering_value_inc;
  410. steering = Math.max(0, steering);
  411. } else if (dir == 0 && steering < 0) {
  412. steering += steering_value_inc;
  413. steering = Math.min(0, steering);
  414. } else
  415. m_print.error("Wrong steering direction");
  416. m_phy.vehicle_steer(obj, m_util.clamp(steering, -1, 1));
  417. }
  418. /**
  419. * Stop the vehicle by applying the brake force.
  420. * @method module:physics.vehicle_brake
  421. * @param {Object3D} obj Object 3D
  422. * @param {number} brake_force Brake force (0..1)
  423. */
  424. exports.vehicle_brake = function(obj, brake_force) {
  425. if (!m_phy.obj_has_physics(obj)) {
  426. m_print.error_once("No physics for object " + obj.name);
  427. return;
  428. }
  429. if (!m_phy.is_vehicle_chassis(obj) && !m_phy.is_vehicle_hull(obj))
  430. m_print.error("Wrong object");
  431. m_phy.vehicle_brake(obj, m_util.clamp(brake_force, 0, 1));
  432. }
  433. /**
  434. * Increment the brake force
  435. * @method module:physics.vehicle_brake_inc
  436. * @param {Object3D} obj Object 3D
  437. * @param {number} brake_force_inc Brake force increment (-1..1)
  438. */
  439. exports.vehicle_brake_inc = function(obj, brake_force_inc) {
  440. if (!m_phy.obj_has_physics(obj)) {
  441. m_print.error_once("No physics for object " + obj.name);
  442. return;
  443. }
  444. if (!m_phy.is_vehicle_chassis(obj) && !m_phy.is_vehicle_hull(obj))
  445. m_print.error("Wrong object");
  446. brake_force_inc = m_util.clamp(brake_force_inc, -1, 1);
  447. var vehicle = obj.vehicle;
  448. var brake_force = vehicle.brake_force;
  449. brake_force += brake_force * brake_force_inc;
  450. m_phy.vehicle_brake(obj, m_util.clamp(brake_force, 0, 1));
  451. }
  452. /**
  453. * Check if the given object is a vehicle chassis.
  454. * @method module:physics.is_vehicle_chassis
  455. * @param {Object3D} obj Object 3D
  456. * @returns {boolean} Checking result.
  457. */
  458. exports.is_vehicle_chassis = function(obj) {
  459. return m_phy.is_vehicle_chassis(obj);
  460. }
  461. /**
  462. * Check if the given object is a vehicle hull.
  463. * @method module:physics.is_vehicle_hull
  464. * @param {Object3D} obj Object 3D
  465. * @returns {boolean} Checking result.
  466. */
  467. exports.is_vehicle_hull = function(obj) {
  468. return m_phy.is_vehicle_hull(obj);
  469. }
  470. /**
  471. * Get the vehicle name.
  472. * @method module:physics.get_vehicle_name
  473. * @param {Object3D} obj Object 3D
  474. * @returns {?string} Vehicle name.
  475. */
  476. exports.get_vehicle_name = function(obj) {
  477. if (!m_phy.obj_has_physics(obj)) {
  478. m_print.error_once("No physics for object " + obj.name);
  479. return null;
  480. }
  481. if (m_phy.is_vehicle_chassis(obj) || m_phy.is_vehicle_hull(obj))
  482. return obj.vehicle_settings.name;
  483. else {
  484. m_print.error("Wrong object");
  485. return null;
  486. }
  487. }
  488. /**
  489. * Get the vehicle's throttle value.
  490. * @method module:physics.get_vehicle_throttle
  491. * @param {Object3D} obj Object 3D
  492. * @returns {?number} Throttle value.
  493. */
  494. exports.get_vehicle_throttle = function(obj) {
  495. if (!m_phy.obj_has_physics(obj)) {
  496. m_print.error_once("No physics for object " + obj.name);
  497. return null;
  498. }
  499. if (m_phy.is_vehicle_chassis(obj) || m_phy.is_vehicle_hull(obj))
  500. return obj.vehicle.engine_force;
  501. else {
  502. m_print.error("Wrong object");
  503. return null;
  504. }
  505. }
  506. /**
  507. * Get the vehicle's steering value.
  508. * @method module:physics.get_vehicle_steering
  509. * @param {Object3D} obj Object 3D
  510. * @returns {number} Steering value
  511. */
  512. exports.get_vehicle_steering = function(obj) {
  513. if (!m_phy.obj_has_physics(obj)) {
  514. m_print.error_once("No physics for object " + obj.name);
  515. return 0;
  516. }
  517. if (m_phy.is_vehicle_chassis(obj) || m_phy.is_vehicle_hull(obj))
  518. return obj.vehicle.steering;
  519. else
  520. m_print.error("Wrong object");
  521. return 0;
  522. }
  523. /**
  524. * Get the vehicle's brake force.
  525. * @method module:physics.get_vehicle_brake
  526. * @param {Object3D} obj Object 3D
  527. * @returns {number} Brake value
  528. */
  529. exports.get_vehicle_brake = function(obj) {
  530. if (!m_phy.obj_has_physics(obj)) {
  531. m_print.error_once("No physics for object " + obj.name);
  532. return 0;
  533. }
  534. if (m_phy.is_vehicle_chassis(obj) || m_phy.is_vehicle_hull(obj))
  535. return obj.vehicle.brake_force;
  536. else
  537. m_print.error("Wrong object");
  538. return 0;
  539. }
  540. /**
  541. * Get the vehicle speed in km/h.
  542. * @method module:physics.get_vehicle_speed
  543. * @param {Object3D} obj Object 3D
  544. * @returns {number} Vehicle speed
  545. */
  546. exports.get_vehicle_speed = function(obj) {
  547. if (!m_phy.obj_has_physics(obj)) {
  548. m_print.error_once("No physics for object " + obj.name);
  549. return 0;
  550. }
  551. if (m_phy.is_vehicle_chassis(obj) || m_phy.is_vehicle_hull(obj))
  552. return m_phy.get_vehicle_speed(obj);
  553. else
  554. m_print.error("Wrong object");
  555. return 0;
  556. }
  557. /**
  558. * Check if the given object is a character.
  559. * @method module:physics.is_character
  560. * @param {Object3D} obj Object 3D
  561. * @returns {boolean} Check result
  562. */
  563. exports.is_character = function(obj) {
  564. return m_phy.has_character_physics(obj);
  565. }
  566. /**
  567. * Move the character in the corresponding direction.
  568. * @method module:physics.set_character_move_dir
  569. * @param {Object3D} obj Object 3D
  570. * @param {number} forw Apply forward speed
  571. * @param {number} side Apply side speed
  572. */
  573. exports.set_character_move_dir = function(obj, forw, side) {
  574. if (!m_phy.obj_has_physics(obj)) {
  575. m_print.error_once("No physics for object " + obj.name);
  576. return;
  577. }
  578. m_phy.set_character_move_dir(obj, forw, side);
  579. }
  580. /**
  581. * Set the character moving type.
  582. * @method module:physics.set_character_move_type
  583. * @param {Object3D} obj Object 3D
  584. * @param {CharacterMoveType} type Character moving type (one of CM_*).
  585. */
  586. exports.set_character_move_type = function(obj, type) {
  587. if (!m_phy.obj_has_physics(obj)) {
  588. m_print.error_once("No physics for object " + obj.name);
  589. return;
  590. }
  591. m_phy.set_character_move_type(obj, type);
  592. }
  593. /**
  594. * Set the character's walk speed.
  595. * @method module:physics.set_character_walk_velocity
  596. * @param {Object3D} obj Object 3D
  597. * @param {number} velocity Walking velocity
  598. */
  599. exports.set_character_walk_velocity = function(obj, velocity) {
  600. if (!m_phy.obj_has_physics(obj)) {
  601. m_print.error_once("No physics for object " + obj.name);
  602. return;
  603. }
  604. m_phy.set_character_walk_velocity(obj, velocity);
  605. }
  606. /**
  607. * Set the character's run speed.
  608. * @method module:physics.set_character_run_velocity
  609. * @param {Object3D} obj Object 3D
  610. * @param {number} velocity Running velocity
  611. */
  612. exports.set_character_run_velocity = function(obj, velocity) {
  613. if (!m_phy.obj_has_physics(obj)) {
  614. m_print.error_once("No physics for object " + obj.name);
  615. return;
  616. }
  617. m_phy.set_character_run_velocity(obj, velocity);
  618. }
  619. /**
  620. * Set the character's fly speed.
  621. * @method module:physics.set_character_fly_velocity
  622. * @param {Object3D} obj Object 3D
  623. * @param {number} velocity Flying velocity
  624. */
  625. exports.set_character_fly_velocity = function(obj, velocity) {
  626. if (!m_phy.obj_has_physics(obj)) {
  627. m_print.error_once("No physics for object " + obj.name);
  628. return;
  629. }
  630. m_phy.set_character_fly_velocity(obj, velocity);
  631. }
  632. /**
  633. * Make the character jump
  634. * @method module:physics.character_jump
  635. * @param {Object3D} obj Object 3D
  636. */
  637. exports.character_jump = function(obj) {
  638. if (!m_phy.obj_has_physics(obj)) {
  639. m_print.error_once("No physics for object " + obj.name);
  640. return;
  641. }
  642. m_phy.character_jump(obj);
  643. }
  644. /**
  645. * Increment the character rotation
  646. * @method module:physics.character_rotation_inc
  647. * @param {Object3D} obj Object 3D
  648. * @param {number} h_angle Angle (in radians) in horizontal plane
  649. * @param {number} v_angle Angle (in radians) in vertical plane
  650. */
  651. exports.character_rotation_inc = function(obj, h_angle, v_angle) {
  652. if (!m_phy.obj_has_physics(obj)) {
  653. m_print.error_once("No physics for object " + obj.name);
  654. return;
  655. }
  656. m_phy.character_rotation_inc(obj, h_angle, v_angle);
  657. }
  658. /**
  659. * Set the character rotation in horizontal and vertical planes
  660. * @method module:physics.set_character_rotation
  661. * @param {Object3D} obj Object 3D
  662. * @param {number} angle_h Angle (in radians) in horizontal plane
  663. * @param {number} angle_v Angle (in radians) in vertical plane
  664. */
  665. exports.set_character_rotation = function(obj, angle_h, angle_v) {
  666. if (!m_phy.obj_has_physics(obj)) {
  667. m_print.error_once("No physics for object " + obj.name);
  668. return;
  669. }
  670. m_phy.set_character_rotation(obj, angle_h, angle_v);
  671. }
  672. /**
  673. * Set the character vertical rotation
  674. * @method module:physics.set_character_rotation_v
  675. * @param {Object3D} obj Object 3D
  676. * @param {number} angle Angle (in radians) in vertical plane
  677. */
  678. exports.set_character_rotation_v = function(obj, angle) {
  679. if (!m_phy.obj_has_physics(obj)) {
  680. m_print.error_once("No physics for object " + obj.name);
  681. return;
  682. }
  683. m_phy.set_character_rotation_v(obj, angle);
  684. }
  685. /**
  686. * Set the character horizontal rotation
  687. * @method module:physics.set_character_rotation_h
  688. * @param {Object3D} obj Object 3D
  689. * @param {number} angle Angle (in radians) in horizontal plane
  690. */
  691. exports.set_character_rotation_h = function(obj, angle) {
  692. if (!m_phy.obj_has_physics(obj)) {
  693. m_print.error_once("No physics for object " + obj.name);
  694. return;
  695. }
  696. m_phy.set_character_rotation_h(obj, angle);
  697. }
  698. /**
  699. * Set the vertical angle of the moving direction for a character. Applies only
  700. * in FLYING and SWIMMING mode. Used to control the moving direction from the
  701. * camera vertical angle.
  702. * @method module:physics.set_character_vert_move_dir_angle
  703. * @param {Object3D} obj Character object.
  704. * @param {number} angle Angle (in radians) in vertical plane
  705. * @example
  706. * var m_cam = require("camera");
  707. * var m_phys = require("physics");
  708. * var m_scenes = require("scenes");
  709. *
  710. * var _vec2_tmp = new Float32Array(2);
  711. *
  712. * var char = m_scenes.get_first_character();
  713. * var camera = m_scenes.get_active_camera();
  714. * var angles = m_cam.get_camera_angles_char(camera, _vec2_tmp);
  715. *
  716. * m_phys.set_character_vert_move_dir_angle(char, angles[1]);
  717. */
  718. exports.set_character_vert_move_dir_angle = function(obj, angle) {
  719. if (!m_phy.obj_has_physics(obj)) {
  720. m_print.error_once("No physics for object " + obj.name);
  721. return;
  722. }
  723. m_phy.set_character_vert_move_dir_angle(obj, angle);
  724. }
  725. /**
  726. * Append a new async collision test to the given object.
  727. * @method module:physics.append_collision_test
  728. * @param {Object3D} obj_src Object 3D
  729. * @param {?string} collision_id Collision ID, pass "ANY" or null for any collision ID.
  730. * @param {CollisionCallback} callback Collision callback
  731. * @param {boolean} [calc_pos_norm=false] Pass collision point/normal/distance in callback
  732. */
  733. exports.append_collision_test = function(obj_src, collision_id, callback,
  734. calc_pos_norm) {
  735. if (!m_phy.obj_has_physics(obj_src)) {
  736. m_print.error_once("No physics for object " + obj_src.name);
  737. return;
  738. }
  739. collision_id = collision_id || "ANY";
  740. calc_pos_norm = calc_pos_norm || false;
  741. m_phy.append_collision_test(obj_src, collision_id, callback, calc_pos_norm);
  742. }
  743. /**
  744. * Remove the collision test from the given object.
  745. * @method module:physics.remove_collision_test
  746. * @param {Object3D} obj Object 3D.
  747. * @param {?string} collision_id Collision ID, pass "ANY" or null for any collision ID.
  748. * @param {CollisionCallback} callback Collision callback.
  749. */
  750. exports.remove_collision_test = function(obj, collision_id, callback) {
  751. if (!m_phy.obj_has_physics(obj)) {
  752. m_print.error_once("No physics for object " + obj.name);
  753. return;
  754. }
  755. collision_id = collision_id || "ANY";
  756. m_phy.remove_collision_test(obj, collision_id, callback);
  757. }
  758. /**
  759. * Apply a new async collision impulse test to the given object.
  760. * @method module:physics.apply_collision_impulse_test
  761. * @param {Object3D} obj Object 3D
  762. * @param {CollisionImpulseCallback} callback Collision impulse test callback.
  763. */
  764. exports.apply_collision_impulse_test = function(obj, callback) {
  765. if (!m_phy.obj_has_physics(obj)) {
  766. m_print.error_once("No physics for object " + obj.name);
  767. return;
  768. }
  769. m_phy.apply_collision_impulse_test(obj, callback);
  770. }
  771. /**
  772. * Remove the collision impulse test from the given object.
  773. * @method module:physics.clear_collision_impulse_test
  774. * @param {Object3D} obj Object 3D
  775. */
  776. exports.clear_collision_impulse_test = function(obj) {
  777. if (!m_phy.obj_has_physics(obj)) {
  778. m_print.error_once("No physics for object " + obj.name);
  779. return;
  780. }
  781. m_phy.clear_collision_impulse_test(obj);
  782. }
  783. /**
  784. * Append a new async ray test.
  785. * @method module:physics.append_ray_test
  786. * @param {?Object3D} obj_src Source object, pass a non-null value to perform ray casting
  787. * in object space, e.g. from/to vectors specified in object space.
  788. * @param {Vec3} from From vector
  789. * @param {Vec3} to To vector
  790. * @param {?string} collision_id Collision ID, pass "ANY" or null for any collision ID.
  791. * @param {RayTestCallback} callback Ray Test callback
  792. * @param {boolean} [autoremove=false] Automatically remove test after ray casting.
  793. * @returns {number} Ray Test ID
  794. */
  795. exports.append_ray_test = function(obj_src, from, to, collision_id, callback,
  796. autoremove) {
  797. obj_src = obj_src || null;
  798. if (obj_src != null && !m_phy.obj_has_physics(obj_src)) {
  799. m_print.error_once("No physics for object " + obj_src.name);
  800. return 0;
  801. }
  802. collision_id = collision_id || "ANY";
  803. autoremove = autoremove || false;
  804. var calc_all_hits = false;
  805. var calc_pos_norm = false;
  806. var ign_src_rot = false;
  807. return m_phy.append_ray_test(obj_src, from, to, collision_id, callback,
  808. autoremove, calc_all_hits, calc_pos_norm, ign_src_rot);
  809. }
  810. /**
  811. * Append a new async ray test (extended version).
  812. * @method module:physics.append_ray_test_ext
  813. * @param {?Object3D} obj_src Source object, pass a non-null value to perform ray casting
  814. * in object space, e.g. from/to vectors specified in object space
  815. * @param {Vec3} from From vector
  816. * @param {Vec3} to To vector
  817. * @param {?string} collision_id Collision ID, pass "ANY" or null for any collision ID.
  818. * @param {RayTestCallback|RayTestCallbackPosNorm} callback Ray Test callback
  819. * @param {boolean} [autoremove=false] Automatically remove test after ray casting.
  820. * @param {boolean} [calc_all_hits=false] Test for all possible objects along the ray or
  821. * just for closest object
  822. * @param {boolean} [calc_pos_norm=false] Calculate and return hit point's position/normal in
  823. * callback
  824. * @param {boolean} [ign_src_rot=false] Ignore rotation of source object
  825. * @returns {number} Ray Test ID
  826. */
  827. exports.append_ray_test_ext = function(obj_src, from, to, collision_id, callback,
  828. autoremove, calc_all_hits, calc_pos_norm, ign_src_rot) {
  829. obj_src = obj_src || null;
  830. if (obj_src != null && !m_phy.obj_has_physics(obj_src)) {
  831. m_print.error_once("No physics for object " + obj_src.name);
  832. return 0;
  833. }
  834. collision_id = collision_id || "ANY";
  835. autoremove = autoremove || false;
  836. calc_all_hits = calc_all_hits || false;
  837. calc_pos_norm = calc_pos_norm || false;
  838. ign_src_rot = ign_src_rot || false;
  839. return m_phy.append_ray_test(obj_src, from, to, collision_id, callback,
  840. autoremove, calc_all_hits, calc_pos_norm, ign_src_rot);
  841. }
  842. /**
  843. * Remove ray test.
  844. * @method module:physics.remove_ray_test
  845. * @param {number} id Ray Test ID
  846. */
  847. exports.remove_ray_test = function(id) {
  848. if (!m_phy.is_ray_test(id)) {
  849. m_print.error("Wrong ray test ID");
  850. return;
  851. }
  852. m_phy.remove_ray_test(id);
  853. }
  854. /**
  855. * Change from/to vectors for the given ray test.
  856. * @method module:physics.change_ray_test_from_to
  857. * @param {number} id Ray Test ID
  858. * @param {Vec3} from New from vector
  859. * @param {Vec3} to New to vector
  860. */
  861. exports.change_ray_test_from_to = function(id, from, to) {
  862. if (!m_phy.is_ray_test(id)) {
  863. m_print.error("Wrong ray test ID");
  864. return;
  865. }
  866. m_phy.change_ray_test_from_to(id, from, to);
  867. }
  868. /**
  869. * Apply physics constraint.
  870. * @method module:physics.apply_constraint
  871. * @param {string} pivot_type Pivot type
  872. * @param {Object3D} obj_a Object 3D A
  873. * @param {Vec3} trans_a Translation of pivot frame relative to A
  874. * @param {Quat} quat_a Rotation of pivot frame relative to A
  875. * @param {Object3D} obj_b Object 3D B
  876. * @param {Vec3} trans_b Translation of pivot frame relative to B
  877. * @param {Quat} quat_b Rotation of pivot frame relative to B
  878. * @param {ConstraintLimits} limits Object containing constraint limits
  879. * @param {Float32Array} [stiffness=null] 6-dimensional vector with constraint stiffness
  880. * @param {Float32Array} [damping=null] 6-dimensional vector with constraint damping
  881. */
  882. exports.apply_constraint = function(pivot_type, obj_a, trans_a, quat_a,
  883. obj_b, trans_b, quat_b, limits, stiffness, damping) {
  884. if (!m_phy.obj_has_physics(obj_a) || !m_phy.obj_has_physics(obj_b)) {
  885. m_print.error("Wrong objects");
  886. return;
  887. }
  888. m_phy.apply_constraint(pivot_type, obj_a, trans_a, quat_a,
  889. obj_b, trans_b, quat_b, limits, stiffness, damping);
  890. }
  891. /**
  892. * Remove physics constraint.
  893. * constraint identified by object A from apply_constraint function
  894. * @method module:physics.remove_constraint
  895. * @param {Object3D} obj_a Object A.
  896. */
  897. exports.clear_constraint = function(obj_a) {
  898. if (!m_phy.obj_has_physics(obj_a) || !m_phy.has_constraint(obj_a)) {
  899. m_print.error("Wrong object");
  900. return;
  901. }
  902. m_phy.clear_constraint(obj_a);
  903. }
  904. /**
  905. * Pull object A to constraint pivot with object B.
  906. * @method module:physics.pull_to_constraint_pivot
  907. * @param {Object3D} obj_a Object 3D A
  908. * @param {Vec3} trans_a Translation of pivot frame relative to A
  909. * @param {Quat} quat_a Rotation of pivot frame relative to A
  910. * @param {Object3D} obj_b Object 3D B
  911. * @param {Vec3} trans_b Translation of pivot frame relative to B
  912. * @param {Quat} quat_b Rotation of pivot frame relative to B
  913. */
  914. exports.pull_to_constraint_pivot = function(obj_a, trans_a, quat_a,
  915. obj_b, trans_b, quat_b) {
  916. if (!m_phy.obj_has_physics(obj_a) || !m_phy.obj_has_physics(obj_b)) {
  917. m_print.error("Wrong objects");
  918. return;
  919. }
  920. m_phy.pull_to_constraint_pivot(obj_a, trans_a, quat_a,
  921. obj_b, trans_b, quat_b);
  922. }
  923. function distance_to_closest_default(position, centroid, vertex_ids, vertices,
  924. current_max_distance) {
  925. return m_util.dist_to_triange(position, vertices[vertex_ids[0]],
  926. vertices[vertex_ids[1]], vertices[vertex_ids[2]]);
  927. }
  928. // NOTE: don't remove this function.
  929. // function distance_to_closest_default(position, centroid, vertex_ids, vertices,
  930. // current_max_distance) {
  931. // m_vec3.subtract(position, centroid, _vec3_tmp);
  932. // return m_vec3.dot(_vec3_tmp, _vec3_tmp);
  933. // }
  934. function distance_to_farthest_default(position, centroid, vertex_ids, vertices,
  935. current_max_distance) {
  936. var distance = Math.abs(position[2] - centroid[2]);
  937. if (distance < current_max_distance &&
  938. m_nmesh.is_vector_in_poly(position, vertex_ids, vertices))
  939. return distance;
  940. else
  941. return Number.MAX_VALUE;
  942. }
  943. /**
  944. * Get the id of a closest navmesh island(group)
  945. * @method module:physics.navmesh_get_island
  946. * @param {Object3D} navmesh_obj Navigation mesh object
  947. * @param {Vec3} position Path start position
  948. * @param {?NavmeshDistanceCallback} distance_to_closest Callback for distance
  949. * calculation to determine the closest node. If null then the default function will
  950. * be used. It calculates the distance from a point to a triangle in the 3D space.
  951. * @returns {number} island ID
  952. * @example
  953. * var m_phys = require("physics");
  954. * var m_scenes = require("scenes");
  955. *
  956. * var start_point = new Float32Array([5, 2, -7]);
  957. * var end_point = new Float32Array([-2, 0, 3]);
  958. * var navmesh_obj = m_scenes.get_object_by_name("navmesh");
  959. *
  960. * var island_id = m_phys.navmesh_get_island(navmesh_obj, start_point);
  961. * var path = m_phys.navmesh_find_path(navmesh_obj, start_point, end_point, { island: island_id });
  962. */
  963. exports.navmesh_get_island = navmesh_get_island;
  964. function navmesh_get_island(navmesh_obj, position,
  965. distance_to_closest) {
  966. if (!distance_to_closest)
  967. distance_to_closest = distance_to_closest_default;
  968. if (!m_phy.obj_has_physics(navmesh_obj)) {
  969. m_print.error_once("No physics for object " + navmesh_obj.name);
  970. return;
  971. }
  972. var navmesh = navmesh_obj.physics.navmesh;
  973. if (!navmesh) {
  974. m_print.error(navmesh_obj.name + " is not a navigation mesh object");
  975. return null;
  976. }
  977. return m_nmesh.navmesh_get_island(navmesh, position, distance_to_closest);
  978. }
  979. /**
  980. * Find path between start_pos and dest_pos, return flat array containing
  981. * positions of path.
  982. * @method module:physics.navmesh_find_path
  983. * @param {Object3D} navmesh_obj Navigation mesh object
  984. * @param {Vec3} start_pos Start position
  985. * @param {Vec3} dest_pos Target position
  986. * @param {NavmeshPathOptions} [options={}] Configurable options of navmesh path
  987. * @returns {?PathInformation} Path information or null if path does not exist
  988. * @example
  989. * var m_phys = require("physics");
  990. * var m_scenes = require("scenes");
  991. *
  992. * var start_point = new Float32Array([5, 2, -7]);
  993. * var end_point = new Float32Array([-2, 0, 3]);
  994. * var navmesh_obj = m_scenes.get_object_by_name("navmesh");
  995. *
  996. * var island_id = m_phys.navmesh_get_island(navmesh_obj, start_point);
  997. * var path = m_phys.navmesh_find_path(navmesh_obj, start_point, end_point, { island: island_id });
  998. */
  999. exports.navmesh_find_path = function (navmesh_obj, start_pos, dest_pos, options) {
  1000. if (!m_phy.obj_has_physics(navmesh_obj)) {
  1001. m_print.error_once("No physics for object " + navmesh_obj.name);
  1002. return;
  1003. }
  1004. var navmesh = navmesh_obj.physics.navmesh;
  1005. if (!navmesh) {
  1006. m_print.error(navmesh_obj.name + " is not a navigation mesh object");
  1007. return null;
  1008. }
  1009. options = options || {};
  1010. var nav_options = {};
  1011. nav_options.do_not_pull_string = Boolean(options.do_not_pull_string);
  1012. nav_options.distance_to_closest = options.distance_to_closest ||
  1013. distance_to_closest_default;
  1014. nav_options.distance_to_farthest = options.distance_to_farthest ||
  1015. distance_to_farthest_default;
  1016. nav_options.island = options.island || 0;
  1017. nav_options.allowed_distance = options.allowed_distance || Number.MAX_VALUE;
  1018. nav_options.return_normals = options.return_normals || false;
  1019. return m_nmesh.navmesh_find_path(navmesh, start_pos, dest_pos, nav_options);
  1020. }
  1021. /**
  1022. * Synchronize collision boundings of the mesh, e.g. after shapekey change
  1023. * @param {Object3D} object target object
  1024. */
  1025. exports.sync_bounding = function (object, scene) {
  1026. if (!scene)
  1027. scene = object.scenes_data[0].scene;
  1028. if (!m_phy.scene_has_physics(scene))
  1029. return;
  1030. m_phy.sync_bounding(object, scene);
  1031. }
  1032. /**
  1033. * Synchronize collision mesh, e.g. after shapekey change
  1034. * @param {Object3D} object
  1035. */
  1036. exports.sync_mesh = function (object, scene) {
  1037. if (!scene)
  1038. scene = object.scenes_data[0].scene;
  1039. if (!m_phy.scene_has_physics(scene))
  1040. return;
  1041. m_phy.sync_mesh(object, scene);
  1042. }
  1043. }
  1044. var physics_factory = register("physics", Physics);
  1045. export default physics_factory;