UserGuide.ts 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843
  1. /**
  2. * The introduction of two main APIs.
  3. *
  4. * @format
  5. */
  6. /*** 两个主要接口说明。*/
  7. /**
  8. * @en
  9. * Shows guides or a single guide.
  10. * @param step Which step to be guided, 1 by default. You may also pass the alias name of the step.
  11. * @param isAuto Is to play the next guide automatically, false by default.
  12. * @param callback Takes a callback function. which will be called the user completes the current guide. Only works when the parameter isAuto is false. Should use this parameter in single step guide type.
  13. *
  14. * @zh
  15. * 显示连续或单步引导。
  16. * @param step 新手引导的第几步,默认是第一步。也可以传入该引导步骤的别名。
  17. * @param isAuto 完成当前引导后是否自动播放下一个引导。
  18. * @param callback 接收一个回调函数,当用户完成当前引导后会执行该回调函数。只有isAuto为false时才有效,适用于单步引导。
  19. */
  20. // showGuide(step:number|string, isAuto:boolean=false, callback: Function=null)
  21. /**
  22. * @en
  23. * Shows the guide by group.
  24. * @param stepArray The guide steps array, [1, 3, 5] means to execute the fist, the third and the fifth guide step. You may also pass an alias array, e.g., ['alias of guide step1', 'alias of guide step 2'];
  25. * @param callback Takes a callback function. which will be called the user completes the current guide.
  26. * @zh
  27. * 按分组显示引导。
  28. * @param stepArray 要执行各个引导步骤,比如传入[1, 3, 5]表示一次执行第一、第三和第五步引导。也可以传入别名数组['第一步引导别名', '第二步引导别名']。
  29. * @param callback 接收一个回调函数,当用户完成当前引导后会执行该回调函数。
  30. */
  31. // showGuideByGroup(stepArray:Array<number|string>, callback: Function=null)
  32. /**
  33. * @en
  34. * Hides all nodes related to user guide.
  35. * @zh
  36. * 隐藏与引导相关的所有节点。
  37. */
  38. // hideGuide()
  39. /*** Other APIs that are used to adjust the user guide. They have to be called before showGuide() or showGuideByGroup(). */
  40. /*** 其他用于调整引导效果的接口,须在showGuide()或showGuideByGroup()方法前调用。*/
  41. /**
  42. * @en
  43. * Sets the mask color, black and half transparent by default.
  44. * @zh
  45. * 设置遮罩层颜色,默认为黑色半透明。
  46. */
  47. // setMaskColor(color: Color)
  48. /**
  49. * @en
  50. * Sets the mask shape, rect by default. Param value can be 'rect', 'ellipse' or 'sprite stencil'.
  51. * @zh
  52. * 设置遮罩挖洞形状,默认为矩形。参数可选值有'rect','ellipse'或者'sprite stencil'。
  53. */
  54. // setMaskShape(shape: string)
  55. /**
  56. * @en
  57. * Sets the line height of guide text, 28 by default.
  58. * @zh
  59. * 设置引导文本行高,默认为40。
  60. */
  61. // setGuideTextLineHeight(lineHeight: number)
  62. /**
  63. * @en
  64. * Sets the font size of guide text, 28 by default.
  65. * @zh
  66. * 设置引导文本字体大小,默认为28。
  67. */
  68. // setGuideTextFontSize(fontSize: number)
  69. /**
  70. * @en
  71. * Sets the system font of guide text.
  72. * @zh
  73. * 设置引导文本的系统字体。
  74. */
  75. // setGuideTextSystemFont(sysFontName: string)
  76. /**
  77. * @en
  78. * Sets the custom font of guide text.
  79. * @param pathInRes The path of the custom font in resources folder. The format should be ttf and the path should end without the extension name .ttf.
  80. * @zh
  81. * @param pathInRes 自定义字体在resources文件夹中的路径,字体格式为ttf,注意路径最后不带后缀名.ttf。
  82. * 设置引导文本自定义字体。
  83. */
  84. // setGuideTextCustomFont(pathInRes: string)
  85. /**
  86. * @en
  87. * Sets the color of guide text, black by default.
  88. * @zh
  89. * 设置引导文本颜色,默认为黑色。
  90. */
  91. // setGuideTextColor(color: Color)
  92. /**
  93. * @en
  94. * Sets the position of guide text.
  95. * @param textPos Where to show the guide text. Choices are Vec3 type of value (position on Canvas), or string type of value: 'follow', 'center' and 'bottom'. 'follow' means showing next to the target node, 'center' means showing in the center of Canvas and 'bottom' means showing at the bottom of Canvas.
  96. * @zh
  97. * 设置引导文本位置。
  98. * @param textPos 要在哪里显示引导文本,可以是Vec3类型的值,即在画布上的具体位置,或者是字符串类型的值'follow'、'center'和'bottom'。'follow'表示显示在目标节点周围,'center'表示显示在画布中间,'bottom'表示显示在画布底部。
  99. */
  100. // setGuideTextPos(textPos: cc.Vec3 | string='follow')
  101. /**
  102. * @en
  103. * Sets the language type of guide text, 'zh' by default, the other value is 'en'.
  104. * @zh
  105. * 设置引导文本语言种类,默认是'zh',其他可选值为'en'。
  106. */
  107. // setGuideTextLang(lang: string='zh')
  108. /**
  109. * @en
  110. * Sets the scale of guide text background node.
  111. * @zh
  112. * 设置引导文本背景缩放值。
  113. */
  114. // setGuideTextBackgroundScale(scaleX: number, scaleY: number)
  115. /**
  116. * @en
  117. * Sets the scale of guide sign node.
  118. * @zh
  119. * 设置引导图片缩放值。
  120. */
  121. // setGuideSignScale(scaleX: number, scaleY: number)
  122. /**
  123. * @en
  124. * Slides the guide sign node, i.e., move from one position to another. This method suits the game which needs a slide guide. Note this method only works for hand or arrow type of guide sign.
  125. * @param slideDistance The slide distance.
  126. * @param slideTime The slide time.
  127. * @zh
  128. * 滑动引导图片,即从一个位置移动到另一个位置,适用于需要进行滑动引导的游戏。注意该方法只对手指或箭头类型的引导图片有效。
  129. * @param slideDistance 滑动位移。
  130. * @param slideTime 滑动时间。
  131. */
  132. // slideGuideSign(slideDistance: cc.Vec3, slideTime: number=2)
  133. /**
  134. * @en
  135. * Moves the guide sign node up and down,i.e., like poking. Note this method only works for hand or arrow type of guide sign.
  136. * @zh
  137. * 让引导图片上下运动,即拥有戳戳戳的效果。注意该方法只对手指或箭头类型的引导图片有效。
  138. */
  139. // makeGuideSignMoveUpAndDown()
  140. /**
  141. * @en
  142. * Sets the rotation of guide sign node. The default value is 90, i.e., 90°. Note this method only works for hand or arrow type of guide sign.
  143. * @zh
  144. * 设置引导图片的旋转角度,默认旋转值为90,即绕z轴旋转90°。注意该方法只对手指或箭头类型的引导图片有效。
  145. */
  146. // setGuideSignRotation(r: number=90)
  147. /**
  148. * @en
  149. * Sets the position of guide sign on Canvas.
  150. * @zh
  151. * 设置引导图片在画布上的位置。
  152. */
  153. // setGuideSignPos(pos: cc.Vec3)
  154. /**
  155. * @en
  156. * Stops the guide sign tween.
  157. * @zh
  158. * 停止引导图片缓动。
  159. */
  160. // stopGuideSignTween()
  161. /**
  162. * @en
  163. * Is to make the guide sign fly to the next node position after each guide. If false, the guide sign will hide, and show at next guide.
  164. * @zh
  165. * 完成一次引导后,是否让引导图片飞到下一个被引导节点的位置上。如果是false,则引导图片会先被隐藏,下次引导时再显示出来。
  166. */
  167. // setGuideSignFly(isFlying: boolean=false)
  168. /**
  169. * @en
  170. * Sets flying tween duration. The default is 0.3 second.
  171. * @zh
  172. * 设置飞行缓动持续时间。
  173. */
  174. // setGuideSignFlyingDuration(duration: number=0.3)
  175. /**
  176. * @en
  177. * Sets the interval between two key-down operations, 1.5 seconds by default. For example, if a user presses Ctrl, and then presses G within 1.5 seconds, We see them as combined keys. If over 1.5 seconds, then we see the user presses G only.
  178. * @zh
  179. * 设置两次按键之间的时间间隔,默认是1.5秒。比如用户先按下Ctrl键,并在1.5秒内按下G键,则判断用户按下了组合键。如果超过1.5秒,则判断为只按下了G键。
  180. */
  181. // setKeyDownInterval(interval: number)
  182. /**
  183. * @en
  184. * Is to enable the typing effect.
  185. * @zh
  186. * 是否开启打字机效果。
  187. */
  188. // setTypingEnabled(isEnabled: boolean)
  189. import {Data, Mgr} from '../GameControl'
  190. import {UI} from '../enums/UI'
  191. import {ConstValue} from '../data/ConstValue'
  192. import {ccUtils} from '../utils/ccUtils'
  193. import {UserGuideConfig} from '../config/UserGuideConfig'
  194. /**
  195. * @en
  196. * Typing interval (second) used in schedule, 0.05 second by default.
  197. * @zh
  198. * 设置打字机效果打字的时间间隔(秒),默认是0.05秒。
  199. */
  200. // setTypingInterval(interval: number)
  201. const {ccclass} = cc._decorator
  202. @ccclass
  203. export default class UserGuide extends cc.Component {
  204. /**
  205. * @en
  206. * The temp value for current step.
  207. * @zh
  208. * 用于记录当前引导步数。
  209. */
  210. currentStepTemp = 1
  211. /**
  212. * @en
  213. * The temp value for text pos.
  214. * @zh
  215. * 记录文本显示位置。
  216. */
  217. textPosTemp: cc.Vec3 | string = 'follow'
  218. /**
  219. * @en
  220. * The interval between two key-down operations.
  221. * @zh
  222. * 两次按键时间间隔。
  223. */
  224. keyDownInterval = 1.5
  225. /**
  226. * @en
  227. * Is to enable the typing effect, false by default.
  228. * @zh
  229. * 是否开启打字效果,默认不开启。
  230. */
  231. isTyping = false
  232. /**
  233. * @en
  234. * Typing interval (second) used in schedule.
  235. * @zh
  236. * 打字机效果打字的时间间隔(秒)。
  237. */
  238. typingInterval = 0.05
  239. /**
  240. * @en
  241. * Guide sprite rotation.
  242. * @zh
  243. * 引导图片角度。
  244. */
  245. guideSignRotation = 90
  246. /**
  247. * @en
  248. * Schedule count.
  249. * @zh
  250. * 调度次数。
  251. */
  252. scheduleCount = 0
  253. /**
  254. * @en
  255. * The temp value for guide text.
  256. * @zh
  257. * 引导文本副本。
  258. */
  259. guideTextTemp = ''
  260. /**
  261. * @en
  262. * Is to enable guide sign node tween.
  263. * @zh
  264. * 引导图片缓动是否开启。
  265. */
  266. isGuideSignTweenEnabled = false
  267. /**
  268. * @en
  269. * Current tween on guide sign node.
  270. * @zh
  271. * 引导图片缓动实例。
  272. */
  273. guideSignTween = null
  274. /**
  275. * @en
  276. * The tween type on guide sign node.
  277. * @zh
  278. * 引导图片的缓动类型。
  279. */
  280. guideSignTweenType = ''
  281. /**
  282. * @en
  283. * Is to make the guide sign fly to the next node position after each guide. If false, the guide sign will hide, and show at next guide.
  284. * @zh
  285. * 完成一次引导后,是否让引导图片飞到下一个被引导节点的位置上。如果是false,则引导图片会先被隐藏,下次引导时再显示出来。
  286. */
  287. isGudieSignFlying = false
  288. /**
  289. * @en
  290. * Guide sign flying tween.
  291. * @zh
  292. * 引导图片飞行缓动。
  293. */
  294. guideSignFlyingTween = null
  295. /**
  296. * @en
  297. * Guide sign flying tween duration.
  298. * @zh
  299. * 引导图片飞行缓动持续时间。
  300. */
  301. flyingTweenDuration = 0.3
  302. /**
  303. * @en
  304. * Is guide sign finished flying.
  305. * @zh
  306. * 引导图片飞行是否结束。
  307. */
  308. isFlyingFinised = true
  309. /**
  310. * @en
  311. * The data of slide tween on guide sign node。
  312. * @zh
  313. * 滑动缓动数据。
  314. */
  315. guideSignSlideTweenData = {
  316. slideDistance: null,
  317. slideTime: 0.5,
  318. }
  319. /**
  320. * @en
  321. * Is to guide by group.
  322. * @zh
  323. * 是否为分组引导。
  324. */
  325. isGuidedByGroup = false
  326. /**
  327. * @en
  328. * Saves the step when guiding by group.
  329. * @zh
  330. * 记录分组引导步数。
  331. */
  332. stepIndexInArray = 0
  333. /**
  334. * @en
  335. * The temp value for current step array.
  336. * @zh
  337. * 当前引导分组。
  338. */
  339. currentStepArrayTemp = []
  340. /**
  341. * @en
  342. * The guide data generated by user guide extension.
  343. * @zh
  344. * 用户通过插件生成的引导数据。
  345. */
  346. guideData = {
  347. nodesAndTexts: [],
  348. guideSignType: 'frame',
  349. }
  350. /**
  351. * @en
  352. * The language type of guide text, 'zh' by default, the other value is 'en'.
  353. * @zh
  354. * 引导文本语言种类,默认是'zh',其他可选值为'en'。
  355. */
  356. guideTextLang = 'zh'
  357. /**
  358. * @en
  359. * The UITransform component of canvas.
  360. * @zh
  361. * 画布的UITransform组件。
  362. */
  363. canvasUITransform = {width: 1920, height: 1080}
  364. /**
  365. * @en
  366. * The mask node which is generated dynamically.
  367. * @zh
  368. * 动态创建的遮罩节点。
  369. */
  370. maskNode: cc.Node = null!
  371. /**
  372. * @en
  373. * The child node of mask node, which has a BlockInputEvents component.
  374. * @zh
  375. * 遮罩节点下的子节点,含有BlockInputEvents组件。
  376. */
  377. blockBgNode: cc.Node = null!
  378. /**
  379. * @en
  380. * The guide sign node which is generated dynamically.
  381. * @zh
  382. * 动态创建的引导图片节点。
  383. */
  384. guideSignSpriteNode: cc.Node = null!
  385. /**
  386. * @en
  387. * Saves the position of guide sign set by developers.
  388. * @zh
  389. * 保存开发者设置的引导图片位置。
  390. */
  391. guideSignPosTemp: cc.Vec3 = null
  392. /**
  393. * @en
  394. * The guide text background node which is generated dynamically.
  395. * @zh
  396. * 动态创建的文本背景图片节点。
  397. */
  398. guideTextBgSpriteNode: cc.Node = null!
  399. /**
  400. * @en
  401. * The guide text node which is generated dynamically.
  402. * @zh
  403. * 动态创建的文本节点。
  404. */
  405. guideTextLabelNode: cc.Node = null!
  406. //角色节点
  407. roleNode: cc.Node = null!
  408. //角色spine
  409. roleSpine: sp.SkeletonData = null!
  410. // 图片bundle
  411. texBundle: cc.AssetManager.Bundle = null!
  412. // handSp
  413. handSp: cc.SpriteFrame = null!
  414. // 箭头
  415. arrowSp: cc.SpriteFrame = null!
  416. onLoad() {}
  417. start() {}
  418. init(roleSpine: sp.SkeletonData, texBundle: cc.AssetManager.Bundle) {
  419. this.guideData.nodesAndTexts = Object.values(UserGuideConfig)
  420. this.roleSpine = roleSpine
  421. this.texBundle = texBundle
  422. this.createNodes()
  423. this.setGuideTextCustomFont('ttf/COMICBD')
  424. this.makeGuideSignMoveUpAndDown()
  425. this.setTypingEnabled(false)
  426. this.guideData.nodesAndTexts.forEach((nodeAndText: any) => {
  427. nodeAndText.guideText = Mgr.i18n.getLabel(nodeAndText.guideText)
  428. nodeAndText.isAliased = true
  429. nodeAndText.alias = nodeAndText.ID
  430. })
  431. }
  432. /**
  433. * @en
  434. * Creates nodes dynamically needed for user guide.
  435. * @zh
  436. * 动态创建新手引导需要用到的节点。
  437. */
  438. createNodes() {
  439. this.createMaskNode()
  440. this.createBlockBgNode()
  441. this.createGuideSignSpriteNode()
  442. this.createGuideTextBgSpriteNode()
  443. this.createGuideTextLabelNode()
  444. }
  445. /**
  446. * @en
  447. * Creates mask node dynamically.
  448. * @zh
  449. * 动态创建遮罩节点。
  450. */
  451. createMaskNode() {
  452. this.maskNode = new cc.Node('Mask Node')
  453. this.maskNode.active = false
  454. this.maskNode.addComponent(cc.Mask)
  455. let maskSpNode = new cc.Node('Mask Sprite Node')
  456. let spriteComp = maskSpNode.addComponent(cc.Sprite)
  457. spriteComp.type = cc.Sprite.Type.SLICED
  458. this.texBundle.load('Public/light_effect_3', cc.SpriteFrame, (err: any, spriteFrame: cc.SpriteFrame) => {
  459. spriteComp.spriteFrame = spriteFrame
  460. spriteFrame.addRef()
  461. })
  462. this.maskNode.addChild(maskSpNode)
  463. maskSpNode.setSiblingIndex(Number.MAX_SAFE_INTEGER)
  464. this.node.addChild(this.maskNode)
  465. }
  466. /**
  467. * @en
  468. * Creates the child node of mask node dynamically. This node can block all input events.
  469. * @zh
  470. * 创建可排除所有输入事件的节点,作为遮罩节点的子节点。
  471. */
  472. createBlockBgNode() {
  473. this.blockBgNode = new cc.Node('Block Bg Node')
  474. this.blockBgNode.addComponent(cc.BlockInputEvents)
  475. let spriteComp = this.blockBgNode.addComponent(cc.Sprite)
  476. this.blockBgNode.color = new cc.Color(0, 0, 0)
  477. this.blockBgNode.opacity = 200
  478. let self = this
  479. this.texBundle.load('Public/block2', cc.SpriteFrame, (err: any, spriteFrame: cc.SpriteFrame) => {
  480. spriteComp.spriteFrame = spriteFrame
  481. self.blockBgNode.width = this.canvasUITransform.width * 10
  482. self.blockBgNode.height = this.canvasUITransform.height * 10
  483. spriteFrame.addRef()
  484. })
  485. this.maskNode.addChild(this.blockBgNode)
  486. this.blockBgNode.setSiblingIndex(0)
  487. }
  488. /**
  489. * @en
  490. * Creates the guide sign node and loads the sprite dynamically.
  491. * @zh
  492. * 动态创建引导图片节点并设置引导图片。
  493. */
  494. createGuideSignSpriteNode() {
  495. this.guideSignSpriteNode = new cc.Node('Guide Sign Sprite Node')
  496. this.guideSignSpriteNode.active = false
  497. let self = this
  498. let spriteComp = this.guideSignSpriteNode.addComponent(cc.Sprite)
  499. // if (this.guideData.guideSignType.includes('frame')) {
  500. // spriteComp.type = cc.Sprite.Type.SLICED
  501. //
  502. // }
  503. this.texBundle.load('Public/arrow_5', cc.SpriteFrame, (err: any, spriteFrame: cc.SpriteFrame) => {
  504. spriteComp.spriteFrame = spriteFrame
  505. self.arrowSp = spriteFrame
  506. //this.adjustGuideSignSpriteNode(1)
  507. spriteFrame.addRef()
  508. })
  509. this.texBundle.load('Public/guide_finger', cc.SpriteFrame, (err: any, spriteFrame: cc.SpriteFrame) => {
  510. self.handSp = spriteFrame
  511. //this.adjustGuideSignSpriteNode(1)
  512. spriteFrame.addRef()
  513. })
  514. this.node.addChild(this.guideSignSpriteNode)
  515. }
  516. /**
  517. * @en
  518. * Creates the guide text background node and loads the sprite dynamically.
  519. * @zh
  520. * 创建文本背景节点并设置图片。
  521. */
  522. createGuideTextBgSpriteNode() {
  523. this.guideTextBgSpriteNode = new cc.Node('Text Bg Sprite Node')
  524. this.guideTextBgSpriteNode.active = false
  525. this.roleNode = new cc.Node('Text Role Node')
  526. this.roleNode.active = false
  527. this.roleNode.scale = 0.75
  528. let self = this
  529. let spriteComp = this.guideTextBgSpriteNode.addComponent(cc.Sprite)
  530. spriteComp.type = cc.Sprite.Type.SLICED
  531. self.textPosTemp == 'bottom'
  532. ? self.setGuideTextBgSpriteSizeByCanvasSize()
  533. : self.setGuideTextBgSpriteSizeByTextLength()
  534. this.texBundle.load('Public/preview_bottom_1', cc.SpriteFrame, (err: any, spriteFrame: cc.SpriteFrame) => {
  535. spriteComp.spriteFrame = spriteFrame
  536. // self.textPosTemp == 'bottom'
  537. // ? self.setGuideTextBgSpriteSizeByCanvasSize()
  538. // : self.setGuideTextBgSpriteSizeByTextLength()
  539. })
  540. this.node.addChild(this.roleNode)
  541. let spCom = this.roleNode.addComponent(sp.Skeleton)
  542. this.roleNode.setSiblingIndex(Number.MAX_SAFE_INTEGER - 1)
  543. spCom.skeletonData = this.roleSpine
  544. this.node.addChild(this.guideTextBgSpriteNode)
  545. }
  546. /**
  547. * @en
  548. * Creates the guide text node dynamically.
  549. * @zh
  550. * 创建引导文本节点。
  551. */
  552. createGuideTextLabelNode() {
  553. this.guideTextLabelNode = new cc.Node('Guide Text Label Node')
  554. this.guideTextLabelNode.width = 100
  555. this.guideTextLabelNode.height = 40
  556. let labelComp = this.guideTextLabelNode.addComponent(cc.Label)
  557. labelComp.horizontalAlign = cc.Label.HorizontalAlign.LEFT
  558. labelComp.verticalAlign = cc.Label.VerticalAlign.TOP
  559. labelComp.overflow = cc.Label.Overflow.SHRINK
  560. this.guideTextLabelNode.color = new cc.Color(255, 255, 255)
  561. labelComp.fontSize = 36
  562. labelComp.lineHeight = 40
  563. let labelOutComp = this.guideTextLabelNode.addComponent(cc.LabelOutline)
  564. labelOutComp.color = new cc.Color(38, 17, 12)
  565. labelOutComp.width = 3
  566. this.guideTextBgSpriteNode.addChild(this.guideTextLabelNode)
  567. // Moves the guide text node downwards a litte bit to make it shown at center.
  568. // 稍微往下移动一点显得在图片上居中。
  569. this.guideTextLabelNode.setPosition(0, -5, 0)
  570. }
  571. /**
  572. * @en
  573. * Hides all nodes related to user guide.
  574. * @zh
  575. * 隐藏与引导相关的所有节点。
  576. */
  577. hideGuide() {
  578. // 隐藏与引导相关的所有节点
  579. console.log('hideGuide')
  580. this.maskNode.active = false
  581. this.guideSignSpriteNode.active = false
  582. this.guideTextBgSpriteNode.active = false
  583. this.roleNode.active = false
  584. }
  585. /**
  586. * @en
  587. * Slides the guide sign node, i.e., move from one position to another. This method suits the game which needs a slide guide. Note this method only works for hand or arrow type of guide sign.
  588. * @param slideDistance The slide distance.
  589. * @param slideTime The slide time.
  590. * @zh
  591. * 滑动引导图片,即从一个位置移动到另一个位置,适用于需要进行滑动引导的游戏。注意该方法只对手指或箭头类型的引导图片有效。
  592. * @param slideDistance 滑动位移。
  593. * @param slideTime 滑动时间。
  594. */
  595. slideGuideSign(slideDistance: cc.Vec3, slideTime: number = 2) {
  596. if (this.guideData.guideSignType.includes('hand') || this.guideData.guideSignType.includes('arrow')) {
  597. return
  598. }
  599. this.isGuideSignTweenEnabled = true
  600. this.guideSignTweenType = 'slide'
  601. this.guideSignSlideTweenData = {
  602. slideDistance: slideDistance,
  603. slideTime: slideTime,
  604. }
  605. }
  606. /**
  607. * @en
  608. * Is to make the guide sign fly to the next node position after each guide. If false, the guide sign will hide, and show at next guide.
  609. * @param isFlying Whether to make the guide sign fly to the target node.
  610. * @zh
  611. * 完成一次引导后,是否让引导图片飞到下一个被引导节点的位置上。如果是false,则引导图片会先被隐藏,下次引导时再显示出来。
  612. * @param isFlying 是否让引导图片飞到目标节点上
  613. */
  614. setGuideSignFly(isFlying: boolean = false) {
  615. this.isGudieSignFlying = isFlying
  616. }
  617. /**
  618. * @en
  619. * Sets flying tween duration. The default is 0.3 second.
  620. * @param duration Flying tween duration
  621. * @zh
  622. * 设置飞行缓动持续时间。
  623. * @param duration 飞行缓动持续时间,默认0.3秒。
  624. */
  625. setGuideSignFlyingDuration(duration: number = 0.3) {
  626. this.flyingTweenDuration = duration
  627. }
  628. /**
  629. * @en
  630. * Moves the guide sign node up and down,i.e., like poking. Note this method only works for hand or arrow type of guide sign.
  631. * @zh
  632. * 让引导图片上下运动,即拥有戳戳戳的效果。注意该方法只对手指或箭头类型的引导图片有效。
  633. */
  634. makeGuideSignMoveUpAndDown() {
  635. if (this.guideData.guideSignType.includes('hand') && this.guideData.guideSignType.includes('arrow')) {
  636. return
  637. }
  638. this.isGuideSignTweenEnabled = true
  639. this.guideSignTweenType = 'updown'
  640. }
  641. /**
  642. * @en
  643. * Sets the rotation of guide sign node. The default value is 90, i.e., 90°. Note this method only works for hand or arrow type of guide sign.
  644. * @zh
  645. * 设置引导图片的旋转角度,默认旋转值为90,即绕z轴旋转90°。注意该方法只对手指或箭头类型的引导图片有效。
  646. */
  647. setGuideSignRotation(r: number = 90) {
  648. if (this.guideData.guideSignType.includes('hand') && this.guideData.guideSignType.includes('arrow')) {
  649. return
  650. }
  651. this.guideSignRotation = r
  652. }
  653. /**
  654. * @en
  655. * Sets the position of guide sign on Canvas.
  656. * @zh
  657. * 设置引导图片在画布上的位置。
  658. */
  659. setGuideSignPos(pos: cc.Vec3) {
  660. this.guideSignPosTemp = pos
  661. }
  662. startGuideSignTween() {
  663. // Stops the current tween and restarts.
  664. // 先停止之前的缓动,然后再重新开始。
  665. if (this.guideSignTween) {
  666. this.guideSignTween.stop()
  667. }
  668. if (this.guideSignTweenType == 'slide') {
  669. // Slides the guide sign node and make it back to original position quickly, then slides again.
  670. // 滑动引导图片,滑动过后快速回到原来的位置,然后继续滑动。
  671. this.initGuideSignSlideTween()
  672. } else if (this.guideSignTweenType == 'updown') {
  673. // Moves the guide sign node up and down.
  674. // 让引导图片上下运动。
  675. this.initGuideSignUpDownTween()
  676. }
  677. // Starts the tween.
  678. // 开启引导图片缓动。
  679. this.guideSignTween.start()
  680. }
  681. /**
  682. * @en
  683. * Slides the guide sign node and make it back to original position quickly, then slides again.
  684. * @zh
  685. * 滑动引导图片,滑动过后快速回到原来的位置,然后继续滑动。
  686. */
  687. initGuideSignSlideTween() {
  688. let slideTime = this.guideSignSlideTweenData.slideTime
  689. let slideDistance = this.guideSignSlideTweenData.slideDistance
  690. this.guideSignTween = cc
  691. .tween(this.guideSignSpriteNode)
  692. .by(slideTime, {position: slideDistance})
  693. .by(slideTime / 5, {position: new cc.Vec3(-slideDistance.x, -slideDistance.y, -slideDistance.z)})
  694. .union()
  695. .repeatForever()
  696. }
  697. /**
  698. * @en
  699. * Moves the guide sign node up and down.
  700. * @zh
  701. * 让引导图片上下运动。
  702. */
  703. initGuideSignUpDownTween() {
  704. this.guideSignTween = cc
  705. .tween(this.guideSignSpriteNode)
  706. .by(0.5, {position: new cc.Vec3(0, -10, 0)})
  707. .by(0.5, {position: new cc.Vec3(0, 10, 0)})
  708. .union()
  709. .repeatForever()
  710. }
  711. /**
  712. * @en
  713. * Stops the guide sign tween.
  714. * @zh
  715. * 停止引导图片缓动。
  716. */
  717. stopGuideSignTween() {
  718. if (this.guideSignTween) {
  719. this.isGuideSignTweenEnabled = false
  720. this.guideSignTween.stop()
  721. this.guideSignTween = null
  722. this.guideSignTweenType = ''
  723. this.guideSignSlideTweenData = {
  724. slideDistance: null,
  725. slideTime: 0.5,
  726. }
  727. }
  728. }
  729. /**
  730. * @en
  731. * Sets the scale of guide sign.
  732. * @zh
  733. * 设置引导图片缩放值。
  734. */
  735. setGuideSignScale(scaleX: number, scaleY: number) {
  736. this.guideSignSpriteNode.setScale(scaleX, scaleY, 0)
  737. }
  738. /**
  739. * @en
  740. * Sets the color of guide text, black by default.
  741. * @zh
  742. * 设置引导文本颜色,默认为黑色。
  743. */
  744. setGuideTextColor(color: cc.Color) {
  745. this.guideTextLabelNode.color = color
  746. }
  747. /**
  748. * @en
  749. * Sets the font size of guide text, 28 by default.
  750. * @zh
  751. * 设置引导文本字体大小,默认为28。
  752. */
  753. setGuideTextFontSize(fontSize: number) {
  754. this.guideTextLabelNode.getComponent(cc.Label).fontSize = fontSize
  755. }
  756. /**
  757. * @en
  758. * Sets the system font of guide text.
  759. * @param sysFontName System font name
  760. * @zh
  761. * 设置引导文本的系统字体。
  762. * @param sysFontName 系统字体名称
  763. */
  764. setGuideTextSystemFont(sysFontName: string) {
  765. this.guideTextLabelNode.getComponent(cc.Label).useSystemFont = true
  766. this.guideTextLabelNode.getComponent(cc.Label).fontFamily = sysFontName
  767. }
  768. /**
  769. * @en
  770. * Sets the custom font of guide text.
  771. * @param pathInRes The path of the custom font in resources folder. The format should be ttf and the path should end without the extension name .ttf.
  772. * @zh
  773. * @param pathInRes 自定义字体在resources文件夹中的路径,字体格式为ttf,注意路径最后不带后缀名.ttf。
  774. * 设置引导文本自定义字体。
  775. */
  776. setGuideTextCustomFont(pathInRes: string) {
  777. this.guideTextLabelNode.getComponent(cc.Label).useSystemFont = false
  778. cc.resources.load(pathInRes, cc.Font, (err: any, font: cc.Font) => {
  779. this.guideTextLabelNode.getComponent(cc.Label).font = font
  780. })
  781. }
  782. /**
  783. * @en
  784. * Sets the line height of guide text, 28 by default.
  785. * @zh
  786. * 设置引导文本行高,默认为40。
  787. */
  788. setGuideTextLineHeight(lineHeight: number) {
  789. this.guideTextLabelNode.getComponent(cc.Label).lineHeight = lineHeight
  790. }
  791. /**
  792. * @en
  793. * Sets the position of guide text.
  794. * @param textPos Where to show the guide text. Choices are Vec3 type of value (position on Canvas), or string type of value: 'follow', 'center' and 'bottom'. 'follow' means showing next to the target node, 'center' means showing in the center of Canvas and 'bottom' means showing at the bottom of Canvas.
  795. * @zh
  796. * 设置引导文本位置。
  797. * @param textPos 要在哪里显示引导文本,可以是Vec3类型的值,即在画布上的具体位置,或者是字符串类型的值'follow'、'center'和'bottom'。'follow'表示显示在目标节点周围,'center'表示显示在画布中间,'bottom'表示显示在画布底部。
  798. */
  799. setGuideTextPos(textPos: cc.Vec3 | string = 'follow') {
  800. this.textPosTemp = textPos
  801. }
  802. /**
  803. * @en
  804. * Sets the language type of guide text, 'zh' by default, the other value is 'en'.
  805. * @zh
  806. * 设置引导文本语言种类,默认是'zh',其他可选值为'en'。
  807. */
  808. setGuideTextLang(lang: string = 'zh') {
  809. this.guideTextLang = lang
  810. }
  811. /**
  812. * @en
  813. * Sets the scale of guide text background node.
  814. * @zh
  815. * 设置引导文本背景缩放值。
  816. */
  817. setGuideTextBackgroundScale(scaleX: number, scaleY: number) {
  818. this.guideTextBgSpriteNode.setScale(scaleX, scaleY, 0)
  819. // The scale of bakcground shouldn't influence the child label node.
  820. // 让Label节点不受父节点影响
  821. this.guideTextLabelNode.setScale(1 / scaleX, 1 / scaleY, 0)
  822. // Label is a little bit smaller than the background node.
  823. // Label大小稍微比背景图片小点。
  824. this.guideTextLabelNode.width = (this.guideTextBgSpriteNode.width * scaleX) / 1.1
  825. this.guideTextLabelNode.width = (this.guideTextBgSpriteNode.height * scaleY) / 1.1
  826. }
  827. /**
  828. * @en
  829. * Sets the mask color, black and half transparent by default.
  830. * @zh
  831. * 设置遮罩层颜色,默认为黑色半透明。
  832. */
  833. setMaskColor(color: cc.Color) {
  834. this.blockBgNode.color = color
  835. this.blockBgNode.opacity = color.a
  836. }
  837. /**
  838. * @en
  839. * Sets the mask shape, rect by default.
  840. * @param shape 'rect', 'ellipse' or 'sprite stencil'
  841. * @param spriteFrame This parameter must accept a SpriteFrame type of value When the shape value is 'sprite stencil'.
  842. * @zh
  843. * 设置遮罩挖洞形状,默认为矩形。
  844. * @param shape 'rect','ellipse'或者'sprite stencil'
  845. * @param spriteFrame 当遮罩挖洞形状为'sprite stencil'时,该参数必须接收一个SpriteFrame类型的值。
  846. */
  847. setMaskShape(shape: string, spriteFrame: cc.SpriteFrame = null) {
  848. if (shape == 'rect') {
  849. this.maskNode.getComponent(cc.Mask).type = cc.Mask.Type.RECT
  850. } else if (shape == 'ellipse') {
  851. this.maskNode.getComponent(cc.Mask).type = cc.Mask.Type.ELLIPSE
  852. } else if (shape == 'sprite stencil' && spriteFrame) {
  853. this.maskNode.getComponent(cc.Mask).type = cc.Mask.Type.IMAGE_STENCIL
  854. this.maskNode.getComponent(cc.Mask).spriteFrame = spriteFrame
  855. }
  856. }
  857. /**
  858. * @en
  859. * Sets the interval between two key-down operations, 1.5 seconds by default.
  860. * @zh
  861. * 设置两次按键之间的时间间隔,默认是1.5秒。
  862. */
  863. setKeyDownInterval(interval: number) {
  864. this.keyDownInterval = interval
  865. }
  866. /**
  867. * @en
  868. * Is to enable the typing effect.
  869. * @zh
  870. * 是否开启打字机效果。
  871. */
  872. setTypingEnabled(isEnabled: boolean) {
  873. this.isTyping = isEnabled
  874. }
  875. /**
  876. * @en
  877. * Typing interval (second) used in schedule, 0.05 second by default.
  878. * @zh
  879. * 设置打字机效果打字的时间间隔(秒),默认是0.05秒。
  880. */
  881. setTypingInterval(interval: number) {
  882. this.typingInterval = interval
  883. }
  884. /**
  885. * @en
  886. * Shows the guide by group.
  887. * @param stepArray The guide steps array, [1, 3, 5] means to execute the fist, the third and the fifth guide step. You may also pass an alias array, e.g., ['alias of guide step1', 'alias of guide step 2'];
  888. * @param callback Takes a callback function. which will be called the user completes the current guide.
  889. * @zh
  890. * 按分组显示引导。
  891. * @param stepArray 要执行各个引导步骤,比如传入[1, 3, 5]表示一次执行第一、第三和第五步引导。也可以传入别名数组['第一步引导别名', '第二步引导别名']。
  892. * @param callback 接收一个回调函数,当用户完成当前引导后会执行该回调函数。
  893. */
  894. showGuideByGroup(stepArray: Array<number | string>, callback: Function = null) {
  895. // Return if the step array is empty.
  896. // 如果引导步骤为空,则直接返回。
  897. if (!stepArray.length) {
  898. return
  899. }
  900. // Sets some related variables to show we are in group guiding.
  901. // 设置相关变量,表明现在正在进行分组引导。
  902. this.isGuidedByGroup = true
  903. this.currentStepArrayTemp = stepArray
  904. this.makeGuideSignMoveUpAndDown()
  905. // Executes the fist guide step in the group.
  906. // 执行分组中的第一步引导
  907. this.stepIndexInArray = 0
  908. this.showGuide(stepArray[this.stepIndexInArray], true, callback)
  909. }
  910. /**
  911. * @en
  912. * Shows guides or a single guide.
  913. * @param step Which step to be guided, 1 by default. You may also pass the alias name of the step.
  914. * @param isAuto Is to play the next guide automatically, false by default.
  915. * @param callback Takes a callback function. which will be called the user completes the current guide. Only works when the parameter isAuto is false. Should use this parameter in single step guide type.
  916. *
  917. * @zh
  918. * 显示连续或单步引导。
  919. * @param step 新手引导的第几步,默认是第一步。也可以传入该引导步骤的别名。
  920. * @param isAuto 完成当前引导后是否自动播放下一个引导。
  921. * @param callback 接收一个回调函数,当用户完成当前引导后会执行该回调函数。只有isAuto为false时才有效,适用于单步引导。
  922. */
  923. showGuide(step: number | string, isAuto: boolean = false, callback: Function = null) {
  924. if (!step) {
  925. console.log('请设置参数step的值。')
  926. console.log("Please set parameter step's value.")
  927. return
  928. }
  929. // Change alias to index.
  930. // 将别名转换成索引。
  931. if (typeof step == 'string') {
  932. let temp = step
  933. step = this.changeAliasToIndex(step)
  934. if (step == 0) {
  935. console.log(`step名称${temp}不存在。`)
  936. console.log(`The step alias ${temp} does not exist.`)
  937. return
  938. }
  939. }
  940. // If a developer passes a step value bigger than the biggest step number, then cleans related content and retuen.
  941. // 如果开发者传入的步数大于插件中设置的步数,则清理相关内容后返回。
  942. if (step > this.guideData.nodesAndTexts.length) {
  943. // Delete the guide sign (repeatForever) tween to prevent memory usage.
  944. // 需要删除引导图片的repeatForever缓动,防止占用内存。
  945. if (this.isGuideSignTweenEnabled) {
  946. this.stopGuideSignTween()
  947. }
  948. return
  949. }
  950. let curData = this.guideData.nodesAndTexts[step - 1]
  951. // Saves the current guide step, and it will be used in resources.load().
  952. // 保存当前引导步数,用在resources.load()方法中。
  953. this.currentStepTemp = step
  954. // 特殊UI引导。
  955. if (curData.guideType == 101 || curData.guideType > 200) {
  956. let self = this
  957. //this.showOnlyTextGuide(step, isAuto, callback)
  958. Mgr.ui.show(
  959. +curData.guideType == 101 ? UI.ModOpenUI : UI.UserGuideUI,
  960. Object.assign(
  961. {
  962. callback: () => {
  963. self.goToNextGuide(this.currentStepTemp, isAuto, callback)
  964. },
  965. },
  966. curData,
  967. ),
  968. )
  969. return
  970. }
  971. //重新设置当前引导类型
  972. this.guideData.guideSignType = `${curData.arrowType == 1 ? 'arrow' : ''}_${curData.showTextBg ? 'frame' : ''}_${
  973. curData.arrowType == 2 ? 'hand' : ''
  974. }`
  975. // Is touch guide or key guide.
  976. // 判断是触摸引导还是按键引导。
  977. if (!this.guideData.nodesAndTexts[step - 1].key) {
  978. let targetNodePath = this.guideData.nodesAndTexts[step - 1].path
  979. if (!targetNodePath) {
  980. console.error(`未找到uuid为${this.guideData.nodesAndTexts[step - 1].path}的节点`)
  981. console.error(`Can't find the node whose uuid is ${this.guideData.nodesAndTexts[step - 1].path}`)
  982. return
  983. }
  984. let targetNode = cc.find(`Canvas/${targetNodePath}`)
  985. if (curData.delay) {
  986. this.scheduleOnce(() => {
  987. this.showNodeAndTextGuide(targetNode, +step, isAuto, callback)
  988. }, curData.delay)
  989. } else {
  990. this.showNodeAndTextGuide(targetNode, step, isAuto, callback)
  991. }
  992. } else {
  993. let keys = this.guideData.nodesAndTexts[step - 1].key.split('+')
  994. this.showKeyAndTextGuide(keys, step, isAuto, callback)
  995. }
  996. }
  997. /**
  998. * @en
  999. * Change alias to index.
  1000. * @zh
  1001. * 将别名转换成索引。
  1002. */
  1003. changeAliasToIndex(step: string) {
  1004. for (let i = 0; i < this.guideData.nodesAndTexts.length; i++) {
  1005. if (this.guideData.nodesAndTexts[i].alias == step) {
  1006. return i + 1
  1007. }
  1008. }
  1009. return 0
  1010. }
  1011. /**
  1012. * @en
  1013. * Shows the next guide.
  1014. * @zh
  1015. * 显示下一步引导。
  1016. */
  1017. goToNextGuide(step: number, isAuto: boolean, callback: Function = null) {
  1018. // If it is guided by group, then gets the next guide step number from the guide array.
  1019. // 判断是否为分组引导,是的话则需要从引导分组中获取下一步引导序号。
  1020. if (this.isGuidedByGroup) {
  1021. //重置当前大段引导
  1022. let alias = this.currentStepArrayTemp[this.stepIndexInArray]
  1023. let allSteps = this.guideData.nodesAndTexts.filter(v => v.alias.split('_')[0] == alias.split('_')[0])
  1024. if (alias == allSteps[allSteps.length - 1].alias) {
  1025. Mgr.global.curGuideStep = 0
  1026. }
  1027. this.stepIndexInArray += 1
  1028. // If it is the last step, resets all related variables and executes the callback.
  1029. // 如果已经是最后一步引导,则重置相关变量,执行回调。
  1030. if (this.stepIndexInArray >= this.currentStepArrayTemp.length) {
  1031. this.stepIndexInArray = 0
  1032. this.isGuidedByGroup = false
  1033. this.currentStepArrayTemp = []
  1034. // Delete the guide sign (repeatForever) tween to prevent memory usage.
  1035. // 需要删除引导图片的repeatForever缓动,防止占用内存
  1036. if (this.isGuideSignTweenEnabled) {
  1037. this.stopGuideSignTween()
  1038. }
  1039. // Executes the callback.
  1040. // 执行回调。
  1041. if (callback) {
  1042. callback()
  1043. }
  1044. }
  1045. // If it is not the last step, use the next guide number from array.
  1046. // 如果不是最后一步引导,则使用数组中的下一个引导数字。
  1047. else {
  1048. this.showGuide(this.currentStepArrayTemp[this.stepIndexInArray], isAuto, callback)
  1049. }
  1050. }
  1051. // If it is not guided by group, then adds 1 on the current step number.
  1052. // 如果不是分组引导,则将引导步骤加上1。
  1053. else {
  1054. this.showGuide((step += 1), isAuto, callback)
  1055. }
  1056. }
  1057. /**
  1058. * @en
  1059. * Shows the guide with text only.
  1060. * @zh
  1061. * 只有文本的引导,文本默认显示在屏幕中间。
  1062. */
  1063. showOnlyTextGuide(step: number, isAuto: boolean, callback: Function = null) {
  1064. // Show related nodes.
  1065. // 显示引导相关节点。
  1066. // this.maskNode.active = true
  1067. // this.guideTextBgSpriteNode.active = true
  1068. // Sets the callback function.
  1069. // 设置回调函数。
  1070. let touchStartCallback = () => {
  1071. this.hideGuide()
  1072. if (isAuto) {
  1073. this.goToNextGuide(step, isAuto, callback)
  1074. } else if (callback) {
  1075. callback()
  1076. }
  1077. }
  1078. this.blockBgNode.once(cc.Node.EventType.TOUCH_END, touchStartCallback, this)
  1079. // Sets mask. All nodes can not accept click event as there is no target node to be clicked in the guide.
  1080. // 设置遮罩,让所有节点都无法被点击,因为没有在引导中设置要点击的目标节点 this.maskNode.setPosition(new cc.Vec3(0, 0, 0))
  1081. this.maskNode.setSiblingIndex(0)
  1082. this.maskNode.getComponent(cc.Mask).inverted = true
  1083. this.maskNode.width = 0
  1084. this.maskNode.height = 0
  1085. // Shows the guide text.
  1086. // 显示引导文本。
  1087. // this.adjustGuideTextBgSpriteNode()
  1088. // this.adjustGuideTextLabelNode(step)
  1089. }
  1090. /**
  1091. * @en
  1092. * Shows the guide text and the node to be guided.
  1093. * @zh
  1094. * 显示文本和节点引导。
  1095. */
  1096. showNodeAndTextGuide(targetNode: cc.Node, step: number, isAuto: boolean, callback: Function = null) {
  1097. let curData = this.guideData.nodesAndTexts[step - 1]
  1098. // Show related nodes.
  1099. // 显示引导相关节点。
  1100. this.maskNode.active = true
  1101. let maskFrameNode = this.maskNode.children[1]
  1102. maskFrameNode.active = false
  1103. this.guideSignSpriteNode.active = curData.arrowType > 0
  1104. if (this.arrowSp && this.handSp && curData.arrowType > 0) {
  1105. let spArr = [null, this.arrowSp, this.handSp]
  1106. this.guideSignSpriteNode.getComponent(cc.Sprite).spriteFrame = spArr[curData.arrowType]
  1107. }
  1108. this.guideTextBgSpriteNode.active = curData.showTextBg
  1109. this.blockBgNode.active = curData.prevent
  1110. this.roleNode.active = curData.showRole
  1111. if (this.roleNode.active) {
  1112. let spCom = this.roleNode.getComponent(sp.Skeleton)
  1113. spCom.setAnimation(0, 'stand', true)
  1114. }
  1115. // Reset guide sign tween before each guide.
  1116. // 每次引导前重置引导图片飞行缓动
  1117. this.guideSignFlyingTween = null
  1118. // Sets the callback function.
  1119. // 设置点击后的回调函数。
  1120. let touchStartCallback = () => {
  1121. this.hideGuide()
  1122. if (isAuto) {
  1123. this.goToNextGuide(step, isAuto, callback)
  1124. } else if (callback) {
  1125. callback()
  1126. }
  1127. }
  1128. //按钮或者局部点击下一步 或者 全屏弱引导下一步
  1129. if (targetNode.height < ConstValue.CANVAS_HEIGHT || curData.guideType == 1) {
  1130. targetNode.once(cc.Node.EventType.TOUCH_END, touchStartCallback, this)
  1131. targetNode['_touchListener'].setSwallowTouches(curData.guideType != 1)
  1132. }
  1133. // Sets mask.
  1134. // 设置遮罩相关属性。
  1135. this.maskNode.setPosition(new cc.Vec3(0, 0, 0))
  1136. this.maskNode.angle = 0
  1137. this.maskNode.setSiblingIndex(0)
  1138. this.maskNode.getComponent(cc.Mask).inverted = true
  1139. // The callback that updates the properties (pos, size...) of mask node and guide sign node.
  1140. // 更新遮罩和引导图片的计时器回调函数。
  1141. // Changes the szie of mask hole and guide sign node according to the target node.
  1142. // 根据目标节点改变遮罩挖洞和引导图片的大小。
  1143. this.maskNode.width = targetNode.width * targetNode.scaleX * 1.1
  1144. this.maskNode.height = targetNode.height * targetNode.scaleY * 1.1
  1145. if (targetNode.height < ConstValue.CANVAS_HEIGHT && targetNode.height > 0) {
  1146. maskFrameNode.active = true
  1147. maskFrameNode.width = this.maskNode.width + 36
  1148. maskFrameNode.height = this.maskNode.height + 36
  1149. } else if (curData.prevent) {
  1150. //全屏target 默认是全屏,点击屏幕任意位置下一步
  1151. this.showOnlyTextGuide(step, isAuto, callback)
  1152. }
  1153. // Changes the mask's position according to the target node.
  1154. // 根据目标节点调整遮罩节点位置。
  1155. this.maskNode.setPosition(ccUtils.convertNode2NodePosAR(targetNode, this.node))
  1156. this.maskNode.angle = targetNode.angle
  1157. // Sets again the size of mask background, in case of the wrong size in some games.
  1158. // 这里再一次设置遮罩背景大小,防止部分游戏逻辑下遮罩背景大小错误的情况。
  1159. this.blockBgNode.width = this.canvasUITransform.width * 10
  1160. this.blockBgNode.height = this.canvasUITransform.height * 10
  1161. // Adjusts the position of guide text background. To ensure that the guide sign node is not covered by guide text background. We need to adjust guide text node before guide sign node.
  1162. // 调整文本背景位置。为了不让引导图片被文本背景遮住,需要先设置文本背景,再设置引导图片。
  1163. this.setGuideTextPos(cc.v3(curData.textBgPos[0], curData.textBgPos[1], 0))
  1164. this.adjustGuideTextBgSpriteNode()
  1165. // Adjust guide sign node. Different guide sign sprites need different adjustments.
  1166. // 调整引导图片,不同引导图片需做不同处理。
  1167. this.setGuideSignRotation(curData.arrowRotation)
  1168. let arrowOffsetX = 0
  1169. if (
  1170. curData.path.includes('MainUI/leftNode') ||
  1171. curData.path.includes('MainUI/bottomLeftNode') ||
  1172. curData.ID == '18_2'
  1173. )
  1174. arrowOffsetX = Data.main.safeTop
  1175. this.setGuideSignPos(cc.v3(curData.arrowPos[0] - arrowOffsetX, curData.arrowPos[1], 0))
  1176. this.adjustGuideSignSpriteNode(step)
  1177. // Adjusts the guide text.
  1178. // 调整引导文本。
  1179. this.adjustGuideTextLabelNode(step)
  1180. }
  1181. /**
  1182. * @en
  1183. * The anchor point of target node could be different from that of mask node, so the position should be adjused according to the anchor point.
  1184. * @zh
  1185. * 目标节点的锚点可能可遮罩节点不同,所以需要根据锚点来调整遮罩位置
  1186. */
  1187. adjustPosAccordingToAnchorPoint(nodeToAdjust: cc.Node, nodeToGuide: cc.Node) {
  1188. let nodeToAdjustAnchorPoint = nodeToAdjust.getAnchorPoint()
  1189. let nodeToGuideAnchorPoint = nodeToGuide.getAnchorPoint()
  1190. if (
  1191. nodeToAdjustAnchorPoint.x == nodeToGuideAnchorPoint.x &&
  1192. nodeToAdjustAnchorPoint.y == nodeToGuideAnchorPoint.y
  1193. ) {
  1194. return
  1195. }
  1196. let xDiff = nodeToAdjustAnchorPoint.x - nodeToGuideAnchorPoint.x
  1197. let yDiff = nodeToAdjustAnchorPoint.y - nodeToGuideAnchorPoint.y
  1198. nodeToAdjust.position = nodeToAdjust.position.add(
  1199. new cc.Vec3(xDiff * nodeToGuide.width, yDiff * nodeToGuide.height, 0),
  1200. )
  1201. }
  1202. /**
  1203. * @en
  1204. * Watches the transformation of all parent ndoes.
  1205. * @zh
  1206. * 监听目标节点所有父类的变化。
  1207. */
  1208. onTargetNodeParentTransformChanged(targetNode: cc.Node, posChangedCallback: any) {
  1209. let currentParentNode = null
  1210. while (true) {
  1211. if (!currentParentNode && targetNode.parent) {
  1212. currentParentNode = targetNode.parent
  1213. currentParentNode.on(cc.Node.EventType.POSITION_CHANGED, posChangedCallback, this)
  1214. currentParentNode.on(cc.Node.EventType.SIZE_CHANGED, posChangedCallback, this)
  1215. currentParentNode.on(cc.Node.EventType.ANCHOR_CHANGED, posChangedCallback, this)
  1216. } else if (currentParentNode && currentParentNode.parent) {
  1217. currentParentNode = currentParentNode.parent
  1218. currentParentNode.on(cc.Node.EventType.POSITION_CHANGED, posChangedCallback, this)
  1219. currentParentNode.on(cc.Node.EventType.SIZE_CHANGED, posChangedCallback, this)
  1220. currentParentNode.on(cc.Node.EventType.ANCHOR_CHANGED, posChangedCallback, this)
  1221. } else {
  1222. break
  1223. }
  1224. }
  1225. }
  1226. /**
  1227. * @en
  1228. * Unwatches the transformation of all parent ndoes.
  1229. * @zh
  1230. * 取消监听目标节点所有父类的缓动变化。
  1231. */
  1232. offTargetNodeParentTransformChanged(targetNode: cc.Node, posChangedCallback: any) {
  1233. let currentParentNode = null
  1234. while (true) {
  1235. if (!currentParentNode && targetNode.parent) {
  1236. currentParentNode = targetNode.parent
  1237. currentParentNode.off(cc.Node.EventType.POSITION_CHANGED, posChangedCallback, this)
  1238. currentParentNode.off(cc.Node.EventType.SIZE_CHANGED, posChangedCallback, this)
  1239. currentParentNode.off(cc.Node.EventType.ANCHOR_CHANGED, posChangedCallback, this)
  1240. } else if (currentParentNode && currentParentNode.parent) {
  1241. currentParentNode = currentParentNode.parent
  1242. currentParentNode.off(cc.Node.EventType.POSITION_CHANGED, posChangedCallback, this)
  1243. currentParentNode.off(cc.Node.EventType.SIZE_CHANGED, posChangedCallback, this)
  1244. currentParentNode.off(cc.Node.EventType.ANCHOR_CHANGED, posChangedCallback, this)
  1245. } else {
  1246. break
  1247. }
  1248. }
  1249. }
  1250. /**
  1251. * @en
  1252. * Show guide text and keys to be guided.
  1253. * @zh
  1254. * 显示文本和按键引导。
  1255. */
  1256. showKeyAndTextGuide(keys: Array<string>, step: number, isAuto: boolean, callback: Function = null) {
  1257. // Show related nodes.
  1258. // 显示引导相关节点。
  1259. this.maskNode.active = true
  1260. this.guideTextBgSpriteNode.active = true
  1261. // Sets callback function.
  1262. // 设置回调函数。
  1263. // Last press time.
  1264. // 上次一按键时间。
  1265. let lastKeyDownTime = 0
  1266. // Keys pressed.
  1267. // 按下的键。
  1268. let pressedKeys = []
  1269. let keyDownCallback = event => {
  1270. // If the key-down interval is over 1.5 second, then we are not having combined keys.
  1271. // 如果按键间隔超过1.5秒则说明不是组合键。
  1272. let now = new Date().getTime()
  1273. if ((now - lastKeyDownTime) / 1000 > this.keyDownInterval) {
  1274. lastKeyDownTime = now
  1275. pressedKeys = []
  1276. }
  1277. // Return if it's not the target key.
  1278. // 如果按键不等于引导中的按键,则返回。
  1279. pressedKeys.push(event.keyCode.toString())
  1280. if (JSON.stringify(keys) != JSON.stringify(pressedKeys)) {
  1281. return
  1282. }
  1283. this.hideGuide()
  1284. if (isAuto) {
  1285. this.goToNextGuide(step, isAuto, callback)
  1286. } else if (callback) {
  1287. callback()
  1288. }
  1289. cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, keyDownCallback, this)
  1290. }
  1291. cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, keyDownCallback, this)
  1292. // Sets mask.
  1293. // 设置遮罩。
  1294. this.maskNode.setPosition(new cc.Vec3(0, 0, 0))
  1295. this.maskNode.setSiblingIndex(0)
  1296. this.maskNode.getComponent(cc.Mask).inverted = true
  1297. this.maskNode.width = 0
  1298. this.maskNode.height = 0
  1299. // Adjusts the guide text.
  1300. // 调整引导文本。
  1301. this.adjustGuideTextBgSpriteNode()
  1302. this.adjustGuideTextLabelNode(step)
  1303. }
  1304. /**
  1305. * @en
  1306. * Adjust guide sign node. Different guide sign sprites need different adjustments.
  1307. * @zh
  1308. * 调整引导图片,不同引导图片需要做不同的调整。
  1309. */
  1310. adjustGuideSignSpriteNode(step: number) {
  1311. // Set the sibling index to maximum.
  1312. // 设置层级最大。
  1313. this.guideSignSpriteNode.setSiblingIndex(Number.MAX_SAFE_INTEGER)
  1314. if (this.guideData.guideSignType.includes('frame')) {
  1315. let adjustFunc = () => {
  1316. this.guideSignSpriteNode.angle = this.maskNode.angle
  1317. if (this.guideSignPosTemp) {
  1318. this.guideSignSpriteNode.setPosition(this.guideSignPosTemp)
  1319. } else {
  1320. this.guideSignSpriteNode.setPosition(this.maskNode.position)
  1321. }
  1322. }
  1323. if (this.isGudieSignFlying && step != 1) {
  1324. if (!this.guideSignFlyingTween) {
  1325. this.isFlyingFinised = false
  1326. this.guideSignFlyingTween = cc
  1327. .tween(this.guideSignSpriteNode)
  1328. .to(this.flyingTweenDuration, {
  1329. position: this.maskNode.position,
  1330. rotation: this.guideSignSpriteNode.angle,
  1331. })
  1332. .call(() => {
  1333. adjustFunc()
  1334. this.isFlyingFinised = true
  1335. if (this.isGuideSignTweenEnabled) {
  1336. this.startGuideSignTween()
  1337. }
  1338. })
  1339. this.guideSignFlyingTween.start()
  1340. } else if (this.isFlyingFinised) {
  1341. adjustFunc()
  1342. }
  1343. } else {
  1344. adjustFunc()
  1345. }
  1346. //this.guideSignSpriteNode.width = this.maskNode.width * 1.1
  1347. //this.guideSignSpriteNode.height = this.maskNode.height * 1.1
  1348. }
  1349. if (this.guideData.guideSignType.includes('hand') || this.guideData.guideSignType.includes('arrow')) {
  1350. // If size of the mask hole is 0, then hide the guide sign.
  1351. // 如果遮罩挖洞宽高为0,则隐藏引导图片。
  1352. if (!this.maskNode.width || !this.maskNode.height) {
  1353. //this.guideSignSpriteNode.active = false
  1354. }
  1355. // Adjusts the position and rotation of the guide sign node according to the mask hole.
  1356. // 根据遮罩挖洞位置调整引导图片位置和角度。
  1357. if (this.maskNode.position.y >= 0) {
  1358. let adjustFunc = () => {
  1359. this.guideSignSpriteNode.angle = this.guideSignRotation // 手指朝上
  1360. if (this.guideSignPosTemp) {
  1361. this.guideSignSpriteNode.setPosition(this.guideSignPosTemp)
  1362. } else {
  1363. this.guideSignSpriteNode.setPosition(
  1364. new cc.Vec3(this.maskNode.position).subtract(
  1365. new cc.Vec3(0, this.maskNode.height * 1.01, 0),
  1366. ),
  1367. )
  1368. }
  1369. }
  1370. if (this.isGudieSignFlying && step != 1) {
  1371. if (!this.guideSignFlyingTween) {
  1372. this.isFlyingFinised = false
  1373. this.guideSignFlyingTween = cc
  1374. .tween(this.guideSignSpriteNode)
  1375. .to(this.flyingTweenDuration, {
  1376. position: new cc.Vec3(this.maskNode.position).subtract(
  1377. new cc.Vec3(0, this.maskNode.height * 1.01, 0),
  1378. ),
  1379. rotation: this.guideSignSpriteNode.angle,
  1380. })
  1381. .call(() => {
  1382. adjustFunc()
  1383. this.isFlyingFinised = true
  1384. if (this.isGuideSignTweenEnabled) {
  1385. this.startGuideSignTween()
  1386. }
  1387. })
  1388. this.guideSignFlyingTween.start()
  1389. } else if (this.isFlyingFinised) {
  1390. adjustFunc()
  1391. }
  1392. } else {
  1393. adjustFunc()
  1394. }
  1395. } else if (this.maskNode.position.y < 0) {
  1396. let adjustFunc = () => {
  1397. this.guideSignSpriteNode.angle = this.guideSignRotation // 手指朝下
  1398. if (this.guideSignPosTemp) {
  1399. this.guideSignSpriteNode.setPosition(this.guideSignPosTemp)
  1400. } else {
  1401. this.guideSignSpriteNode.setPosition(
  1402. new cc.Vec3(this.maskNode.position).subtract(
  1403. new cc.Vec3(0, -this.maskNode.height * 1.01, 0),
  1404. ),
  1405. )
  1406. }
  1407. }
  1408. if (this.isGudieSignFlying && step != 1) {
  1409. if (!this.guideSignFlyingTween) {
  1410. this.isFlyingFinised = false
  1411. this.guideSignFlyingTween = cc
  1412. .tween(this.guideSignSpriteNode)
  1413. .to(this.flyingTweenDuration, {
  1414. position: new cc.Vec3(this.maskNode.position).subtract(
  1415. new cc.Vec3(0, -this.maskNode.height * 1.01, 0),
  1416. ),
  1417. rotation: this.guideSignSpriteNode.angle,
  1418. })
  1419. .call(() => {
  1420. adjustFunc()
  1421. this.isFlyingFinised = true
  1422. if (this.isGuideSignTweenEnabled) {
  1423. this.startGuideSignTween()
  1424. }
  1425. })
  1426. this.guideSignFlyingTween.start()
  1427. } else if (this.isFlyingFinised) {
  1428. adjustFunc()
  1429. }
  1430. } else {
  1431. adjustFunc()
  1432. }
  1433. }
  1434. // If the guide sign tween exists, starts it.
  1435. // 如果引导图片缓动存在,则开启。
  1436. if (this.isGuideSignTweenEnabled && this.isFlyingFinised) {
  1437. this.startGuideSignTween()
  1438. }
  1439. }
  1440. }
  1441. /**
  1442. * @en
  1443. * Adjust guide guide text. If there are many words, a bigger text background will be used. If the guide text is put at bottom, guide text background won't need adjustment.
  1444. * @zh
  1445. * 调整文本背景图片大小和位置。如果文本很多那图片就要大些,如果是放在底部的则无需调整。
  1446. */
  1447. adjustGuideTextBgSpriteNode() {
  1448. // Sets the sibling index to maximum.
  1449. // 设置层级最大
  1450. this.guideTextBgSpriteNode.setSiblingIndex(Number.MAX_SAFE_INTEGER)
  1451. // The guide text will be shown at center.
  1452. // 屏幕居中显示。
  1453. if (this.textPosTemp == 'center') {
  1454. // Adjusts the background's size.
  1455. // 调整文本背景大小。
  1456. this.setGuideTextBgSpriteSizeByTextLength()
  1457. // Adjusts the guide text backrgound's position.
  1458. // 调整文本背景位置。
  1459. this.guideTextBgSpriteNode.setPosition(0, 0, 0)
  1460. }
  1461. // The guide text will be shown at bottom.
  1462. // 屏幕底部显示。
  1463. else if (this.textPosTemp == 'bottom') {
  1464. // Adjusts the guide text background's size.
  1465. // 调整文本背景大小。
  1466. this.setGuideTextBgSpriteSizeByCanvasSize()
  1467. // Adjusts the guide text backrgound's position.
  1468. // 调整文本背景位置。
  1469. let y = this.canvasUITransform.height / 2 - this.guideTextBgSpriteNode.height / 2
  1470. this.guideTextBgSpriteNode.setPosition(0, -y, 0)
  1471. }
  1472. // The guide text will be shown next to the target node.
  1473. // 跟随引导图片显示。
  1474. else if (this.textPosTemp == 'follow') {
  1475. // Adjusts the background's size.
  1476. // 调整文本背景大小。
  1477. this.setGuideTextBgSpriteSizeByTextLength()
  1478. // Adjusts the guide text backrgound's position.
  1479. // 调整文本背景位置。
  1480. if (this.maskNode.position.x >= 0 && this.maskNode.position.y >= 0) {
  1481. this.guideTextBgSpriteNode.setPosition(
  1482. new cc.Vec3(this.maskNode.position).subtract(
  1483. new cc.Vec3(this.maskNode.width * 1.1, this.maskNode.height * 1.1, 0),
  1484. ),
  1485. )
  1486. } else if (this.maskNode.position.x >= 0 && this.maskNode.position.y <= 0) {
  1487. this.guideTextBgSpriteNode.setPosition(
  1488. new cc.Vec3(this.maskNode.position).subtract(
  1489. new cc.Vec3(this.maskNode.width * 1.1, -this.maskNode.height * 1.1, 0),
  1490. ),
  1491. )
  1492. } else if (this.maskNode.position.x <= 0 && this.maskNode.position.y >= 0) {
  1493. this.guideTextBgSpriteNode.setPosition(
  1494. new cc.Vec3(this.maskNode.position).subtract(
  1495. new cc.Vec3(-this.maskNode.width * 1.1, this.maskNode.height * 1.1, 0),
  1496. ),
  1497. )
  1498. } else if (this.maskNode.position.x <= 0 && this.maskNode.position.y <= 0) {
  1499. this.guideTextBgSpriteNode.setPosition(
  1500. new cc.Vec3(this.maskNode.position).subtract(
  1501. new cc.Vec3(-this.maskNode.width * 1.1, -this.maskNode.height * 1.1, 0),
  1502. ),
  1503. )
  1504. }
  1505. } else if (typeof this.textPosTemp == 'object') {
  1506. // Adjusts the background's size.
  1507. // 调整文本背景大小。
  1508. this.setGuideTextBgSpriteSizeByTextLength()
  1509. // Adjusts the guide text backrgound's position.
  1510. // 调整文本背景位置。
  1511. this.guideTextBgSpriteNode.setPosition(this.textPosTemp)
  1512. let offsetX = 120
  1513. let offsetY = -80
  1514. this.roleNode.setPosition(
  1515. this.textPosTemp.add(
  1516. cc.v3(
  1517. -this.guideTextBgSpriteNode.width / 2 + offsetX,
  1518. this.guideTextBgSpriteNode.height / 2 + offsetY,
  1519. 0,
  1520. ),
  1521. ),
  1522. )
  1523. }
  1524. }
  1525. /**
  1526. * @en
  1527. * When the guide text is shown at bottom, its size is adjusted based on the canvas size.
  1528. * @zh
  1529. * 当引导文本显示在屏幕底部时,根据屏幕大小来设置文本背景大小。
  1530. */
  1531. setGuideTextBgSpriteSizeByCanvasSize() {
  1532. this.guideTextBgSpriteNode.width = this.canvasUITransform.width
  1533. this.guideTextBgSpriteNode.height = this.canvasUITransform.height / 7
  1534. }
  1535. /**
  1536. * @en
  1537. * When the guide text is shown next to target node or at center, its size is adjusted based on the text length.
  1538. * @zh
  1539. * 当引导文本跟随引导图片或居中显示时,根据引导文本长度调整文本背景大小。
  1540. */
  1541. setGuideTextBgSpriteSizeByTextLength() {
  1542. let guideText = ''
  1543. let width = 0
  1544. let height = 0
  1545. if (Mgr.i18n.getLanguage() == 'zh') {
  1546. guideText = this.guideData.nodesAndTexts[this.currentStepTemp - 1].guideText
  1547. if (guideText.length <= 15 && guideText.length > 0) {
  1548. width = this.canvasUITransform.width / 5
  1549. height = this.canvasUITransform.height / 10
  1550. } else if (guideText.length > 15 && guideText.length <= 40) {
  1551. width = this.canvasUITransform.width / 5
  1552. height = this.canvasUITransform.height / 8
  1553. } else if (guideText.length > 40) {
  1554. width = this.canvasUITransform.width / 3
  1555. height = this.canvasUITransform.height / 6
  1556. }
  1557. } else {
  1558. guideText = this.guideData.nodesAndTexts[this.currentStepTemp - 1].guideText
  1559. if (guideText.length <= 40 && guideText.length > 0) {
  1560. width = this.canvasUITransform.width / 3
  1561. height = this.canvasUITransform.height / 10
  1562. } else if (guideText.length > 15 && guideText.length <= 80) {
  1563. width = this.canvasUITransform.width / 3
  1564. height = this.canvasUITransform.height / 8
  1565. } else if (guideText.length > 80) {
  1566. width = this.canvasUITransform.width / 2
  1567. height = this.canvasUITransform.height / 6
  1568. }
  1569. }
  1570. width = 820
  1571. height = 210
  1572. if (!this.roleNode.active) {
  1573. width = 540
  1574. height = 160
  1575. }
  1576. // Switch the value of width and height if the canvas direction is portrait.
  1577. // 如果是竖屏则将width和height值对调。
  1578. if (width < height) {
  1579. let temp = height
  1580. height = width
  1581. width = temp
  1582. }
  1583. this.guideTextBgSpriteNode.width = width
  1584. this.guideTextBgSpriteNode.height = height
  1585. }
  1586. /**
  1587. * @en
  1588. * Sets guide text and adjusts the label size according to the background node.
  1589. * @zh
  1590. * 设置引导文本并根据文本背景图片调整Label宽高以及字体大小。
  1591. */
  1592. adjustGuideTextLabelNode(step: number) {
  1593. if (!this.isTyping) {
  1594. // If typing effect is not enabled, set the text directly to Label.
  1595. // 如果没有打字机效果,则直接将引导文本设置到Label上。
  1596. if (this.guideTextLang == 'zh') {
  1597. this.guideTextLabelNode.getComponent(cc.Label).string = this.guideData.nodesAndTexts[step - 1].guideText
  1598. } else {
  1599. this.guideTextLabelNode.getComponent(cc.Label).string = this.guideData.nodesAndTexts[
  1600. step - 1
  1601. ].guideEnText
  1602. }
  1603. } else {
  1604. this.scheduleCount = 0
  1605. if (this.guideTextLang == 'zh') {
  1606. this.guideTextTemp = this.guideData.nodesAndTexts[step - 1].guideText
  1607. } else {
  1608. this.guideTextTemp = this.guideData.nodesAndTexts[step - 1].guideEnText
  1609. }
  1610. // Sets the callback function.
  1611. // 设置调度函数。
  1612. let callback = () => {
  1613. if (this.guideTextTemp[this.scheduleCount]) {
  1614. this.guideTextLabelNode.getComponent(cc.Label).string += this.guideTextTemp[this.scheduleCount]
  1615. }
  1616. this.scheduleCount++
  1617. if (this.scheduleCount >= this.guideTextTemp.length) {
  1618. this.unschedule(callback)
  1619. }
  1620. }
  1621. // Cancel the last schedule and clean the text content.
  1622. // 开始调度前要先取消上一次的调度并清空文本。
  1623. this.unschedule(callback)
  1624. this.guideTextLabelNode.getComponent(cc.Label).string = ''
  1625. // Begins a new schedule.
  1626. // 开始新的调度。
  1627. this.schedule(callback, this.typingInterval)
  1628. }
  1629. // The size of Label should be a little bit smaller than that of the text background node.
  1630. // Label大小稍微比背景图片小点。
  1631. this.guideTextLabelNode.width = (this.guideTextBgSpriteNode.width * this.guideTextBgSpriteNode.scaleX) / 1.1
  1632. this.guideTextLabelNode.height = (this.guideTextBgSpriteNode.height * this.guideTextBgSpriteNode.scaleY) / 1.1
  1633. }
  1634. /**
  1635. * @en
  1636. * Find the target node recursively.
  1637. * @zh
  1638. * 递归寻找目标节点。
  1639. */
  1640. getNodeByUuid(node: cc.Node, uuid: string) {
  1641. let targetNode = null
  1642. for (let i = 0; i < node.children.length; i++) {
  1643. if (node.children[i].uuid == uuid) {
  1644. targetNode = node.children[i]
  1645. break
  1646. } else if (node.children[i].children.length) {
  1647. targetNode = this.getNodeByUuid(node.children[i], uuid)
  1648. if (targetNode) {
  1649. break
  1650. }
  1651. }
  1652. }
  1653. return targetNode
  1654. }
  1655. /**
  1656. * @en
  1657. * Get positions of all parent nodes except for Canvas.
  1658. * @zh
  1659. * 获取目标节点坐标及其所有父节点,祖父节点,曾祖父节点...的坐标(不包括Canvas节点)。
  1660. */
  1661. getAllParentPosIncludingSelf(node: cc.Node) {
  1662. let posArray = [node.position]
  1663. let tempNode = node
  1664. while (true) {
  1665. let parentNode = tempNode.parent
  1666. if (parentNode && parentNode != this.node) {
  1667. posArray.push(parentNode.position)
  1668. tempNode = parentNode
  1669. } else {
  1670. break
  1671. }
  1672. }
  1673. return posArray
  1674. }
  1675. }