UIJoystick.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. import { _decorator, Node, EventTouch, Touch, Component, UITransform, Input, EventKeyboard, KeyCode, v2, Vec3, input, Scene, director, EventMouse, macro, view, screen, isValid } from 'cc';
  2. import { EasyControllerEvent } from './EasyController';
  3. const { ccclass, property } = _decorator;
  4. /****
  5. * split screen into three parts.
  6. * ---------------------------------------------
  7. * |
  8. * 1.camera rotation zone |
  9. * |
  10. *----------------------------------------------|
  11. * | |
  12. * 2.movement ctrl zone | 3.camera rotation zone|
  13. * | |
  14. * ----------------------------------------------
  15. *
  16. * multi-touch for camera zoom.
  17. * */
  18. @ccclass('tgxUIJoystick')
  19. export class UIJoystick extends Component {
  20. private static _inst: UIJoystick = null;
  21. public static get inst(): UIJoystick {
  22. return this._inst;
  23. }
  24. private _ctrlRoot: UITransform = null;
  25. private _ctrlPointer: Node = null;
  26. private _buttons: Node = null;
  27. private _cameraSensitivity: number = 0.1;
  28. private _distanceOfTwoTouchPoint: number = 0;
  29. private _movementTouch: Touch = null;
  30. private _cameraTouchA: Touch = null;
  31. private _cameraTouchB: Touch = null;
  32. private _fullscreen:UITransform = null;
  33. private _key2buttonMap = {};
  34. protected onLoad(): void {
  35. UIJoystick._inst = this;
  36. this._key2buttonMap[KeyCode.KEY_J] = 'btn_slot_0';
  37. this._key2buttonMap[KeyCode.KEY_K] = 'btn_slot_1';
  38. this._key2buttonMap[KeyCode.KEY_L] = 'btn_slot_2';
  39. this._key2buttonMap[KeyCode.KEY_U] = 'btn_slot_3';
  40. this._key2buttonMap[KeyCode.KEY_I] = 'btn_slot_4';
  41. let checkerCamera = this.node.getChildByName('checker_camera').getComponent(UITransform);
  42. checkerCamera.node.on(Input.EventType.TOUCH_START, this.onTouchStart_CameraCtrl, this);
  43. checkerCamera.node.on(Input.EventType.TOUCH_MOVE, this.onTouchMove_CameraCtrl, this);
  44. checkerCamera.node.on(Input.EventType.TOUCH_END, this.onTouchUp_CameraCtrl, this);
  45. checkerCamera.node.on(Input.EventType.TOUCH_CANCEL, this.onTouchUp_CameraCtrl, this);
  46. let checkerMovement = this.node.getChildByName('checker_movement').getComponent(UITransform);
  47. checkerMovement.node.on(Input.EventType.TOUCH_START, this.onTouchStart_Movement, this);
  48. checkerMovement.node.on(Input.EventType.TOUCH_MOVE, this.onTouchMove_Movement, this);
  49. checkerMovement.node.on(Input.EventType.TOUCH_END, this.onTouchUp_Movement, this);
  50. checkerMovement.node.on(Input.EventType.TOUCH_CANCEL, this.onTouchUp_Movement, this);
  51. this._fullscreen = this.node.getComponent(UITransform);
  52. this._ctrlRoot = this.node.getChildByName('ctrl').getComponent(UITransform);
  53. this._ctrlRoot.node.active = false;
  54. this._ctrlPointer = this._ctrlRoot.node.getChildByName('pointer');
  55. this._buttons = this.node.getChildByName('buttons');
  56. input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
  57. input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
  58. input.on(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
  59. }
  60. onDestroy() {
  61. input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
  62. input.off(Input.EventType.KEY_UP, this.onKeyUp, this);
  63. input.off(Input.EventType.MOUSE_WHEEL, this.onMouseWheel, this);
  64. UIJoystick._inst = null;
  65. }
  66. cleanKeyMap() {
  67. this._key2buttonMap = {};
  68. }
  69. bindKeyToButton(keyCode: KeyCode, btnName: string) {
  70. this._key2buttonMap[keyCode] = btnName;
  71. }
  72. setButtonVisible(btnName: string, visible: boolean) {
  73. let node = this._buttons?.getChildByName(btnName);
  74. if (node) {
  75. node.active = visible;
  76. }
  77. }
  78. getButtonByName(btnName: string): Node {
  79. return this._buttons.getChildByName(btnName);
  80. }
  81. onTouchStart_Movement(event: EventTouch) {
  82. let touches = event.getTouches();
  83. for (let i = 0; i < touches.length; ++i) {
  84. let touch = touches[i];
  85. let x = touch.getUILocationX();
  86. let y = touch.getUILocationY();
  87. if (!this._movementTouch) {
  88. //we sub halfWidth,halfHeight here.
  89. //because, the touch event use left bottom as zero point(0,0), ui node use the center of screen as zero point(0,0)
  90. //this._ctrlRoot.setPosition(x - halfWidth, y - halfHeight, 0);
  91. let halfWidth = this._fullscreen.width / 2;
  92. let halfHeight = this._fullscreen.height / 2;
  93. this._ctrlRoot.node.active = true;
  94. this._ctrlRoot.node.setPosition(x - halfWidth, y - halfHeight, 0);
  95. this._ctrlPointer.setPosition(0, 0, 0);
  96. this._movementTouch = touch;
  97. }
  98. }
  99. }
  100. onTouchMove_Movement(event: EventTouch) {
  101. let touches = event.getTouches();
  102. for (let i = 0; i < touches.length; ++i) {
  103. let touch = touches[i];
  104. if (this._movementTouch && touch.getID() == this._movementTouch.getID()) {
  105. let halfWidth = this._fullscreen.width / 2;
  106. let halfHeight = this._fullscreen.height / 2;
  107. let x = touch.getUILocationX();
  108. let y = touch.getUILocationY();
  109. let pos = this._ctrlRoot.node.position;
  110. let ox = x - halfWidth - pos.x;
  111. let oy = y - halfHeight - pos.y;
  112. let len = Math.sqrt(ox * ox + oy * oy);
  113. if (len <= 0) {
  114. return;
  115. }
  116. let dirX = ox / len;
  117. let dirY = oy / len;
  118. let radius = this._ctrlRoot.width / 2;
  119. if (len > radius) {
  120. len = radius;
  121. ox = dirX * radius;
  122. oy = dirY * radius;
  123. }
  124. this._ctrlPointer.setPosition(ox, oy, 0);
  125. // degree 0 ~ 360 based on x axis.
  126. let degree = Math.atan(dirY / dirX) / Math.PI * 180;
  127. if (dirX < 0) {
  128. degree += 180;
  129. }
  130. else {
  131. degree += 360;
  132. }
  133. this.emitEvent(EasyControllerEvent.MOVEMENT, degree, len / radius);
  134. }
  135. }
  136. }
  137. onTouchUp_Movement(event: EventTouch) {
  138. let touches = event.getTouches();
  139. for (let i = 0; i < touches.length; ++i) {
  140. let touch = touches[i];
  141. if (this._movementTouch && touch.getID() == this._movementTouch.getID()) {
  142. this.emitEvent(EasyControllerEvent.MOVEMENT_STOP);
  143. this._movementTouch = null;
  144. this._ctrlRoot.node.active = false;
  145. }
  146. }
  147. }
  148. private getDistOfTwoTouchPoints(): number {
  149. let touchA = this._cameraTouchA;
  150. let touchB = this._cameraTouchB;
  151. if (!touchA || !touchB) {
  152. return 0;
  153. }
  154. let dx = touchA.getLocationX() - touchB.getLocationX();
  155. let dy = touchB.getLocationY() - touchB.getLocationY();
  156. return Math.sqrt(dx * dx + dy * dy);
  157. }
  158. private onTouchStart_CameraCtrl(event: EventTouch) {
  159. this.emitEvent(EasyControllerEvent.SCREEN_TOUCH_START, event);
  160. let touches = event.getAllTouches();
  161. this._cameraTouchA = null;
  162. this._cameraTouchB = null;
  163. for (let i = touches.length - 1; i >= 0; i--) {
  164. let touch = touches[i];
  165. if (this._movementTouch && touch.getID() == this._movementTouch.getID()) {
  166. continue;
  167. }
  168. if (this._cameraTouchA == null) {
  169. this._cameraTouchA = touches[i];
  170. }
  171. else if (this._cameraTouchB == null) {
  172. this._cameraTouchB = touches[i];
  173. break;
  174. }
  175. }
  176. this._distanceOfTwoTouchPoint = this.getDistOfTwoTouchPoints();
  177. }
  178. private onTouchMove_CameraCtrl(event: EventTouch) {
  179. let touches = event.getTouches();
  180. for (let i = 0; i < touches.length; ++i) {
  181. let touch = touches[i];
  182. let touchID = touch.getID();
  183. //two touches, do camera zoom.
  184. if (this._cameraTouchA && this._cameraTouchB) {
  185. console.log(touchID, this._cameraTouchA.getID(), this._cameraTouchB.getID());
  186. let needZoom = false;
  187. if (touchID == this._cameraTouchA.getID()) {
  188. this._cameraTouchA = touch;
  189. needZoom = true;
  190. }
  191. if (touchID == this._cameraTouchB.getID()) {
  192. this._cameraTouchB = touch;
  193. needZoom = true;
  194. }
  195. if (needZoom) {
  196. let newDist = this.getDistOfTwoTouchPoints();
  197. let delta = this._distanceOfTwoTouchPoint - newDist;
  198. this.emitEvent(EasyControllerEvent.CAMERA_ZOOM, delta);
  199. this._distanceOfTwoTouchPoint = newDist;
  200. }
  201. }
  202. //only one touch, do camera rotate.
  203. else if (this._cameraTouchA && touchID == this._cameraTouchA.getID()) {
  204. let dt = touch.getDelta();
  205. let rx = dt.y * this._cameraSensitivity;
  206. let ry = -dt.x * this._cameraSensitivity;
  207. this.emitEvent(EasyControllerEvent.CAMERA_ROTATE, rx, ry);
  208. }
  209. }
  210. }
  211. private onTouchUp_CameraCtrl(event: EventTouch) {
  212. this.emitEvent(EasyControllerEvent.SCREEN_TOUCH_END, event);
  213. let touches = event.getAllTouches();
  214. let hasTouchA = false;
  215. let hasTouchB = false;
  216. for (let i = 0; i < touches.length; ++i) {
  217. let touch = touches[i];
  218. let touchID = touch.getID();
  219. if (this._cameraTouchA && touchID == this._cameraTouchA.getID()) {
  220. hasTouchA = true;
  221. }
  222. else if (this._cameraTouchB && touchID == this._cameraTouchB.getID()) {
  223. hasTouchB = true;
  224. }
  225. }
  226. if (!hasTouchA) {
  227. this._cameraTouchA = null;
  228. }
  229. if (!hasTouchB) {
  230. this._cameraTouchB = null;
  231. }
  232. }
  233. private _keys = [];
  234. private _degree: number = 0;
  235. onKeyDown(event: EventKeyboard) {
  236. let keyCode = event.keyCode;
  237. if (keyCode == KeyCode.KEY_A || keyCode == KeyCode.KEY_S || keyCode == KeyCode.KEY_D || keyCode == KeyCode.KEY_W) {
  238. if (this._keys.indexOf(keyCode) == -1) {
  239. this._keys.push(keyCode);
  240. this.updateDirection();
  241. }
  242. }
  243. else {
  244. let btnName = this._key2buttonMap[keyCode];
  245. if (btnName) {
  246. this.emitEvent(EasyControllerEvent.BUTTON, btnName);
  247. }
  248. }
  249. }
  250. onKeyUp(event: EventKeyboard) {
  251. let keyCode = event.keyCode;
  252. if (keyCode == KeyCode.KEY_A || keyCode == KeyCode.KEY_S || keyCode == KeyCode.KEY_D || keyCode == KeyCode.KEY_W) {
  253. let index = this._keys.indexOf(keyCode);
  254. if (index != -1) {
  255. this._keys.splice(index, 1);
  256. this.updateDirection();
  257. }
  258. }
  259. }
  260. onMouseWheel(event: EventMouse) {
  261. let delta = event.getScrollY() * 0.1;
  262. //console.log(delta);
  263. this.emitEvent(EasyControllerEvent.CAMERA_ZOOM, delta);
  264. }
  265. onButtonSlot(event) {
  266. let btnName = event.target.name;
  267. this.emitEvent(EasyControllerEvent.BUTTON, btnName);
  268. }
  269. private _key2dirMap = null;
  270. updateDirection() {
  271. if (this._key2dirMap == null) {
  272. this._key2dirMap = {};
  273. this._key2dirMap[0] = -1;
  274. this._key2dirMap[KeyCode.KEY_A] = 180;
  275. this._key2dirMap[KeyCode.KEY_D] = 0;
  276. this._key2dirMap[KeyCode.KEY_W] = 90;
  277. this._key2dirMap[KeyCode.KEY_S] = 270;
  278. this._key2dirMap[KeyCode.KEY_A * 1000 + KeyCode.KEY_W] = this._key2dirMap[KeyCode.KEY_W * 1000 + KeyCode.KEY_A] = 135;
  279. this._key2dirMap[KeyCode.KEY_D * 1000 + KeyCode.KEY_W] = this._key2dirMap[KeyCode.KEY_W * 1000 + KeyCode.KEY_D] = 45;
  280. this._key2dirMap[KeyCode.KEY_A * 1000 + KeyCode.KEY_S] = this._key2dirMap[KeyCode.KEY_S * 1000 + KeyCode.KEY_A] = 225;
  281. this._key2dirMap[KeyCode.KEY_D * 1000 + KeyCode.KEY_S] = this._key2dirMap[KeyCode.KEY_S * 1000 + KeyCode.KEY_D] = 315;
  282. this._key2dirMap[KeyCode.KEY_A * 1000 + KeyCode.KEY_D] = this._key2dirMap[KeyCode.KEY_D];
  283. this._key2dirMap[KeyCode.KEY_D * 1000 + KeyCode.KEY_A] = this._key2dirMap[KeyCode.KEY_A];
  284. this._key2dirMap[KeyCode.KEY_W * 1000 + KeyCode.KEY_S] = this._key2dirMap[KeyCode.KEY_S];
  285. this._key2dirMap[KeyCode.KEY_S * 1000 + KeyCode.KEY_W] = this._key2dirMap[KeyCode.KEY_W];
  286. }
  287. let keyCode0 = this._keys[this._keys.length - 1] || 0;
  288. let keyCode1 = this._keys[this._keys.length - 2] || 0;
  289. this._degree = this._key2dirMap[keyCode1 * 1000 + keyCode0];
  290. if (this._degree == null || this._degree < 0) {
  291. this.emitEvent(EasyControllerEvent.MOVEMENT_STOP);
  292. }
  293. else {
  294. this.emitEvent(EasyControllerEvent.MOVEMENT, this._degree, 1.0);
  295. }
  296. }
  297. private emitEvent(type: string, arg0?: any, arg1?: any, arg2?: any, arg3?: any, arg4?: any) {
  298. director.emit(type, arg0, arg1, arg2, arg3, arg4);
  299. }
  300. }