AvatarController.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // Atomic Component
  2. var glmatrix = require("gl-matrix");
  3. var quat = glmatrix.quat;
  4. var vec3 = glmatrix.vec3;
  5. var game = Atomic.game;
  6. var node = self.node;
  7. var cameraNode = game.cameraNode;
  8. var onGround = true;
  9. var okToJump = true;
  10. var inAirTime = 0;
  11. var MOVE_FORCE = 1.8;
  12. var INAIR_MOVE_FORCE = 0.02;
  13. var BRAKE_FORCE = 0.2;
  14. var JUMP_FORCE = 7.0;
  15. var YAW_SENSITIVITY = 0.1;
  16. var INAIR_THRESHOLD_TIME = 0.1;
  17. var cameraMode = 0;
  18. var yaw = 0;
  19. var pitch = 0;
  20. var moveForward = false;
  21. var moveBackwards = false;
  22. var moveLeft = false;
  23. var moveRight = false;
  24. var mouseMoveX = 0.0;
  25. var mouseMoveY = 0.0;
  26. var button0 = false;
  27. var button1 = false;
  28. var lastButton0 = false;
  29. var lastButton1 = false;
  30. self.idle = true;
  31. function start() {
  32. // Create rigidbody, and set non-zero mass so that the body becomes dynamic
  33. var body = node.createComponent("RigidBody");
  34. body.mass = 1.0;
  35. // Set zero angular factor so that physics doesn't turn the character on its own.
  36. // Instead we will control the character yaw manually
  37. body.angularFactor = [0, 0, 0];
  38. // Set the rigidbody to signal collision also when in rest, so that we get ground collisions properly
  39. body.collisionEventMode = Atomic.COLLISION_ALWAYS;
  40. // Set a capsule shape for collision
  41. var shape = node.createComponent("CollisionShape");
  42. shape.setCapsule(2, 4, [0, 2, 0]);
  43. }
  44. function fixedUpdate(timestep) {
  45. var body = node.getComponent("RigidBody");
  46. // Update the in air timer. Reset if grounded
  47. if (!onGround)
  48. inAirTimer += timeStep;
  49. else
  50. inAirTimer = 0.0;
  51. // When character has been in air less than 1/10 second, it's still interpreted as being on ground
  52. var softGrounded = inAirTimer < INAIR_THRESHOLD_TIME;
  53. var rot = node.getRotation();
  54. var moveDir = [0, 0, 0];
  55. // Update movement & animation
  56. var velocity = body.getLinearVelocity();
  57. // Velocity on the XZ plane
  58. var planeVelocity = [velocity[0], 0.0, velocity[2]];
  59. if (cameraMode != 2) {
  60. if (moveForward) {
  61. vec3.add(moveDir, moveDir, [0, 0, 1])
  62. }
  63. if (moveBackwards) {
  64. vec3.add(moveDir, moveDir, [0, 0, -1])
  65. }
  66. if (moveLeft) {
  67. vec3.add(moveDir, moveDir, [-1, 0, 0])
  68. }
  69. if (moveRight) {
  70. vec3.add(moveDir, moveDir, [1, 0, 0])
  71. }
  72. }
  73. if (vec3.length(moveDir) > 0.0)
  74. vec3.normalize(moveDir, moveDir);
  75. vec3.transformQuat(moveDir, moveDir, [rot[1], rot[2], rot[3], rot[0]]);
  76. vec3.scale(moveDir, moveDir, (softGrounded ? MOVE_FORCE : INAIR_MOVE_FORCE));
  77. body.applyImpulse(moveDir);
  78. if (softGrounded) {
  79. // When on ground, apply a braking force to limit maximum ground velocity
  80. vec3.negate(planeVelocity, planeVelocity);
  81. vec3.scale(planeVelocity, planeVelocity, BRAKE_FORCE);
  82. body.applyImpulse(planeVelocity);
  83. // Jump. Must release jump control inbetween jumps
  84. if (button1) {
  85. if (okToJump) {
  86. var jumpforce = [0, 1, 0];
  87. vec3.scale(jumpforce, jumpforce, JUMP_FORCE);
  88. body.applyImpulse(jumpforce);
  89. okToJump = false;
  90. }
  91. } else
  92. okToJump = true;
  93. }
  94. if (softGrounded && vec3.length(moveDir) > 0.0)
  95. self.idle = false;
  96. else
  97. self.idle = true;
  98. // Reset grounded flag for next frame
  99. onGround = true;
  100. }
  101. function MoveCamera(timeStep) {
  102. // Movement speed as world units per second
  103. var MOVE_SPEED = 10.0;
  104. // Mouse sensitivity as degrees per pixel
  105. var MOUSE_SENSITIVITY = 0.1;
  106. yaw = yaw + MOUSE_SENSITIVITY * mouseMoveX;
  107. pitch = pitch + MOUSE_SENSITIVITY * mouseMoveY;
  108. if (pitch < -90)
  109. pitch = -90;
  110. if (pitch > 90)
  111. pitch = 90;
  112. // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero
  113. cameraNode.rotation = QuatFromEuler(pitch, yaw, 0.0);
  114. var speed = MOVE_SPEED * timeStep;
  115. if (moveForward)
  116. cameraNode.translate([0.0, 0.0, speed])
  117. if (moveBackwards)
  118. cameraNode.translate([0.0, 0.0, -speed])
  119. if (moveLeft)
  120. cameraNode.translate([-speed, 0.0, 0.0])
  121. if (moveRight)
  122. cameraNode.translate([speed, 0.0, 0.0])
  123. }
  124. function UpdateControls() {
  125. var input = game.input;
  126. moveForward = false;
  127. moveBackwards = false;
  128. moveLeft = false;
  129. moveRight = false;
  130. mouseMoveX = 0.0;
  131. mouseMoveY = 0.0;
  132. button0 = false;
  133. button1 = false;
  134. // Movement speed as world units per second
  135. var MOVE_SPEED = 20.0;
  136. // Mouse sensitivity as degrees per pixel
  137. var MOUSE_SENSITIVITY = 0.1;
  138. if (input.getNumJoysticks()) {
  139. var state = GetGamepadState(0);
  140. if (state.axis0 < -0.5)
  141. moveLeft = true;
  142. if (state.axis0 > 0.5)
  143. moveRight = true;
  144. if (state.axis1 < -0.5)
  145. moveForward = true;
  146. if (state.axis1 > 0.5)
  147. moveBackwards = true;
  148. if (state.button0 && !lastButton0) {
  149. button0 = true;
  150. lastButton0 = true;
  151. } else if (!state.button0) {
  152. lastButton0 = false;
  153. }
  154. if (state.button1 && !lastButton1) {
  155. button1 = true;
  156. lastButton1 = true;
  157. } else if (!state.button1) {
  158. lastButton1 = false;
  159. }
  160. mouseMoveX = state.axis2 * 20;
  161. mouseMoveY = state.axis3 * 10;
  162. } else {
  163. if (input.getKeyDown(Atomic.KEY_W))
  164. moveForward = true;
  165. if (input.getKeyDown(Atomic.KEY_S))
  166. moveBackwards = true;
  167. if (input.getKeyDown(Atomic.KEY_A))
  168. moveLeft = true;
  169. if (input.getKeyDown(Atomic.KEY_D))
  170. moveRight = true;
  171. if (input.getKeyPress(Atomic.KEY_F))
  172. button0 = true;
  173. if (input.getKeyPress(Atomic.KEY_SPACE))
  174. button1 = true;
  175. mouseMoveX = input.getMouseMoveX();
  176. mouseMoveY = input.getMouseMoveY();
  177. }
  178. }
  179. function update(timeStep) {
  180. UpdateControls();
  181. if (cameraMode != 2) {
  182. yaw += mouseMoveX * YAW_SENSITIVITY;
  183. pitch += mouseMoveY * YAW_SENSITIVITY;
  184. }
  185. if (pitch < -80)
  186. pitch = -80;
  187. if (pitch > 80)
  188. pitch = 80;
  189. if (button0) {
  190. cameraMode++;
  191. if (cameraMode == 3)
  192. cameraMode = 0;
  193. }
  194. }
  195. function postUpdate(timestep) {
  196. // Get camera lookat dir from character yaw + pitch
  197. var rot = node.getRotation();
  198. dir = quat.create();
  199. quat.setAxisAngle(dir, [1, 0, 0], (pitch * Math.PI / 180.0));
  200. quat.multiply(dir, [rot[1], rot[2], rot[3], rot[0]], dir);
  201. var headNode = node.getChild("Head_Tip", true);
  202. if (cameraMode == 1) {
  203. var headPos = headNode.getWorldPosition();
  204. var offset = [0.0, 0.15, 0.2];
  205. vec3.add(headPos, headPos, vec3.transformQuat(offset, offset, [rot[1], rot[2], rot[3], rot[0]]));
  206. cameraNode.setPosition(headPos);
  207. cameraNode.setRotation([dir[3], dir[0], dir[1], dir[2]]);
  208. quat.setAxisAngle(dir, [0, 1, 0], (yaw * Math.PI / 180.0));
  209. node.setRotation([dir[3], dir[0], dir[1], dir[2]]);
  210. }
  211. if (cameraMode == 0) {
  212. var aimPoint = node.getPosition();
  213. var aimOffset = [0, 1.7, 0];
  214. vec3.transformQuat(aimOffset, aimOffset, dir);
  215. vec3.add(aimPoint, aimPoint, aimOffset);
  216. var rayDir = vec3.create();
  217. vec3.transformQuat(rayDir, [0, 0, -1], dir);
  218. vec3.scale(rayDir, rayDir, 12);
  219. vec3.add(aimPoint, aimPoint, rayDir);
  220. cameraNode.setPosition(aimPoint);
  221. cameraNode.setRotation([dir[3], dir[0], dir[1], dir[2]]);
  222. quat.setAxisAngle(dir, [0, 1, 0], (yaw * Math.PI / 180.0));
  223. node.setRotation([dir[3], dir[0], dir[1], dir[2]]);
  224. } else
  225. MoveCamera(timestep);
  226. }