教程目錄
一 前言
二 實際效果
三 實現原理
四 自定義位圖影片剪輯類
五 切圖工具類
六 使用示例
七 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
