教程目录
一 前言
二 实际效果
三 实现原理
四 自定义位图影片剪辑类
五 切图工具类
六 使用示例
七 Demo源码下载
一 前言
一般我们做动画用TextureMerger,用gif或swf,导出一个json和png纹理合集,用MovieClip类来实现。
现在我们使用自定义的BitmapMovie类来制作序列图动画,直接用代码制作,节省TextureMerger工具的操作步骤。
参考:史上最高效、易用的位图动画类开源了,还不快进来!?
《ActionScript3.0 基础动画教程》第一章 基本动画概念
使用封装好的工具类,只需要简单几句就能使用。
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);
https://files-cdn.cnblogs.com/files/gamedaybyday/Egret3.2.6_MovieBitmapExample.7z