AnimationUtils.ts 6.34 KB
import FrameAnimation from "../components/FrameAnimation";
import { ScheduleUtils } from "./ScheduleUtils";

export namespace AnimationUtils {
    export function playFrameAnimation(node: cc.Node, loop: boolean, name: string, callback?: (loopCount?: number) => void) {
        let anims = node.getComponents(FrameAnimation)
        if (!anims || anims.length == 0) {
            return
        }
        let findOne: FrameAnimation = anims[0]
        for (let i = 0; i < anims.length; i++) {
            const anim = anims[i];
            if (anim.tag == name) {
                findOne = anim
            } else {
                anim.enabled = false
            }
        }
        findOne.enabled = true;
        findOne.play(callback, loop);
    }

    export function playFrameAnimationOnce(node: cc.Node, name: string, callback?: (loopCount?: number) => void) {
        playFrameAnimation(node, false, name, callback);
    }

    export function playFrameAnimationLoop(node: cc.Node, name: string) {
        playFrameAnimation(node, true, name);
    }

    export function animateProgress(progressBar: cc.ProgressBar, progress: number, speed = 1, label?: cc.Label): Promise<void> {
        return new Promise((resolve) => {
            let oldProgress = progressBar.progress
            if (oldProgress == progress) {
                resolve();
                return;
            }
            if (progress > 1) progress = 1;
            if (progress < 0) progress = 0;
            let delta = progress - oldProgress;

            if ((<any>progressBar).updateFunc) ScheduleUtils.unscheduleUpdate((<any>progressBar).updateFunc);
            const update = (dt: number) => {
                oldProgress += delta * dt * speed;
                if ((delta > 0 && oldProgress > progress) || (delta < 0 && oldProgress < progress)) {
                    oldProgress = progress;
                    delete (<any>progressBar).updateFunc;
                    ScheduleUtils.unscheduleUpdate(update);
                    resolve();
                }
                progressBar.progress = oldProgress;
                if (label) label.string = `${Math.round(oldProgress * 1000) / 10}%`;
            }
            (<any>progressBar).updateFunc = update;
            ScheduleUtils.scheduleUpdate(update);
        });
    }

    //异步动画执行API. 方便链式调用.
    export async function runAction(node: cc.Node | cc.Component, action: cc.FiniteTimeAction | cc.FiniteTimeAction[]): Promise<any> {
        return new Promise<any>(resolve => {
            if (!action || !node) {
                console.info("runAction param is null:", node, action)
                resolve();
                return;
            }
            let nd = node instanceof cc.Component ? node.node : node
            nd.runAction(cc.sequence(action, cc.callFunc(function () {
                resolve()
            })))
        })
    }

    let timerIds: number[] = [];
    export function ActionTypeWriter(comp: cc.Label | cc.RichText, str: string, time?: number) {
        return new Promise<any>((resolve) => {
            if (timerIds && timerIds.length) {
                for (let i = 0; i < timerIds.length; i++) {
                    clearTimeout(timerIds[i]);
                }
                timerIds = [];
            }
            if (!comp || !str || "" === str.trim()) { return; }
            comp.string = str;
            time = time ? time : 1;
            let cArr: string[] = [];
            for (let i = 0; i < str.length; i++) {
                cArr.push(" ");
            }
            let reg = new RegExp(',', 'g');
            for (let i = 0; i < str.length; i++) {
                cArr[i] = str[i];
                let s = cArr.toString();
                let id = setTimeout(() => {
                    s = s.replace(reg, "");
                    comp.string = s;
                    if (s.length === str.length) {
                        resolve();
                    }
                }, time / str.length * 1000 * i);
                timerIds.push(id);
            }
        });
    }

    let animTime: number = 0.3;
    /**
     * 
     * @param maskNode 遮罩node
     * @param mainNode 所有内容node
     * @param params callback:执行完成后的回调,maskNodeOpacityValue遮罩node的opacity值
     */
    export function showUIAnim(mainNode: cc.Node, params = { callback: () => { }, maskNodeOpacityValue: 200 }, maskNode?: cc.Node): void {

        mainNode.scale = 0;
        mainNode.active = true;
        // 播放背景动画
        let opacityValue = params.maskNodeOpacityValue;
        if (maskNode) {
            maskNode.opacity = 0;
            maskNode.active = true;
            cc.tween(maskNode)
                .to(animTime * 0.8, { opacity: opacityValue })
                .call(() => {
                })
                .start();
        }

        // 播放主体动画
        cc.tween(mainNode)
            .to(animTime, { scale: 1 }, { easing: 'backOut' })
            .call(() => {
                // 弹窗已完全展示(动画完毕)
                if (params.callback) params.callback();
            })
            .start();

    }

    /**
     * 
     * @param parentNode 该组件挂载的node
     * @param maskNode 遮罩node
     * @param mainNode 所有内容node
     * @param params callback:执行完成后的回调,maskNodeOpacityValue遮罩node的opacity值
     */
    export function hideUIAnim(parentNode: cc.Node, mainNode: cc.Node, params = { callback: () => { } }, maskNode?: cc.Node): void {
        // 拦截点击事件
        let blocker = parentNode.getChildByName("blocker");
        if (!blocker) {
            blocker = new cc.Node('blocker');
            blocker.addComponent(cc.BlockInputEvents);
            blocker.setParent(parentNode);
            blocker.setContentSize(parentNode.getContentSize());
        }
        blocker.active = true;
        if (maskNode) {
            // 播放背景动画
            cc.tween(maskNode)
                .delay(animTime * 0.2)
                .to(animTime * 0.8, { opacity: 0 })
                .call(() => {
                })
                .start();
        }

        // 播放主体动画
        cc.tween(mainNode)
            .to(animTime, { scale: 0 }, { easing: 'backIn' })
            .call(() => {
                blocker.active = false;
                if (params.callback) params.callback();
            })
            .start();
    }
}