UserMovement.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. "atomic component";
  2. var glmatrix = require("gl-matrix");
  3. var quat = glmatrix.quat;
  4. var vec3 = glmatrix.vec3;
  5. var MATH_RAD_TO_DEG = 360 / Math.PI
  6. exports.component = function(self) {
  7. var BRAKE_FORCE = 0.028;
  8. var MOVE_FORCE = 0.3;
  9. var camNode
  10. var charNode
  11. var charBody
  12. var charAnimCtrl
  13. var cameraToCharVector
  14. var camera
  15. var screenWidth
  16. var screenHeight
  17. self.start = function() {
  18. charNode = self.node
  19. camera = charNode.scene.getMainCamera()
  20. camNode = camera.node
  21. cameraToCharVector = [0, 0, 0]
  22. var charPos = [0, 0, 0]
  23. // We define the cameraToCharVector as the vector with origin in the character
  24. // and that ends up on the camera position.
  25. // Initial vector value is computed from the initial state of the scene.
  26. vec3.add(cameraToCharVector, camNode.getWorldPosition(), vec3.negate(charPos, charNode.getWorldPosition()))
  27. charBody = charNode.getComponent("RigidBody")
  28. charBody.angularFactor = [0, 0, 0]
  29. charAnimCtrl = charNode.getComponent("AnimationController");
  30. // Set the rigidbody to signal collision also when in rest, so that we get ground collisions properly
  31. charBody.collisionEventMode = Atomic.COLLISION_ALWAYS;
  32. screenWidth = Atomic.graphics.width
  33. screenHeight = Atomic.graphics.height
  34. }
  35. self.update = function(timeStep) {
  36. var mousePos = Atomic.input.getMousePosition()
  37. var inputData = updateInputData()
  38. // Update movement & animation
  39. var velocity = charBody.getLinearVelocity();
  40. var moveDir = [0, 0, 0];
  41. if (inputData.moveUp) {
  42. vec3.add(moveDir, moveDir, [0, 0, -1]);
  43. }
  44. if (inputData.moveDown) {
  45. vec3.add(moveDir, moveDir, [0, 0, 1]);
  46. }
  47. if (inputData.moveLeft) {
  48. vec3.add(moveDir, moveDir, [1, 0, 0]);
  49. }
  50. if (inputData.moveRight) {
  51. vec3.add(moveDir, moveDir, [-1, 0, 0]);
  52. }
  53. // Scale the vector to match the acceleration of the character
  54. vec3.normalize(moveDir, moveDir)
  55. vec3.scale(moveDir, moveDir, MOVE_FORCE);
  56. charBody.applyImpulse(moveDir)
  57. // Velocity on the XZ plane
  58. var planeVelocity = [velocity[0], 0.0, velocity[2]]
  59. vec3.negate(planeVelocity, planeVelocity)
  60. vec3.scale(planeVelocity, planeVelocity, BRAKE_FORCE)
  61. charBody.applyImpulse(planeVelocity)
  62. var newCamPos = [0, 0, 0]
  63. vec3.add(newCamPos, charNode.getWorldPosition(), cameraToCharVector)
  64. camNode.setWorldPosition(newCamPos)
  65. var scene = self.node.scene
  66. var octree = scene.getComponent("Octree")
  67. var origin = camNode.getWorldPosition()
  68. var mouseX = inputData.mousePos[0]
  69. var mouseY = inputData.mousePos[1]
  70. // Create a ray from the origin (users POV) that passes through the (mouseX, mouseY) point
  71. // in the near plane of the camera.
  72. var ray = camera.getScreenRay(mouseX / screenWidth, mouseY / screenHeight)
  73. // Perform raycasting
  74. var rayCastHits = octree.rayCastSingle(ray, Atomic.RAY_TRIANGLE, 250, Atomic.DRAWABLE_GEOMETRY)
  75. // If we hit something we take into account the XZ coordinates of the
  76. // hit object and get the vector describing the direction to which the
  77. // character is heading
  78. if (rayCastHits) {
  79. var charHeadingPlaneXZ = [0, 0,- 1]
  80. var rayHitPosPlaneXZ = rayCastHits.position
  81. rayHitPosPlaneXZ[1] = 0
  82. var charPosPlaneXZ = charNode.getWorldPosition()
  83. charPosPlaneXZ[1] = 0
  84. var charHeading = vec3.add([0, 0, 0], rayHitPosPlaneXZ, vec3.negate([0, 0, 0], charPosPlaneXZ))
  85. charHeadingPlaneXZ = charHeading
  86. charHeadingPlaneXZ[1] = 0
  87. var initHeading = [0, 0, -1]
  88. vec3.normalize(initHeading, initHeading)
  89. vec3.normalize(charHeadingPlaneXZ, charHeadingPlaneXZ)
  90. // Create a rotation quaternion to describe rotation from characters initial
  91. // heading to the computed char heading direction
  92. var rotationQ = quat.rotationTo([0, 0, 0, 0], [0, 0, -1], charHeadingPlaneXZ)
  93. // Here there is a little gotcha with quaternion math and JS
  94. // The engine expects the quaternion components to be ordered
  95. // differently than gl-matrix order so we just switch the order to match
  96. // the engines before appling rotation.
  97. quat.set(rotationQ, rotationQ[3], rotationQ[0], rotationQ[1], rotationQ[2])
  98. charNode.rotation = rotationQ
  99. }
  100. var idle = !(Math.abs(velocity[0]) >= 0.01 || Math.abs(velocity[2]) > 0.01)
  101. if (idle)
  102. charAnimCtrl.playExclusive("Idle", 0, true, 0.0)
  103. else
  104. charAnimCtrl.playExclusive("Run", 0, true, 0.0)
  105. }
  106. }
  107. function updateInputData() {
  108. var input = Atomic.input;
  109. moveUp = false;
  110. moveDown = false;
  111. moveLeft = false;
  112. moveRight = false;
  113. button0 = false;
  114. button1 = false;
  115. //check input
  116. if (input.getKeyDown(Atomic.KEY_W) || input.getKeyDown(Atomic.KEY_UP))
  117. moveUp = true;
  118. if (input.getKeyDown(Atomic.KEY_S) || input.getKeyDown(Atomic.KEY_DOWN))
  119. moveDown = true;
  120. if (input.getKeyDown(Atomic.KEY_A) || input.getKeyDown(Atomic.KEY_LEFT))
  121. moveLeft = true;
  122. if (input.getKeyDown(Atomic.KEY_D) || input.getKeyDown(Atomic.KEY_RIGHT))
  123. moveRight = true;
  124. if (input.getKeyPress(Atomic.KEY_F))
  125. button0 = true;
  126. if (input.getKeyPress(Atomic.KEY_SPACE))
  127. button1 = true;
  128. return {
  129. moveUp: moveUp,
  130. moveDown: moveDown,
  131. moveLeft: moveLeft,
  132. moveRight: moveRight,
  133. mousePos: input.getMousePosition()
  134. }
  135. }