教程目录
一 前言
二 实际效果
三 实现原理
四 自定义位图影片剪辑类
五 切图工具类
六 使用示例
七 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, 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,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源码下载