import { isValid, Node, Quat, sp, sys, systemEvent, SystemEvent, tween, UIOpacity, UITransform, v3, Vec3, view } from "cc"; import { constants } from "../game/data/constants"; import { resManager } from "../game/manager/resManager"; export const cocosUtil = { addHand(attachNode: Node, parent: Node, cb?: Function) { resManager.instance.loadAsset(constants.bundles.common.name, constants.bundles.common.spine.shouzhi, sp.SkeletonData, () => { }, (err, skeletonData) => { if (err) { return; } let handNode = new Node(); let handSkeleton = handNode.addComponent(sp.Skeleton); handSkeleton.skeletonData = skeletonData; handSkeleton.setAnimation(0, "dianji", true); handSkeleton.premultipliedAlpha = false; handNode.parent = parent; let pos = cocosUtil.convertToWorldSpace(attachNode, true); pos = cocosUtil.convertToNodeSpace(handNode, pos); handNode.setPosition(pos); if (cb) { cb(handNode); } }); }, tweenBlink(node: Node, time?: number) { if (!time) { time = 0.5; } tween(node.getComponent(UIOpacity)).to(time, { opacity: 0 }).to(time, { opacity: 255 }).union().repeatForever().start(); }, tweenRotate(node: Node, time?: number) { if (!time) { time = 2; } let quat = new Quat(); let angle = 360; Quat.fromEuler(quat, 0, 0, angle); tween(node).by(time, { rotation: quat }, { easing: "linear", onUpdate: (target: Node, ratio: number) => { let da = angle * ratio; Quat.fromEuler(quat, 0, 0, da); target.setRotation(quat); } }).repeatForever().start(); }, tweenUpDown(node: Node, dy?: number, time?: number) { if (!dy) { dy = 10; } if (!time) { time = 1; } let pos1 = node.getPosition(); pos1.y += dy; let pos2 = node.getPosition(); tween(node).to(time, { position: pos1 }).to(time, { position: pos2 }).union().repeatForever().start(); }, tweenFadeOut(node: Node, time?: number, cb?: Function) { if (!time) { time = 1.5; } tween(node.getComponent(UIOpacity)).to(time, { opacity: 0 }).call(() => { if (cb) { cb(); } }).start(); }, /** * 放大缩小呼吸效果 * @param node 节点 * @param time 缩放时长,单位:秒 * @param scale 缩放大小 */ tweenScaleBreath(node: Node, time?: number, scale?: number) { if (!time) { time = 0.4; } if (!scale) { scale = 1.2; } tween(node).to( time, { scale: v3(scale, scale, 1) } ).to( time, { scale: v3(1, 1, 1) } ).union().repeatForever().start(); }, /** * 间接性晃动效果 * @param node 节点 * @param time 时长,单位:秒 * @param rotation 旋转角度,单位:度数 * @param delayTime 中间暂停时长,单位:秒 */ tweenShake(node: Node, time?: number, rotation?: number, delayTime?: number) { if (!time) { time = 0.2; } if (!rotation) { rotation = 6; } if (delayTime == undefined) { delayTime = time * 5; } let quat1: Quat = new Quat(); Quat.fromEuler(quat1, 0, 0, rotation); let quat2: Quat = new Quat(); Quat.fromEuler(quat2, 0, 0, -rotation); let quat3: Quat = new Quat(); Quat.fromEuler(quat3, 0, 0, 0); tween(node).to(time, { rotation: quat1 }).to(time * 2, { rotation: quat2 }).to(time, { rotation: quat3 }).delay(delayTime).union().repeatForever().start(); }, /** * 判断节点是否可用 * @param node 节点对象 */ isNodeValid(node: Node) { if (!node || !isValid(node)) { return false; } return true; }, isAndroid() { return sys.platform === sys.Platform.ANDROID; }, isDesktopBrowser() { return sys.platform === sys.Platform.DESKTOP_BROWSER; }, isIos() { return sys.platform === sys.Platform.IOS; }, isWechatGame() { return sys.platform === sys.Platform.WECHAT_GAME; }, addKeyDownListener(cb, sender) { systemEvent.on(SystemEvent.EventType.KEY_DOWN, cb, sender); }, init() { // 设计分辨率 this.designSize = view.getDesignResolutionSize(); // 实际屏幕分辨率 this.frameSize = view.getFrameSize(); // 实际屏幕安全区域,{x: 0, y: 0, width: 766.6256157635468, height: 1660} // 是以左下角为原点,以设计分辨率为单位的,并且是遵循高度为适配原则后的尺寸 this.safeAreaRect = sys.getSafeAreaRect(); // 计算出顶部刘海屏高度 this.safeAreaMarginTop = this.designSize.height - this.safeAreaRect.height; if (this.safeAreaMarginTop < 0) { this.safeAreaMarginTop = 0; } this.intiScreenAdapterWidthScale(); this.initScreenBgAdapterWidthScale(); }, // UI适配,以高度为适配原则,按照满宽度显示计算,如果宽度不够显示,要乘以这个缩放比例 intiScreenAdapterWidthScale() { let fh = this.frameSize.height; let fw = this.frameSize.width; let scale = fh / this.designSize.height; let adapterWidth = this.designSize.width * scale; let retScale = 1; if (adapterWidth > fw) { // 屏幕不够显示,有些交互UI会丢失,要进行缩小 retScale = fw / adapterWidth; } // if (this.safeAreaMarginTop > 0) { // // cocos内部以高度为适配策略,但是如果有刘海屏,要额外再缩放一点 // let subScale = this.safeAreaMarginTop / this.designSize.height; // retScale -= subScale; // } this.screenAdapterScale = retScale; }, getScreenAdapterScale() { if (!this.screenAdapterScale) { this.screenAdapterScale = 1; } return this.screenAdapterScale; }, // 背景图适配,跟上面的UI适配,刚好相反,超出的屏幕不管,屏幕没显示满,要放大 initScreenBgAdapterWidthScale() { let fh = this.frameSize.height; let fw = this.frameSize.width; let scale = fh / this.designSize.height; let adapterWidth = this.designSize.width * scale; let retScale = 1; if (adapterWidth < fw) { // 屏幕没显示满,会有黑边,要进行放大 retScale = fw / adapterWidth; } // if (this.safeAreaMarginTop > 0) { // // 额外增加放大值,使得背景图铺满包括刘海在内的整个屏幕 // let addScale = this.safeAreaMarginTop / this.designSize.height; // retScale += addScale; // } this.screenBgAdapterScale = retScale; }, getScreenBgAdapterScale() { if (!this.screenBgAdapterScale) { this.screenBgAdapterScale = 1; } return this.screenBgAdapterScale; }, /** * 将node坐标转换为世界坐标 * @param node * @param isCenter 是否强制是node的中心点坐标 */ convertToWorldSpace(node: Node, isCenter?: boolean) { let transform = node.parent.getComponent(UITransform); let pos = node.getPosition(); if (isCenter) { let tf = node.getComponent(UITransform); pos.x = pos.x + (0.5 - tf.anchorX) * tf.width; pos.y = pos.y + (0.5 - tf.anchorY) * tf.height; } return transform.convertToWorldSpaceAR(pos); }, /** * 获得以node父节点锚点位置为原点的坐标系下的坐标 * @param node 注意,是同坐标下的节点 * @param pos 世界坐标 */ convertToNodeSpace(node: Node, pos: Vec3) { let transform = node.parent.getComponent(UITransform); return transform.convertToNodeSpaceAR(pos); }, setPositionX(node: Node, x: number) { let pos = node.getPosition(); pos.x = x; node.setPosition(pos); }, setPositionY(node: Node, y: number) { let pos = node.getPosition(); pos.y = y; node.setPosition(pos); }, }