【咸魚教程】自定義序列圖工具類(制作序列圖動畫)


教程目錄  
一 前言
二 實際效果
三 實現原理
四 自定義位圖影片剪輯類
五 切圖工具類
六 使用示例
七 Demo源碼下載


一 前言

一般我們做動畫用TextureMerger,用gif或swf,導出一個json和png紋理合集,用MovieClip類來實現。
現在我們使用自定義的BitmapMovie類來制作序列圖動畫,直接用代碼制作,節省TextureMerger工具的操作步驟。

參考:史上最高效、易用的位圖動畫類開源了,還不快進來!?
         《ActionScript3.0 基礎動畫教程》第一章 基本動畫概念

使用封裝好的工具類,只需要簡單幾句就能使用。

[C#]  純文本查看 復制代碼
?
1
2
3
4
var mc:BitmapMovie = new BitmapMovie();
mc.initByTile( "dragon" , "jpg" ,18);
this .addChild(mc);
mc.play();



二 實際效果


多張序列圖
 

             


一整張序列圖

      

 


三 實現原理
1 自定義BtimapMovie類繼承自eui.Image。(不繼承egret.Bitmap,因為沒有eui的特性,比如約束適配...)
2 整張的序列圖,使用egret.Texture的initData進行切圖,並將切下的texture保存到數組中。
3 零碎的序列圖,使用RES.getRes(),將texture保存到數組中。
3 每一幀切換紋理 BitmapMovie.texture =  下一張texture,這樣就連成了一個動畫。
 

四 自定義位圖影片剪輯類
1 整張序列圖,使用initByOnePic進行初始化,對整張Bitmap進行裁剪,變成單張的texture,並保存到數組中。
2 多張序列圖,使用initByTile進行初始化,將單張的texture保存到數組中
3 使用egret.Timer進行計時,輪流切換BitmapMovie.texture,達到動畫的效果。 (這樣每一個剪輯就有一個timer,這里可以優化...)
4 提供了egret.MoveClip的play, stop, gotoAndPlay, gotoAndStop等,其他可自行擴展....

 
class BitmapMovie extends eui.Image{
    /**紋理緩存列表 */
    private textureCaches:Array<egret.Texture> = [];
    /**總幀數 */
    public totalFrame:number;
    /**當前播放幀數 索引從1開始 */
    public curFrame:number = 0;
    /**計時器 */
    private timer:egret.Timer;
    /**播放延遲 默認30幀*/
    private _delay:number = 1000/30;
    /**循環次數 */
    private loop:number = 0;

    public constructor() {
        super();
    }
    /**
     * 使用整張序列圖創建動畫
     * @param srcTexture 源紋理
     * @param maxRow 有幾行
     * @param maxCol 有幾列
     * @param startPos 從第幾張位置開始切(包含該位置 索引從0開始)
     * @param pieceNum 切多少張
     * @param width tile寬度
     * @param height tile高度
     */
    public initByOnePic(srcTexture:egret.Texture, maxRow:number, maxCol:number, startPos:number, pieceNum:number, width:number, height:number){
        this.textureCaches = CutImgTool.cutTile(srcTexture, maxRow, maxCol, startPos, pieceNum, width, height);
        if(this.textureCaches && this.textureCaches.length > 0){
            this.texture = this.textureCaches[0];
            this.curFrame = 0;
            this.totalFrame = this.textureCaches.length;
        }
    }
    /**
     * 使用多張序列圖創建動畫  命名格式: "boom0_png"
     * @param imgName 圖片名稱  "boom"
     * @param imgType 圖片后綴 "png" ("jpg")
     * @param pieceNum 有多少張
     */
    public initByTile(imgName:string, imgType:string, pieceNum:number){
        this.textureCaches.length = 0;
        for(var i=0;i<pieceNum;i++){
            if(RES.hasRes(imgName + i + "_" + imgType)){
                this.textureCaches[i] = RES.getRes(imgName + i + "_" + imgType);
            }else{
                this.textureCaches[i] = null;
                Log.error("BitmapMovie >> 序列圖不存在:", imgName + i + "_" + imgType);
            }
        }
        this.texture = this.textureCaches[0];
        this.curFrame = 0;
        this.totalFrame = this.textureCaches.length;
    }
    /**
     * 播放
     * @param loop 循環次數  負整數無限循環
     */
    public play(loop:number = 0){
        this.loop = loop;
        this.startTimer();
    }
    /**
     * 停止播放
     */
    public stop(){
        this.stopTimer();
    }
    /**
     * 跳轉播放
     * @param frame 播放的起始幀 (索引從1開始)
     * @param loop 循環次數
     */
    public gotoAndPlay(frame:number, loop:number = 0){
        if(frame <= this.totalFrame){
            this.loop = loop;
            this.curFrame = frame;
            this.texture = this.textureCaches[frame-1];
            this.startTimer();
        }else{
            Log.error("BitmapMovie >> frame超出范圍");
        }
    }
    
    /**
     * 跳轉並停止
     * @param frame 幀 (索引從1開始)
     */
    public gotoAndStop(frame:number){
        if(frame <= this.totalFrame){
            this.stopTimer();
            this.curFrame = frame;
            this.texture = this.textureCaches[frame-1];
        }else{
            Log.error("BitmapMovie >> frame超出范圍");
        }
    }
    
    /**啟動計時器 */
    private startTimer(){
        this.timer || (this.timer = new egret.Timer(this.delay));
        this.timer.addEventListener(egret.TimerEvent.TIMER, this.onTimerHandler, this);
        this.timer.reset();
        this.timer.start();
    }

    /**計時處理 */
    private onTimerHandler(){
        this.curFrame ++;
        if(this.curFrame <= this.totalFrame){
            this.texture = this.textureCaches[this.curFrame-1];
        }else{
            this.loop --;
            this.dispatchEvent(new egret.Event(egret.Event.LOOP_COMPLETE));
            if(this.loop == 0){
                this.stopTimer();
                this.dispatchEvent(new egret.Event(egret.Event.COMPLETE));
            }else{
                this.curFrame = 1;
                this.texture = this.textureCaches[this.curFrame-1];
            } 
        }
    }
    
    /**停止計時 */
    private stopTimer(){
        if(this.timer){
            this.timer.removeEventListener(egret.TimerEvent.TIMER, this.onTimerHandler, this);
            this.timer.stop();
        }
    }
    
    /**延遲 */
    public set delay(value:number){
        this._delay = value;
        if(this.timer){
            this.timer.delay = value;
        }
    }
    
    /**延遲 */
    public get delay(){
        return this._delay;
    }

    /**銷毀 */
    public destroy(){
        //移除舞台
        this.parent && this.parent.removeChild(this);
        //停止並刪除計時器
        this.stop();
        this.timer = null;
        //刪除紋理
        this.textureCaches.length = 0;
    }
}

  


五 切圖工具類

    /**
     * 切圖
     * @param srcTexture 源圖
     * @param maxRow 有幾行
     * @param maxCol 有幾列
     * @param startPos 從第幾張位置開始切(包含該位置 索引從0開始)
     * @param pieceNum 切多少張
     * @param width tile寬度
     * @param height tile高度
     * @returns 返回切割的紋理列表
     */
    public static cutTile(srcTexture:egret.Texture,maxRow:number,maxCol:number,startPos:number, pieceNum:number,width:number,height:number){
        var rect:egret.Rectangle = new egret.Rectangle();  //切割矩形區域
        var cutCount:number = 0;                           //當前已切割多少塊
        var textureCaches = [];                            //保存切割的紋理
        for(var i=0;i<maxRow;i++){
            for(var j=0;j<maxCol;j++){
                //>=起始位置,並且<=切割數量
                if((i*maxCol + j >= startPos) && cutCount <= pieceNum){
                    let texture:egret.Texture = new egret.Texture();
                    texture.disposeBitmapData = false;
                    texture.$bitmapData = srcTexture.$bitmapData;
                    texture.$initData(j*width, i*height, width, height, 0, 0, width, height, srcTexture.textureWidth, srcTexture.textureHeight);
                    textureCaches.push(texture);
                    cutCount++;
                }else{
                    return textureCaches;
                }
            }
        }
        return textureCaches;
    }
}

  


六 使用示例

 
let mc:BitmapMovie = new BitmapMovie();
 mc.initByOnePic(RES.getRes("login_edge_jpg"),1,10,0,10,48,48);
 mc.x = i*50;
mc.y = 200;
 mc.play(-1);
this.addChild(mc);

  

 
 


七 Demo下載

https://files-cdn.cnblogs.com/files/gamedaybyday/Egret3.2.6_MovieBitmapExample.7z


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM