import bundleManager from "../../manager/bundleManager"; import { BenzAssetManager } from "../asset/BenzAssetManager"; export default class Utils { /**获取本地数据 * * @param key 存储的键 */ public static getLocalStorageItem(key: string) { return cc.sys.platform === cc.sys.WECHAT_GAME ? wx.getStorageSync(key) : cc.sys.localStorage.getItem(key); } /**设置本地数据 * * @param key 存储的键 * @param value 存储的值 */ public static setLocalStorageItem(key: string, value: any) { return cc.sys.platform === cc.sys.WECHAT_GAME ? wx.setStorageSync(key, value) : cc.sys.localStorage.setItem(key, value); } public static getWorld(data): cc.Vec2 { var x = data.x , y = data.y; while (data.parent) { data = data.parent; x += data.x; y += data.y; } x += data.x; y += data.y; return cc.v2(-x, -y); } /** * 根据坐标a,角度,长度获取坐标b * @param pointA * @param angle * @param bevel * @returns {cc.Vec2} */ public static getPositionPositiveCalculation(pointA, angle, bevel): cc.Vec2 { var radian = cc.misc.degreesToRadians(angle); var xMargin = Math.cos(radian) * bevel; var yMargin = Math.sin(radian) * bevel; return cc.v2(pointA.x + xMargin, pointA.y + yMargin); } public static getWorldRotation(data): number { var rotation = 0; rotation += data.rotation; while (data.parent) { rotation += data.rotation; data = data.parent; } return rotation; } /** * @description 射线检测获取碰撞点 * @param startPos 起点坐标 * @param endPos 结束坐标 * */ public static getRayCast(startPos: cc.Vec2, endPos: cc.Vec2, type: cc.RayCastType): any[] { return cc.director.getPhysicsManager().rayCast(startPos, endPos, type); } // 获得两点之间顺时针旋转的角度 public static TwoPointAngle(pointFrom, pointTo) { // console.log("pointFrom", pointFrom, pointTo); var dx = Math.abs(pointFrom.x - pointTo.x); var dy = Math.abs(pointFrom.y - pointTo.y); var z = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2)); var cos = dy / z; var radina = Math.acos(cos); // 用反三角函数求弧度 var angle = Math.floor(180 / (Math.PI / radina)); // 将弧度转换成角度 if (pointTo.x > pointFrom.x && pointTo.y > pointFrom.y) { // 鼠标在第四象限 angle = 180 - angle; } else if (pointTo.x == pointFrom.x && pointTo.y > pointFrom.y) { // 鼠标在y轴负方向上 angle = 180; } else if (pointTo.x > pointFrom.x && pointTo.y == pointFrom.y) { // 鼠标在x轴正方向上 angle = 90; } else if (pointTo.x < pointFrom.x && pointTo.y > pointFrom.y) { // 鼠标在第三象限 angle = 180 + angle; } else if (pointTo.x < pointFrom.x && pointTo.y == pointFrom.y) { // 鼠标在x轴负方向 angle = 270; } else if (pointTo.x < pointFrom.x && pointTo.y < pointFrom.y) { // 鼠标在第二象限 angle = 360 - angle; } angle = -180 - angle; return angle; } /** * 添加按钮的点击事件 * @param node 按钮节点 * @param target 目标节点 * @param component 目标组件名 * @param handler 目标函数名 * @param customEventData 携带的参数 */ public static addClickButtonEvent(node: cc.Node, target: cc.Node, component: string, handler: string, customEventData?: any) { var eventHandler = new cc.Component.EventHandler(); // 创建一个回调事件 eventHandler.target = target; // 目标节点 eventHandler.component = component; // 目标组件名 eventHandler.handler = handler; // 目标函数名 eventHandler.customEventData = customEventData; // 携带的参数 var clickEvents = node.getComponent(cc.Button).clickEvents; // 获取节点上的按钮事件 clickEvents.push(eventHandler); // 把新建事件添加到回调 } public static getNodeToWorldPoint(node: cc.Node, pos: cc.Vec2) { return node.parent.convertToWorldSpaceAR(pos || cc.v2()); } /**节点A的坐标切换到节点B的坐标 * * @param nodeA * @param nodeB */ public static getNodeAToNodeBPoint(nodeA: cc.Node, nodeB: cc.Node, pos) { pos = this.getNodeToWorldPoint(nodeA, pos); return this.getWorldToNodePoint(nodeB, pos); } /**世界坐标转成节点坐标 * * @param node 需要转换的节点 * @param pos 需要转换的坐标 */ public static getWorldToNodePoint(node: cc.Node, pos: cc.Vec2) { return node.parent.convertToNodeSpaceAR(pos || cc.v2()); } /** * name */ public static clone(obj) { // Handle the 3 simple types, and null or undefined if (null == obj || "object" != typeof obj) return obj; // Handle Date let copy = null; if (obj instanceof Date) { copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { copy = []; for (let i = 0, len = obj.length; i < len; ++i) { copy[i] = Utils.clone(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = Utils.clone(obj[attr]); } return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); } /** * 产生随机整数,包含下限值,包括上限值 * @param {Number} lower 下限 * @param {Number} upper 上限 * @return {Number} 返回在下限到上限之间的一个随机整数 */ public static random(lower, upper) { return Math.floor(Math.random() * (upper - lower + 1)) + lower; } /** * 自动补0 * @param num * @param length */ public static PrefixInteger(num, length) { return (Array(length).join('0') + num).slice(-length); } /** * 当前时间 */ public static getCurrentSecond() { let date = new Date(); return Math.ceil(date.getTime() / 1000); } public static format(src: string, ...args): string { var _dic = args; return src.replace(/\{(\d+)\}/g, function (str, key) { return _dic[parseInt(key)]; }); } /** * 可扩充的解决方案 * @param bits 格式化位数 * @param identifier 补全字符 * @param value 值 */ public static dataLeftCompleting(bits: number, identifier: string, value: number): string { let result = Array(bits + 1).join(identifier) + value; return result.slice(-bits); } //====================================UI================================================// /** * 背景适配 * @param type 适配方式 0 等比适配 1 拉升适配 * @param target 目标背景节点 */ public static fitBackground(target: cc.Node, type = 0) { let disX = cc.winSize.width / 750; let disY = cc.winSize.height / 1334; let max = disX > disY ? disX : disY; if (type) { target.scaleX = max; target.scaleY = max; } else { target.scaleX = disX; target.scaleY = disY; } } public static safeDestroy(target: cc.Sprite): void { if (target && target.isValid) { target.destroy(); } } public static addPrefab(tag: string, parent: cc.Node) { let layer = BenzAssetManager.getInstance().getAsset(tag); let prefab = cc.instantiate(layer); prefab.parent = parent; if (prefab) { return prefab; } } /** * 动态加载龙骨 * @param animationDisplay 龙骨组件 * @param path 龙骨地址 * @param armatureName Armature名称 * @param newAnimation Animation名称 * @param completeCallback 动画播放完毕的回调 * @param playTimes 播放次数 -1是根据龙骨文件 0五险循环 >0是播放次数 */ public static loadDragonBones(animationDisplay, path, armatureName, newAnimation, playTimes = 1) { //动态加载龙骨 cc.loader.loadResDir(path, function (err, assets) { if (err || assets.length <= 0) return; assets.forEach(asset => { if (asset instanceof dragonBones.DragonBonesAsset) { animationDisplay.dragonAsset = asset; } if (asset instanceof dragonBones.DragonBonesAtlasAsset) { animationDisplay.dragonAtlasAsset = asset; } }); animationDisplay.armatureName = armatureName; animationDisplay.playAnimation(newAnimation, playTimes); //animationDisplay.addEventListener(dragonBones.EventObject.COMPLETE, completeCallback); }) } /** * 动态加载分包spine * @param spineCom spine组件 * @param path spine地址 * @param animName Animation名称 * @param isLoop 是否循环 * @param skinName 皮肤名字 * @param cb 回调 */ public static loadSpineBunble(spineCom, path, cb?) { bundleManager.getBundleByName('spine').load(path, sp.SkeletonData, function (err, spine) { if (spine) { spineCom.skeletonData = spine; spineCom.clearTracks(0); if (cb) { cb(); } } }) } public static getYearMonthDay() { let date = new Date() let year = date.getFullYear().toString(); let month = date.getMonth().toString(); let day = date.getDate().toString(); return year + month + day } /** * 获取时间戳(秒) * @param isMillisecond 是否返回毫秒时间戳 * @method getTimeStamp */ public static getTimeStamp(isMillisecond?) { if (isMillisecond) { return (new Date()).getTime(); } return Math.floor((new Date()).getTime() / 1000); } public static tipsSprite(path, parent) { let winSize = cc.winSize; let node = new cc.Node(); node.addComponent(cc.Sprite) bundleManager.setBundleFrame('UI', path, node); node.parent = parent; node.x = -winSize.width / 2 - 400; node.y += 80; cc.tween(node) .delay(1) .to(1, { x: 0 }, { easing: 'smooth' }) .delay(2) .by(1, { x: winSize.width / 2 + 350 }, { easing: 'smooth' }) .call(() => { node.destroy() }) .start() } /** * * 只计算到分钟 */ public static getTime(time: number) { return `${Utils.PrefixInteger(Math.floor(time / 60), 2)}:${Utils.PrefixInteger(time % 60, 2)}` } public static getPlatformName() { if (cc.sys.platform === cc.sys.WECHAT_GAME) { return 'wx'; } else if (cc.sys.platform === cc.sys.BYTEDANCE_GAME) { return 'tt'; } else if (cc.sys.platform === cc.sys.OPPO_GAME) { return 'qg'; } else if (cc.sys.platform === cc.sys.VIVO_GAME) { return 'qg'; } else { return null; } } /** * 对象池 * @param prefab 节点预制 * @param maxNum 对象池初始长度 */ public static initNodePool(prefab: cc.Prefab, maxNum: number) { let nodePool = new cc.NodePool(); let initNum = maxNum; for (let i = 0; i < initNum; ++i) { let node = cc.instantiate(prefab); nodePool.put(node); } return nodePool; } };