utils.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. import bundleManager from "../../manager/bundleManager";
  2. import { BenzAssetManager } from "../asset/BenzAssetManager";
  3. export default class Utils {
  4. /**获取本地数据
  5. *
  6. * @param key 存储的键
  7. */
  8. public static getLocalStorageItem(key: string) {
  9. return cc.sys.platform === cc.sys.WECHAT_GAME ? wx.getStorageSync(key) : cc.sys.localStorage.getItem(key);
  10. }
  11. /**设置本地数据
  12. *
  13. * @param key 存储的键
  14. * @param value 存储的值
  15. */
  16. public static setLocalStorageItem(key: string, value: any) {
  17. return cc.sys.platform === cc.sys.WECHAT_GAME ? wx.setStorageSync(key, value) : cc.sys.localStorage.setItem(key, value);
  18. }
  19. public static getWorld(data): cc.Vec2 {
  20. var x = data.x
  21. , y = data.y;
  22. while (data.parent) {
  23. data = data.parent;
  24. x += data.x;
  25. y += data.y;
  26. }
  27. x += data.x;
  28. y += data.y;
  29. return cc.v2(-x, -y);
  30. }
  31. /**
  32. * 根据坐标a,角度,长度获取坐标b
  33. * @param pointA
  34. * @param angle
  35. * @param bevel
  36. * @returns {cc.Vec2}
  37. */
  38. public static getPositionPositiveCalculation(pointA, angle, bevel): cc.Vec2 {
  39. var radian = cc.misc.degreesToRadians(angle);
  40. var xMargin = Math.cos(radian) * bevel;
  41. var yMargin = Math.sin(radian) * bevel;
  42. return cc.v2(pointA.x + xMargin, pointA.y + yMargin);
  43. }
  44. public static getWorldRotation(data): number {
  45. var rotation = 0;
  46. rotation += data.rotation;
  47. while (data.parent) {
  48. rotation += data.rotation;
  49. data = data.parent;
  50. }
  51. return rotation;
  52. }
  53. /**
  54. * @description 射线检测获取碰撞点
  55. * @param startPos 起点坐标
  56. * @param endPos 结束坐标
  57. * */
  58. public static getRayCast(startPos: cc.Vec2, endPos: cc.Vec2, type: cc.RayCastType): any[] {
  59. return cc.director.getPhysicsManager().rayCast(startPos, endPos, type);
  60. }
  61. // 获得两点之间顺时针旋转的角度
  62. public static TwoPointAngle(pointFrom, pointTo) {
  63. // console.log("pointFrom", pointFrom, pointTo);
  64. var dx = Math.abs(pointFrom.x - pointTo.x);
  65. var dy = Math.abs(pointFrom.y - pointTo.y);
  66. var z = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
  67. var cos = dy / z;
  68. var radina = Math.acos(cos); // 用反三角函数求弧度
  69. var angle = Math.floor(180 / (Math.PI / radina)); // 将弧度转换成角度
  70. if (pointTo.x > pointFrom.x && pointTo.y > pointFrom.y) { // 鼠标在第四象限
  71. angle = 180 - angle;
  72. } else if (pointTo.x == pointFrom.x && pointTo.y > pointFrom.y) { // 鼠标在y轴负方向上
  73. angle = 180;
  74. } else if (pointTo.x > pointFrom.x && pointTo.y == pointFrom.y) { // 鼠标在x轴正方向上
  75. angle = 90;
  76. } else if (pointTo.x < pointFrom.x && pointTo.y > pointFrom.y) { // 鼠标在第三象限
  77. angle = 180 + angle;
  78. } else if (pointTo.x < pointFrom.x && pointTo.y == pointFrom.y) { // 鼠标在x轴负方向
  79. angle = 270;
  80. } else if (pointTo.x < pointFrom.x && pointTo.y < pointFrom.y) { // 鼠标在第二象限
  81. angle = 360 - angle;
  82. }
  83. angle = -180 - angle;
  84. return angle;
  85. }
  86. /**
  87. * 添加按钮的点击事件
  88. * @param node 按钮节点
  89. * @param target 目标节点
  90. * @param component 目标组件名
  91. * @param handler 目标函数名
  92. * @param customEventData 携带的参数
  93. */
  94. public static addClickButtonEvent(node: cc.Node, target: cc.Node, component: string, handler: string, customEventData?: any) {
  95. var eventHandler = new cc.Component.EventHandler(); // 创建一个回调事件
  96. eventHandler.target = target; // 目标节点
  97. eventHandler.component = component; // 目标组件名
  98. eventHandler.handler = handler; // 目标函数名
  99. eventHandler.customEventData = customEventData; // 携带的参数
  100. var clickEvents = node.getComponent(cc.Button).clickEvents; // 获取节点上的按钮事件
  101. clickEvents.push(eventHandler); // 把新建事件添加到回调
  102. }
  103. public static getNodeToWorldPoint(node: cc.Node, pos: cc.Vec2) {
  104. return node.parent.convertToWorldSpaceAR(pos || cc.v2());
  105. }
  106. /**节点A的坐标切换到节点B的坐标
  107. *
  108. * @param nodeA
  109. * @param nodeB
  110. */
  111. public static getNodeAToNodeBPoint(nodeA: cc.Node, nodeB: cc.Node, pos) {
  112. pos = this.getNodeToWorldPoint(nodeA, pos);
  113. return this.getWorldToNodePoint(nodeB, pos);
  114. }
  115. /**世界坐标转成节点坐标
  116. *
  117. * @param node 需要转换的节点
  118. * @param pos 需要转换的坐标
  119. */
  120. public static getWorldToNodePoint(node: cc.Node, pos: cc.Vec2) {
  121. return node.parent.convertToNodeSpaceAR(pos || cc.v2());
  122. }
  123. /**
  124. * name
  125. */
  126. public static clone(obj) {
  127. // Handle the 3 simple types, and null or undefined
  128. if (null == obj || "object" != typeof obj) return obj;
  129. // Handle Date
  130. let copy = null;
  131. if (obj instanceof Date) {
  132. copy = new Date();
  133. copy.setTime(obj.getTime());
  134. return copy;
  135. }
  136. // Handle Array
  137. if (obj instanceof Array) {
  138. copy = [];
  139. for (let i = 0, len = obj.length; i < len; ++i) {
  140. copy[i] = Utils.clone(obj[i]);
  141. }
  142. return copy;
  143. }
  144. // Handle Object
  145. if (obj instanceof Object) {
  146. copy = {};
  147. for (var attr in obj) {
  148. if (obj.hasOwnProperty(attr)) copy[attr] = Utils.clone(obj[attr]);
  149. }
  150. return copy;
  151. }
  152. throw new Error("Unable to copy obj! Its type isn't supported.");
  153. }
  154. /**
  155. * 产生随机整数,包含下限值,包括上限值
  156. * @param {Number} lower 下限
  157. * @param {Number} upper 上限
  158. * @return {Number} 返回在下限到上限之间的一个随机整数
  159. */
  160. public static random(lower, upper) {
  161. return Math.floor(Math.random() * (upper - lower + 1)) + lower;
  162. }
  163. /**
  164. * 自动补0
  165. * @param num
  166. * @param length
  167. */
  168. public static PrefixInteger(num, length) {
  169. return (Array(length).join('0') + num).slice(-length);
  170. }
  171. /**
  172. * 当前时间
  173. */
  174. public static getCurrentSecond() {
  175. let date = new Date();
  176. return Math.ceil(date.getTime() / 1000);
  177. }
  178. public static format(src: string, ...args): string {
  179. var _dic = args;
  180. return src.replace(/\{(\d+)\}/g, function (str, key) {
  181. return _dic[parseInt(key)];
  182. });
  183. }
  184. /**
  185. * 可扩充的解决方案
  186. * @param bits 格式化位数
  187. * @param identifier 补全字符
  188. * @param value 值
  189. */
  190. public static dataLeftCompleting(bits: number, identifier: string, value: number): string {
  191. let result = Array(bits + 1).join(identifier) + value;
  192. return result.slice(-bits);
  193. }
  194. //====================================UI================================================//
  195. /**
  196. * 背景适配
  197. * @param type 适配方式 0 等比适配 1 拉升适配
  198. * @param target 目标背景节点
  199. */
  200. public static fitBackground(target: cc.Node, type = 0) {
  201. let disX = cc.winSize.width / 750;
  202. let disY = cc.winSize.height / 1334;
  203. let max = disX > disY ? disX : disY;
  204. if (type) {
  205. target.scaleX = max;
  206. target.scaleY = max;
  207. } else {
  208. target.scaleX = disX;
  209. target.scaleY = disY;
  210. }
  211. }
  212. public static safeDestroy(target: cc.Sprite): void {
  213. if (target && target.isValid) {
  214. target.destroy();
  215. }
  216. }
  217. public static addPrefab(tag: string, parent: cc.Node) {
  218. let layer = <cc.Prefab>BenzAssetManager.getInstance().getAsset(tag);
  219. let prefab = cc.instantiate(layer);
  220. prefab.parent = parent;
  221. if (prefab) {
  222. return prefab;
  223. }
  224. }
  225. /**
  226. * 动态加载龙骨
  227. * @param animationDisplay 龙骨组件
  228. * @param path 龙骨地址
  229. * @param armatureName Armature名称
  230. * @param newAnimation Animation名称
  231. * @param completeCallback 动画播放完毕的回调
  232. * @param playTimes 播放次数 -1是根据龙骨文件 0五险循环 >0是播放次数
  233. */
  234. public static loadDragonBones(animationDisplay, path, armatureName, newAnimation, playTimes = 1) { //动态加载龙骨
  235. cc.loader.loadResDir(path, function (err, assets) {
  236. if (err || assets.length <= 0) return;
  237. assets.forEach(asset => {
  238. if (asset instanceof dragonBones.DragonBonesAsset) {
  239. animationDisplay.dragonAsset = asset;
  240. }
  241. if (asset instanceof dragonBones.DragonBonesAtlasAsset) {
  242. animationDisplay.dragonAtlasAsset = asset;
  243. }
  244. });
  245. animationDisplay.armatureName = armatureName;
  246. animationDisplay.playAnimation(newAnimation, playTimes);
  247. //animationDisplay.addEventListener(dragonBones.EventObject.COMPLETE, completeCallback);
  248. })
  249. }
  250. /**
  251. * 动态加载分包spine
  252. * @param spineCom spine组件
  253. * @param path spine地址
  254. * @param animName Animation名称
  255. * @param isLoop 是否循环
  256. * @param skinName 皮肤名字
  257. * @param cb 回调
  258. */
  259. public static loadSpineBunble(spineCom, path, cb?) {
  260. bundleManager.getBundleByName('spine').load(path, sp.SkeletonData, function (err, spine) {
  261. if (spine) {
  262. spineCom.skeletonData = spine;
  263. spineCom.clearTracks(0);
  264. if (cb) {
  265. cb();
  266. }
  267. }
  268. })
  269. }
  270. public static getYearMonthDay() {
  271. let date = new Date()
  272. let year = date.getFullYear().toString();
  273. let month = date.getMonth().toString();
  274. let day = date.getDate().toString();
  275. return year + month + day
  276. }
  277. /**
  278. * 获取时间戳(秒)
  279. * @param isMillisecond 是否返回毫秒时间戳
  280. * @method getTimeStamp
  281. */
  282. public static getTimeStamp(isMillisecond?) {
  283. if (isMillisecond) {
  284. return (new Date()).getTime();
  285. }
  286. return Math.floor((new Date()).getTime() / 1000);
  287. }
  288. public static tipsSprite(path, parent) {
  289. let winSize = cc.winSize;
  290. let node = new cc.Node();
  291. node.addComponent(cc.Sprite)
  292. bundleManager.setBundleFrame('UI', path, node);
  293. node.parent = parent;
  294. node.x = -winSize.width / 2 - 400;
  295. node.y += 80;
  296. cc.tween(node)
  297. .delay(1)
  298. .to(1, { x: 0 }, { easing: 'smooth' })
  299. .delay(2)
  300. .by(1, { x: winSize.width / 2 + 350 }, { easing: 'smooth' })
  301. .call(() => { node.destroy() })
  302. .start()
  303. }
  304. /**
  305. *
  306. * 只计算到分钟
  307. */
  308. public static getTime(time: number) {
  309. return `${Utils.PrefixInteger(Math.floor(time / 60), 2)}:${Utils.PrefixInteger(time % 60, 2)}`
  310. }
  311. public static getPlatformName() {
  312. if (cc.sys.platform === cc.sys.WECHAT_GAME) {
  313. return 'wx';
  314. } else if (cc.sys.platform === cc.sys.BYTEDANCE_GAME) {
  315. return 'tt';
  316. } else if (cc.sys.platform === cc.sys.OPPO_GAME) {
  317. return 'qg';
  318. } else if (cc.sys.platform === cc.sys.VIVO_GAME) {
  319. return 'qg';
  320. } else {
  321. return null;
  322. }
  323. }
  324. /**
  325. * 对象池
  326. * @param prefab 节点预制
  327. * @param maxNum 对象池初始长度
  328. */
  329. public static initNodePool(prefab: cc.Prefab, maxNum: number) {
  330. let nodePool = new cc.NodePool();
  331. let initNum = maxNum;
  332. for (let i = 0; i < initNum; ++i) {
  333. let node = cc.instantiate(prefab);
  334. nodePool.put(node);
  335. }
  336. return nodePool;
  337. }
  338. };