joystick.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. import { _decorator, Component, Node, Enum, EventTouch, UITransformComponent, Vec3, view, UITransform, Vec2 } from "cc";
  2. import { config } from "../config";
  3. import { DirType } from "../data";
  4. import { car } from "./car";
  5. const { ccclass, property } = _decorator;
  6. //触摸类型
  7. const TOUCH_TYPE = Enum({
  8. DEFAULT: 0,//按钮和背景距离不变,背景位置与触碰点一致,不可改变按钮背景位置,按钮背景随着按钮移动而移动,松手后无法恢复到初始位置
  9. FOLLOW: 1,//按钮和背景距离不变,背景位置与触碰点一致,不可改变按钮背景位置,按钮背景随着按钮移动而移动,松手后恢复到初始位置
  10. FOLLOW_ALWAYS: 2, //按钮和背景距离不变,背景位置与触碰点一致,可改变按钮背景位置,按钮背景随着按钮移动而移动,松手后恢复到初始位置
  11. FOLLOW_DOT: 3 //按钮和背景距离可改变,按钮位置与触碰点可不一致,不可改变按钮背景位置,按钮背景不随着按钮移动而移动,松手后恢复到初始位置
  12. });
  13. //方向
  14. const DIRECTION_TYPE = Enum({
  15. FOUR: 4,
  16. EIGHT: 8,
  17. ALL: 0,
  18. });
  19. const screenHeight = view.getVisibleSize().height;//屏幕可视范围高度
  20. @ccclass("Joystick")
  21. export class Joystick extends Component {
  22. @property({type: Node, displayName: '摇杆背景节点'})
  23. public ndRing: Node = null!;
  24. @property({type: Node, displayName: '摇杆节点'})
  25. public ndDot: Node = null!;
  26. @property({type: TOUCH_TYPE, displayName: '触摸类型'})
  27. public touchType = TOUCH_TYPE.DEFAULT;
  28. @property({type: DIRECTION_TYPE, displayName: '方向类型'})
  29. public directionType = DIRECTION_TYPE.ALL;
  30. @property({displayName: '启动半透明'})
  31. public isEnableTransparent: boolean = false;
  32. @property({displayName: '点击跟随'})
  33. public isFollowStart: boolean = false;
  34. @property({displayName: '内圈大小'})
  35. public innerSize: number = 10;
  36. @property(Node) spr_dun:Node = null;
  37. public onClickCb: Function = null!;
  38. public onEndCb: Function = null!;
  39. public clearFECb: Function = null!;
  40. public onBeginFECb: Function = null!;
  41. public onSuccessFECb: Function = null!;
  42. public isMoving: boolean = false;//是否正在移动
  43. private mCar:car = null
  44. private mDir:DirType = DirType.NONE
  45. public get distanceRate () {
  46. return this._distanceRate;
  47. }
  48. public get angle () {
  49. return this._angle;
  50. }
  51. public set angle (v: number) {
  52. this._angle = v;
  53. }
  54. private _angle: number = 0;//当前的角度
  55. private _oriRingPos: Vec3 = null!;//圆圈初始位置
  56. private _targetRingPos: Vec3 = new Vec3();//圆圈背景位置
  57. private _touchStartLocation: Vec3 = new Vec3();//开始触碰位置
  58. private _touchMoveLocation: Vec3 = new Vec3();//移动触碰位置
  59. private _touchEndLocation: Vec3 = new Vec3();//结束触碰位置
  60. private _isOutInnerSize: Boolean = false;//终点拖动的点是否超出按钮圆圈背景
  61. private _distanceRate: number = 0; //遥感移动距离比
  62. private _checkInterval: number = 0.04;//每40ms刷新一次
  63. private _oldAngle: number = 0;//之前的角度
  64. private _oldDotPos: number = 0;
  65. private _currentTime: number = 0;//当前累积时间
  66. private _oriDotPos: Vec3 = new Vec3();//中间按钮初始坐标
  67. private _movePos: Vec3 = new Vec3();//移动坐标
  68. private _curRingPos_1: Vec3 = new Vec3();//当前圆圈坐标
  69. private _curRingPos_2: Vec3 = new Vec3();//
  70. private _origin_pos:Vec3 = Vec3.ZERO
  71. private mCallBack = null;
  72. start () {
  73. // Your initialization goes here.
  74. }
  75. public init(call_back,car:car)
  76. {
  77. this.mCar = car
  78. this.mCallBack = call_back
  79. this.node.on(Node.EventType.TOUCH_START, this._touchStartEvent, this);
  80. this.node.on(Node.EventType.TOUCH_MOVE, this._touchMoveEvent, this);
  81. // 触摸在圆圈内离开或在圆圈外离开后,摇杆归位,player速度为0
  82. this.node.on(Node.EventType.TOUCH_END, this._touchEndEvent, this);
  83. this.node.on(Node.EventType.TOUCH_CANCEL, this._touchEndEvent, this);
  84. }
  85. public unInit(){
  86. this.node.off(Node.EventType.TOUCH_START, this._touchStartEvent, this);
  87. this.node.off(Node.EventType.TOUCH_MOVE, this._touchMoveEvent, this);
  88. // 触摸在圆圈内离开或在圆圈外离开后,摇杆归位,player速度为0
  89. this.node.off(Node.EventType.TOUCH_END, this._touchEndEvent, this);
  90. this.node.off(Node.EventType.TOUCH_CANCEL, this._touchEndEvent, this);
  91. //重置
  92. this.isMoving = false;
  93. this.ndDot.setPosition(this._oriDotPos);
  94. this._origin_pos = this._oriDotPos
  95. if (this._oriRingPos) {
  96. this.ndRing.setPosition(this._oriRingPos);
  97. }
  98. }
  99. private _touchStartEvent (event: EventTouch) {
  100. // 记录触摸的世界坐标,给touch move使用
  101. // this.dot.opacity = 255;
  102. this._targetRingPos = null!;
  103. let touch = event.getUILocation();
  104. this._touchStartLocation.set(touch.x, touch.y, 0);
  105. let touchPos = this.node.getComponent(UITransformComponent)?.convertToNodeSpaceAR(this._touchStartLocation) as Vec3;
  106. if (!this._oriRingPos) {
  107. this._oriRingPos = this.ndRing.getPosition().clone();
  108. }
  109. // 记录摇杆位置,给touch move使用
  110. // this._stickPos.set(touchPos);
  111. this._isOutInnerSize = false;
  112. if (!this.isFollowStart) {
  113. touchPos = this.ndRing.getComponent(UITransformComponent)?.convertToNodeSpaceAR(this._touchStartLocation) as Vec3;
  114. //触摸点与圆圈中心的距离
  115. let distance = touchPos.length();
  116. let width = this.ndRing.getComponent(UITransformComponent)?.contentSize.width as number;
  117. //圆圈半径
  118. let radius = width / 2;
  119. //手指在圆圈内触摸,控杆跟随触摸点
  120. if (radius > distance) {
  121. this.ndDot.setPosition(touchPos);
  122. this._updateAngle(touchPos);
  123. return true;
  124. }
  125. return false;
  126. } else {
  127. //设置遥感可移动范围
  128. if (this.touchType === TOUCH_TYPE.FOLLOW) {
  129. touchPos.y = touchPos.y >= -screenHeight/6 ? -screenHeight/6 : touchPos.y;
  130. }
  131. this.ndRing.setPosition(touchPos);
  132. }
  133. }
  134. private _touchMoveEvent (event: EventTouch) {
  135. let touch = event.getUILocation();
  136. this._touchMoveLocation.set(touch.x, touch.y, 0);
  137. let touchPos = this.ndRing.getComponent(UITransformComponent)?.convertToNodeSpaceAR(this._touchMoveLocation) as Vec3;
  138. // if (this.touchType === TOUCH_TYPE.FOLLOW) {
  139. // let offsetPos = cc.v3(touchPos.x - this._stickPos.x, touchPos.y - this._stickPos.y, 0);
  140. // touchPos = offsetPos;
  141. // }
  142. let dir_type = DirType.NONE
  143. if(touchPos.x>this.ndDot.position.x){
  144. dir_type = DirType.RIGHT
  145. }else if(touchPos.x<this.ndDot.position.x){
  146. dir_type = DirType.LEFT
  147. }
  148. this.mDir = dir_type
  149. if(this.mDir!=dir_type){
  150. this._origin_pos = this.ndDot.position
  151. }
  152. let distance = touchPos.length();
  153. if (distance > this.innerSize) {
  154. this.isMoving = true;
  155. this._isOutInnerSize = true;
  156. } else {
  157. this._isOutInnerSize = false;
  158. }
  159. let width = this.ndRing.getComponent(UITransformComponent)?.contentSize.width as number;
  160. //圆圈半径
  161. let radius = width / 2;
  162. let rate = 0;
  163. // 由于摇杆的postion是以父节点为锚点,所以定位要加上ring和dot当前的位置(stickX,stickY)
  164. if (radius > distance) {
  165. rate = Number((distance / radius).toFixed(3));
  166. this.ndDot.setPosition(touchPos);
  167. }
  168. else if (this.touchType !== TOUCH_TYPE.FOLLOW_DOT) {
  169. rate = 1;
  170. //控杆永远保持在圈内,并在圈内跟随触摸更新角度
  171. let radian = Math.atan2(touchPos.y, touchPos.x);
  172. let x = Math.cos(radian) * radius;
  173. let y = Math.sin(radian) * radius;
  174. this._movePos.set(x, y, 0);
  175. if (this.touchType === TOUCH_TYPE.FOLLOW_ALWAYS) {
  176. this._curRingPos_2.set(touch.x - x, touch.y - y, 0);
  177. let ringPos = this.node.getComponent(UITransformComponent)?.convertToNodeSpaceAR(this._curRingPos_2) as Vec3;
  178. this._targetRingPos = ringPos;
  179. }
  180. this.ndDot.setPosition(this._movePos);
  181. } else {
  182. // 点跟随移动
  183. this.ndDot.setPosition(touchPos);
  184. }
  185. //更新角度
  186. this._updateAngle(touchPos);
  187. //更新遥感移动距离百分比
  188. this._distanceRate = rate;
  189. }
  190. private _touchEndEvent (event: EventTouch) {
  191. if (!this.isMoving) {
  192. //可以判断为点击
  193. this.onClickCb && this.onClickCb();
  194. } else {
  195. let touch = event.getUILocation();
  196. this._touchEndLocation.set(touch.x, touch.y, 0);
  197. let touchPos = this.ndRing.getComponent(UITransformComponent)?.convertToNodeSpaceAR(this._touchEndLocation) as Vec3;
  198. let isDragToInner = false;
  199. if (touchPos.length() < this.innerSize) {
  200. //取消掉
  201. isDragToInner = true;
  202. this.onEndCb && this.onEndCb(isDragToInner);
  203. } else {
  204. this.onEndCb && this.onEndCb(isDragToInner);
  205. }
  206. }
  207. this.isMoving = false;
  208. this.mDir = DirType.NONE
  209. this.ndDot.setPosition(this._oriDotPos);
  210. this._origin_pos = this._oriDotPos
  211. if (this.touchType === TOUCH_TYPE.FOLLOW || this.touchType === TOUCH_TYPE.FOLLOW_ALWAYS || this.touchType === TOUCH_TYPE.FOLLOW_DOT) {
  212. this._targetRingPos = null!;
  213. this.ndRing.setPosition(this._oriRingPos);
  214. }
  215. }
  216. private _updateAngle (pos: Vec3) {
  217. this._angle = Math.round(Math.atan2(pos.y, pos.x) * 180 / Math.PI);
  218. return this._angle;
  219. }
  220. public reset () {
  221. this.isMoving = false;
  222. this._origin_pos = this._oriDotPos
  223. this.ndDot.setPosition(this._oriDotPos);
  224. }
  225. public getJoyInfo(){
  226. this.mCar.setDir(this.mDir)
  227. console.log("this.mDir",this.mDir)
  228. this.mCar.setMoveSpeedX(Math.abs(this.ndDot.position.x-this._origin_pos.x)/130*50)
  229. }
  230. update (deltaTime: number) {
  231. // Your update function goes here.
  232. //设置终终点按钮位置
  233. // if (this._targetRingPos) {
  234. // this._curRingPos_1.set(0, 0, 0);
  235. // Vec3.lerp(this._curRingPos_1, this.ndRing.position, this._targetRingPos, 20 * deltaTime);
  236. // this.ndRing.setPosition(this._curRingPos_1);
  237. // }
  238. this._currentTime += deltaTime;
  239. if (this._currentTime >= this._checkInterval) {
  240. this._currentTime = 0;
  241. if (this.isMoving) {
  242. if (this.angle !== this._oldAngle) {
  243. this._oldAngle = this.angle;
  244. }
  245. } else {
  246. this.isMoving = false;
  247. }
  248. if(this.mCallBack !=null ){
  249. this.mCallBack()
  250. }
  251. this._oldDotPos = this.ndDot.position.x
  252. this.getJoyInfo()
  253. }
  254. }
  255. }