cocos creator实现读取白鹭movieClip组件(尝试)

发布于:2022-12-03 ⋅ 阅读:(163) ⋅ 点赞:(0)

背景:原本是做白鹭项目的,后续考虑换成creator,但是由于creator的动画编辑器比较难受,而在白鹭那边已经有了一些脚本工具,因此希望在creator上实现一个组件,直接能够播放白鹭的movieClip。

        在cocos社区找了一圈,没有找到可以直接伸手的组件,故想着自己也试着来造造轮子。

期待的样子:

1.实现movieClip控件(继承Node节点),直接new出来,添加到对应节点下,然后可以调用load(fileName)接口直接加载资源。playMovie/loadAndPlay等直接播放或者加载播放对应的动画/动作;一些额外回调操作;

2.实现movieClipComponent组件,可以挂载到节点上。具体是实现上述的需求。

首先做的一些准备:

        1.封装了读取mc资源的接口,主要是来读取json跟texture2d;

 加载json,加载texture,保证两步都加载完成了,才进行下一步操作。

解析配置主要做的是把json里的资源resData跟  动画mcData保存下来。

实现思路:

        1.当前帧包括当前动画/当前动作/当前帧索引等。将这些作为一个私有变量保存起来,这样可以随时getter/setter。在数据发生变化的时候才重新去计算当前值。

        2.基于update帧驱动或者计时器驱动,获取当前帧的配置数据,将纹理渲染出来,然后索引+1,等待下一次刷新。

只是拿到了当前帧的配置数据,怎样才能在雪碧图里裁切出想要的子图呢?

在这里我采取的办法是spriteFrame中的设置rect,来实现子图的效果。

在实现的路上,暂时忽略new过程中的性能损耗。。。。

3.后续又加入了循环以及播放次数的判断。播放结束/完成等的判断。

 最后终于能够把动画播放起来了。 

延时切换到该文件下的其他动画,结果也是可行。 

最后是完整的代码。。。。。

import { Node } from "cc";
import { MovieClipComponent } from "./MovieClipComponent";

export class MovieClip extends Node{

    private _mcc:MovieClipComponent;
    private get mcc(){
        if(!this._mcc)
            this._mcc = this.addComponent(MovieClipComponent);
        return this._mcc;
    }
    private _fileName:string;
    constructor(){
        super();
    }

    onLoad(){
        
    };

    /**
     *  加载mc资源文件
     */
    public loadFile(fileName:string){
        if(fileName === this._fileName){
            return;
        }
        this._fileName = fileName;
        this.mcc.loadFile(fileName);
    }

    /**加载并播放  指定文件名 动画名 动作名 次数 加载完成回调*/
    public loadAndPlay(fileName:string,mcName:string,actName?:string,times?:number,compeletCall?:Function,target?:any){
        this._fileName = fileName;
        this.mcc.loadAndPlay(fileName,mcName,actName,times,compeletCall,target);
    }

    /**播放指定动画 动作 */
    public playMovie(mcName: string, actName?: string, times?: number){
        if(!this._fileName)
            return;
        this.mcc.playMovie(mcName,actName,times);
    }

    /**跳到指定动作的第几帧 播放次数 播放一轮回调 播放完成回调 -------  当前动画*/
    public gotoAndPlay(actName: string, frame: number = 0, times: number = -1, roundCall?: Function,finishCall?: Function, target?: any) {
        if(target){
            roundCall = roundCall && roundCall.bind(target);
            finishCall = finishCall && finishCall.bind(target);
        }
        this.mcc.gotoAndPlay(actName, frame, times, roundCall, finishCall);
    } 

}
import { Component, JsonAsset, Layers, math, Node, Rect, Sprite, SpriteFrame, Texture2D, UITransform, Vec2, _decorator } from "cc";
import { ResourceManage } from "../ResourceManage";

const { ccclass, property } = _decorator;


/**
 * 帧动画组件
 * 
 * 读取白鹭.json + .png资源格式
 * 利用帧刷新/计时器来刷新纹理
 * 
 */
@ccclass('MovieClipComponent')
export class MovieClipComponent extends Component {


    /**资源文件名 */
    private _fileName: string;
    /**帧图数据 */
    private _resData: any;
    /**动画数据 */
    private _mcData: any;
    /**纹理数据 */
    private _texture2d: Texture2D;

    /**渲染节点 */
    private _sprite: Sprite;
    private _spriteUI: UITransform;

    /**播放次数 -1为循环播放 */
    private _times: number;

    /**加载完成回调 */
    private _compeletCall: Function;
    /**播放一轮回调 */
    private _playRoundCall:Function;
    /**播放结束回调 */
    private _playFinishCall:Function;

    /**是否播放中 */
    public isPlay: boolean;
    private _interval;
    /**帧率 */
    private _frameRate: number;
    /**设置帧率 */
    public set frameRate(rate: number) {
        if (!rate || this._frameRate == rate) {
            return;
        }
        this._frameRate = rate;
        this.play();
    }
    /**帧率 */
    public get frameRate() {
        return this._frameRate || this._mcData[this.mcName].frameRate || 24;
    }

    /**首图基准 */
    private _initPos: any;
    /**首图基准 */
    private get initPos() {
        if (!this._initPos)
            this._initPos = this._mcData[this.mcName].frames[0];
        return this._initPos
    }

    /**当前动画名 */
    private _mcName: string;
    /**当前动画名 */
    public get mcName(): string {
        if (!this._mcName)
            this._mcName = this._mcData && Object.keys(this._mcData)[0];
        return this._mcName;
    }
    /**当前动画名 */
    public set mcName(name: string) {
        let mcs = this._mcData && Object.keys(this._mcData);
        if (mcs.indexOf(name) == -1) {
            name = mcs[0];
        }
        this._mcName = name;
    }

    /**当前动作名 */
    private _actName: string;
    /**当前动作名 */
    public get actName() {
        if (this._actName == void 0) {
            let labels = this.actNames;
            this._actName = labels[0].name;
        }
        return this._actName;
    }
    /**设置当前动作名 */
    public set actName(name) {
        if (this._actName == name)
            return;
        let actNames = this.actNames;
        for (let data of actNames) {
            if (data.name == name) {
                this._actName = name;
                break;
            }
        }
    }

    /**当前动画所有动作 */
    private _actNames: any[];
    /**当前动画所有动作 */
    public get actNames() {
        if (!this._actNames)
            this._actNames = this._mcData[this.mcName].labels || [{ name: "", frame: 1, end: this._mcData[this.mcName].frames.length }];
        return this._actNames;
    }

    onLoad() {
        let node = new Node('mc');
        node.layer = Layers.Enum.UI_2D;
        node.parent = this.node;
        this._sprite = node.addComponent(Sprite);
        // this._sprite =  this.node.getChildByName("Sprite").getComponent(Sprite);
        this._spriteUI = this._sprite.getComponent(UITransform);
    }

    /**加载资源 */
    public loadFile(fileName: string,compeletCall?:Function) {
        if (fileName == this._fileName)
            return;
        this._fileName = fileName;
        this._compeletCall = compeletCall;
        let thiz = this;
        ResourceManage.loadMcRes(`${fileName}`, JsonAsset, (res: JsonAsset) => {
            thiz.parseJson(res.json);
            thiz.checkCompelet();
        });
        ResourceManage.loadMcRes(`${fileName}/texture`, Texture2D, (res: Texture2D) => {
            if (res) {
                thiz._texture2d = res;
                thiz.checkCompelet();
            }
        });
    }

    /**解析配置 */
    private parseJson(data: any) {
        this._resData = data.res;
        this._mcData = data.mc;
    }

    /**检查加载状态 */
    private checkCompelet(): boolean {
        if (this._resData && this._mcData) {
            this.doLoadCompelet();
            return true;
        }
        return false;
    }

    /**加载完成 */
    private doLoadCompelet() {
        this._compeletCall && this._compeletCall()
    }

    /**加载并播放
     * @property fileName 文件名
     * @property mcName 动画名
     * @property actName 动作名
     * @property times 播放次数 -1为循环
     * @property compeletCall 加载完成回调
     */
    public loadAndPlay(fileName: string, mcName: string, actName: string, times: number = -1, compeletCall?: Function, target?: any) {
        let thiz = this;
        this.loadFile(fileName,() => {
            thiz.playMovie(mcName, actName, times);
            compeletCall && compeletCall.call(target);

        });
    }

    /**播放动画 */
    public playMovie(mcName: string, actName?: string, times: number = -1) {
        this.mcName = mcName;
        this.gotoAndPlay(actName, 0, times);
    }


    /**跳到指定动作 指定帧 */
    public gotoAndPlay(actName: string, frame: number = 0, times: number = -1, roundCall?: Function, finishCall?:Function,) {
        this.curIndex = void 0;
        this.actName = actName;
        this._actData = void 0;
        this._times = times;
        this.curIndex = frame;
        this._times = times;
        this._playRoundCall = roundCall;
        this._playFinishCall = finishCall;
        this.play();
    }




    public play() {
        if (this.isPlay)
            return;
        let thiz = this;
        clearInterval(this._interval);
        this.isPlay = true;
        this._interval = setInterval(() => {
            thiz.doTimeUpdate();
        }, 1000.0 / this.frameRate);
    }

    /**停止播放 */
    public stop() {
        if (!this.isPlay)
            return;
        this.isPlay = false;
        this.curIndex = 0;
        clearInterval(this._interval);
    }

    public pause() {
        if (!this.isPlay)
            return;
        this.isPlay = false;
        clearInterval(this._interval);
    }

    /**重新播放 */
    public replay() {
        this.isPlay = false;
        this.curIndex = 0;
        this.play();
    }



    /**当前帧索引*/
    private _curIndex: number;
    private get curIndex() {
        if (!this._curIndex == void 0 || this._curIndex < this.actData.frame || this._curIndex > this.actData.end) {
            this._curIndex = this.actData.frame - 1;
        }
        return this._curIndex
    }
    private set curIndex(index) {
        if (index == void 0 || index < this.actData.frame - 1 || index > this.actData.end) {
            return;
        }
        this._curIndex = index;
    }
    /**当前帧数据 */
    private _actData: any;
    private get actData() {
        if (!this._actData) {
            let labels = this.actNames;
            for (let data of labels) {
                if (data.name == this.actName) {
                    this._actData = data;
                    break;
                }
            }
        }
        return this._actData;
    }
    /**当前帧数据 */
    private get curFrameData() {
        return this._mcData[this.mcName].frames[this.curIndex];
    }

    /**当前纹理数据 */
    private getCurResData(res: string) {
        return this._resData[res];
    }


    private doTimeUpdate() {
        if (!this.isPlay) {
            return;
        }
        let curFrame = this.curFrameData;
        if (!curFrame) {
            return;
        }
        let res = this.getCurResData(curFrame.res);
        let spriteFrame = new SpriteFrame();
        spriteFrame.texture = this._texture2d;
        this._sprite.spriteFrame = spriteFrame;
        this._sprite.spriteFrame.rect = new Rect(res.x, res.y, res.w, res.h);
        this._sprite.spriteFrame.offset = new Vec2(res.x, res.y);
        this._sprite.node.setPosition(curFrame.x - this.initPos.x, curFrame.y - this.initPos.y);
        this._spriteUI.width = res.w;
        this._spriteUI.height = res.h;
        this.curIndex++;
        if (this.curIndex >= this.actData.end) {
            if (this._times > 0) {
                this._times--;
            }
            this.curIndex = 0;
            this.doPlayRound();
            if (this._times == 0) {
                this.isPlay = false;
                this.doPlayFinished();
            }
        }
    }

    /**播放结束 */
    private doPlayFinished() {
        console.log('endddddddddddddddd');
        this._playFinishCall && this._playFinishCall();
    }

    /**播放一轮 */
    private doPlayRound() {
        console.log('rooooooooooound');
        this._playRoundCall && this._playRoundCall();
    }

}


网站公告

今日签到

点亮在社区的每一天
去签到