FreeCamera.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import { _decorator, Component, Quat, Vec2, Vec3, Input, game, EventTouch, EventMouse, input, EventKeyboard, KeyCode, v2 } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. const v2_1 = new Vec2();
  4. const v2_2 = new Vec2();
  5. const v3_1 = new Vec3();
  6. const qt_1 = new Quat();
  7. const forward = new Vec3();
  8. const right = new Vec3();
  9. @ccclass('FreeCamera')
  10. export class FreeCamera extends Component {
  11. @property
  12. public moveSpeed = 1;
  13. @property
  14. public moveSpeedShiftScale = 5;
  15. @property({ slide: true, range: [0.05, 0.5, 0.01] })
  16. public damp = 0.2;
  17. @property
  18. public rotateSpeed = 1;
  19. private _euler = new Vec3();
  20. private _velocity = new Vec3();
  21. private _position = new Vec3();
  22. private _speedScale = 1;
  23. private _eulerP = new Vec3();
  24. public onLoad () {
  25. input.on(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
  26. input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
  27. input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
  28. input.on(Input.EventType.TOUCH_END, this.onTouchEnd, this);
  29. Vec3.copy(this._euler, this.node.eulerAngles);
  30. Vec3.copy(this._position, this.node.getPosition());
  31. Vec3.copy(this._eulerP, this.node.eulerAngles);
  32. input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
  33. input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
  34. }
  35. public onDestroy () {
  36. input.off(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
  37. input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
  38. input.off(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);
  39. input.off(Input.EventType.TOUCH_END, this.onTouchEnd, this);
  40. input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
  41. input.off(Input.EventType.KEY_UP, this.onKeyUp, this);
  42. }
  43. public update (dt: number) {
  44. const t = Math.min(dt / this.damp, 1);
  45. // position
  46. Vec3.transformQuat(v3_1, this._velocity, this.node.rotation);
  47. Vec3.scaleAndAdd(this._position, this._position, v3_1, this.moveSpeed * this._speedScale);
  48. Vec3.lerp(v3_1, this.node.getPosition(), this._position, t);
  49. this.node.setPosition(v3_1);
  50. if(this.moveDir.lengthSqr()){
  51. Vec3.transformQuat(forward, Vec3.FORWARD, this.node.rotation);
  52. forward.normalize();
  53. Vec3.cross(right, forward, Vec3.UP);
  54. right.normalize();
  55. Vec3.scaleAndAdd(this._position, this._position, forward, this.moveSpeed * this._speedScale * this.moveDir.z);
  56. Vec3.lerp(v3_1, this.node.getPosition(), this._position, t);
  57. this.node.setPosition(v3_1);
  58. Vec3.scaleAndAdd(this._position, this._position, right, this.moveSpeed * this._speedScale * this.moveDir.x);
  59. Vec3.lerp(v3_1, this.node.getPosition(), this._position, t);
  60. this.node.setPosition(v3_1);
  61. Vec3.scaleAndAdd(this._position, this._position, Vec3.UP, this.moveSpeed * this._speedScale * this.moveDir.y);
  62. Vec3.lerp(v3_1, this.node.getPosition(), this._position, t);
  63. this.node.setPosition(v3_1);
  64. }
  65. // rotation
  66. Quat.fromEuler(qt_1, this._eulerP.x, this._eulerP.y, this._eulerP.z);
  67. Quat.slerp(qt_1, this.node.rotation, qt_1, t);
  68. this.node.setWorldRotationFromEuler(this._eulerP.x, this._eulerP.y, this._eulerP.z);
  69. }
  70. public onMouseWheel (e: EventMouse) {
  71. const delta = -e.getScrollY() * this.moveSpeed * 0.1; // delta is positive when scroll down
  72. Vec3.transformQuat(v3_1, Vec3.UNIT_Z, this.node.rotation);
  73. Vec3.scaleAndAdd(this._position, this.node.position, v3_1, delta);
  74. }
  75. public onTouchStart (e: EventTouch) {
  76. if (game.canvas.requestPointerLock) { game.canvas.requestPointerLock(); }
  77. }
  78. public onTouchMove (e: EventTouch) {
  79. e.getStartLocation(v2_1);
  80. if (v2_1.x > game.canvas.width * 0.4) { // rotation
  81. e.getDelta(v2_2);
  82. this._eulerP.y -= v2_2.x * this.rotateSpeed * 0.1;
  83. this._eulerP.x += v2_2.y * this.rotateSpeed * 0.1;
  84. } else { // position
  85. e.getDelta(v2_2);
  86. this._eulerP.y -= v2_2.x * this.rotateSpeed * 0.1;
  87. this._eulerP.x += v2_2.y * this.rotateSpeed * 0.1;
  88. }
  89. }
  90. public onTouchEnd (e: EventTouch) {
  91. if (document.exitPointerLock) { document.exitPointerLock(); }
  92. e.getStartLocation(v2_1);
  93. if (v2_1.x < game.canvas.width * 0.4) { // position
  94. this._velocity.x = 0;
  95. this._velocity.z = 0;
  96. }
  97. }
  98. private keys = [];
  99. // x -1 left, +1 right y -1 backword, +1 forward
  100. private moveDir:Vec3 = new Vec3();
  101. onKeyDown(event:EventKeyboard){
  102. let keyCode = event.keyCode;
  103. if(keyCode == KeyCode.KEY_A || keyCode == KeyCode.KEY_S || keyCode == KeyCode.KEY_D || keyCode == KeyCode.KEY_W){
  104. if(this.keys.indexOf(keyCode) == -1){
  105. this.keys.push(keyCode);
  106. this.updateDirection();
  107. }
  108. }
  109. if(keyCode == KeyCode.KEY_Q){
  110. this.moveDir.y = -1;
  111. }
  112. else if(keyCode == KeyCode.KEY_E){
  113. this.moveDir.y = 1;
  114. }
  115. }
  116. onKeyUp(event:EventKeyboard){
  117. let keyCode = event.keyCode;
  118. if(keyCode == KeyCode.KEY_A || keyCode == KeyCode.KEY_S || keyCode == KeyCode.KEY_D || keyCode == KeyCode.KEY_W){
  119. let index = this.keys.indexOf(keyCode);
  120. if(index != -1){
  121. this.keys.splice(index,1);
  122. this.updateDirection();
  123. }
  124. }
  125. if(keyCode == KeyCode.KEY_Q || keyCode == KeyCode.KEY_E){
  126. this.moveDir.y = 0;
  127. }
  128. }
  129. private key2dirMap = null;
  130. updateDirection(){
  131. if(this.key2dirMap == null){
  132. this.key2dirMap = {};
  133. this.key2dirMap[0] = v2(0,0);
  134. this.key2dirMap[KeyCode.KEY_A] = v2(-1,0);
  135. this.key2dirMap[KeyCode.KEY_D] = v2(1,0);
  136. this.key2dirMap[KeyCode.KEY_W] = v2(0,1);
  137. this.key2dirMap[KeyCode.KEY_S] = v2(0,-1);
  138. this.key2dirMap[KeyCode.KEY_A * 1000 + KeyCode.KEY_W] = this.key2dirMap[KeyCode.KEY_W * 1000 + KeyCode.KEY_A] = v2(-1,1);
  139. this.key2dirMap[KeyCode.KEY_D * 1000 + KeyCode.KEY_W] = this.key2dirMap[KeyCode.KEY_W * 1000 + KeyCode.KEY_D] = v2(1,1);
  140. this.key2dirMap[KeyCode.KEY_A * 1000 + KeyCode.KEY_S] = this.key2dirMap[KeyCode.KEY_S * 1000 + KeyCode.KEY_A] = v2(-1,-1);
  141. this.key2dirMap[KeyCode.KEY_D * 1000 + KeyCode.KEY_S] = this.key2dirMap[KeyCode.KEY_S * 1000 + KeyCode.KEY_D] = v2(1,-1);
  142. this.key2dirMap[KeyCode.KEY_A * 1000 + KeyCode.KEY_D] = this.key2dirMap[KeyCode.KEY_D];
  143. this.key2dirMap[KeyCode.KEY_D * 1000 + KeyCode.KEY_A] = this.key2dirMap[KeyCode.KEY_A];
  144. this.key2dirMap[KeyCode.KEY_W * 1000 + KeyCode.KEY_S] = this.key2dirMap[KeyCode.KEY_S];
  145. this.key2dirMap[KeyCode.KEY_S * 1000 + KeyCode.KEY_W] = this.key2dirMap[KeyCode.KEY_W];
  146. }
  147. let keyCode0 = this.keys[this.keys.length - 1] || 0;
  148. let keyCode1 = this.keys[this.keys.length - 2] || 0;
  149. let dir = this.key2dirMap[keyCode1 * 1000 + keyCode0];
  150. this.moveDir.x = dir.x;
  151. this.moveDir.z = dir.y;
  152. }
  153. }