让位图动起来!
这个主要是把一张绘制有几个图像,并且有连续关系的位图利用BitmapData类的copyPixels实例方法截取位图上面的部分图像,然后利用ENTER_FRAME事件或者Timer事件制作动画!
在这个方法里面有好几个重要参数
copyPixels(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, alphaBitmapData:BitmapData = null, alphaPoint:Point = null, mergeAlpha:Boolean = false)
sourceBitmapData:要制作动画的图片源
sourceRect:这个参数是一个Rectangle,它表示在源位图上开始切割的坐标,宽,高
destPoint:这个表示把切割好的位图作为Bitmap类的源的时候,左上角所在的坐标(我知道这样解析很难明白,但是我想不到其他的解析方式了)
其他参数请看帮助,因为我也没有去具体了解过,也很少用到!
要想你的位图动起来,还需要在制作位图的时候注意每一个图像之间要有一定的间隔,而且最好都在一个固定大小的矩形内。
好了现在把整个类的代码贴出来~!
因为我想用在项目中,所以也写了它的一个父类和一个支持多帧的类
所以工有三个类(DisplaySuper,BmpMovieClip,MultiFrameBmpMovieClip)
DisplaySuper类的代码(很简单):
1 package kongfu 2 { 3 import flash.display.DisplayObject; 4 import flash.display.DisplayObjectContainer; 5 import flash.display.Sprite; 6 /** 7 * ... 8 * @author kongfuzhou 9 10 */ 11 public class DisplaySuper extends Sprite 12 { 13 public var parentDpl:DisplayObjectContainer; 14 15 public function DisplaySuper(self:DisplaySuper) 16 { 17 if (self!=this) 18 { 19 throw new Error("abstract class can't new a instance!"); 20 } 21 } 22 /** 23 * 设置显示对象的坐标 24 * @param xp 25 * @param yp 26 * @param basePro 居于某个宽高居中显示 {w:500,h:500} 27 * @example 28 */ 29 public function setPosOrCenter(xp:Number=0,yp:Number=0,basePro:Object=null):void 30 { 31 if (basePro && basePro.w && basePro.h) 32 { 33 this.x = (basePro.w - this.width) / 2; 34 this.y = (basePro.h - this.height) / 2; 35 }else 36 { 37 this.x = xp; 38 this.y = yp; 39 } 40 41 } 42 protected function removeMySelf():void 43 { 44 if (this.parent) 45 { 46 this.parent.removeChild(this); 47 } 48 } 49 50 } 51 52 }
制作动画的主要类BmpMovieClip:
package kongfu { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.DisplayObject; import flash.display.DisplayObjectContainer; import flash.events.Event; import flash.events.TimerEvent; import flash.geom.Point; import flash.geom.Rectangle; import flash.utils.Timer; /** * 实现将连续位图转换成动画的类 * @author kongfuzhou */ public class BmpMovieClip extends DisplaySuper { /** * 各种属性 * * @example var obj:Object = { * startXY:{startX:Number,startY:Number}, sizeDiff: { xDiff:106, yDiff:119 }, xDiff:左右两张图的x坐标间隔,yDiff:上下两张图的y坐标间隔 sizePos: { w:80, h:60}, control: { len:12, col:8, row:2 } }; */ private var vars:Object; /** * 最终显示的位图 */ private var bmp_mc:Bitmap; /** * 源位图数据 */ public var bmpdResouce:BitmapData; /** * 最终位图数据 */ private var bmpMcData:BitmapData; private var index:int = 0; private var startPoint:Point; private var rectDataArr:Array; private var frameRate:int; public var firstIsEnd:Boolean = false; private var frameTimer:Timer; private var transParent:Boolean = true; private var color:uint = 0x00ffffff; private var resBmpdObj:Object; private var boolObj:Object; public var isStop:Boolean = true; public var oneTimesFunc:Function; /** * 构造函数 * * @param vars 调用动画的各种属性 * @param resBmpdObj {bmpdRes:BitmapData,bmpdCs:Class} * @param parentDpl 父层 * @param boolObj 该对像的属性是boolean类型的{opentFrameEvent:Boolean=true,useTimer:Boolean=false,autoPlay:Boolean=false} * @param frameRate 使用timer来进行切割位图做动画时的虚拟帧频 * @param startPoint destPoint参数 * @param rectDataArr BitmapData实例的copyPixels函数里面的Rectangle参数的参数(当你想每一个图片的宽、高、切割的X和Y坐标是自己随意定义的时传该参数) */ public function BmpMovieClip(vars:Object, resBmpdObj:Object, parentDpl:DisplayObjectContainer, boolObj:Object = null, frameRate:int = 0, startPoint:Point = null, rectDataArr:Array = null) { super(this); this.boolObj = boolObj; this.boolObj == null ? this.boolObj = {opentFrameEvent: true, useTimer: false, autoPlay: true} : ""; this.boolObj.opentFrameEvent == null ? this.boolObj.opentFrameEvent = true : ""; this.boolObj.useTimer == null ? this.boolObj.useTimer = false : ""; this.boolObj.autoPlay == null ? this.boolObj.autoPlay = true : ""; this.resBmpdObj = resBmpdObj; this.frameRate = frameRate; this.rectDataArr = rectDataArr; this.startPoint = startPoint; this.startPoint == null ? this.startPoint = new Point(0, 0) : ""; this.parentDpl = parentDpl; this.vars = vars; init(); } private function init():void { if (this.vars.control == null || this.vars.startXY == null || this.vars.sizeDiff == null || this.vars.sizePos == null) { throw new Error("vars's property must four or more!"); } this.rectDataArr ? this.vars.control.len = this.rectDataArr.length : ""; this.bmp_mc = new Bitmap(); this.vars.transParent ? this.transParent = this.vars.transParent : ""; this.vars.color ? this.color = this.vars.color : ""; this.bmpMcData = new BitmapData(this.vars.sizePos.w, this.vars.sizePos.h, this.transParent, this.color); if (this.resBmpdObj.bmpdRes) { this.bmpdResouce = this.resBmpdObj.bmpdRes; } else if (this.resBmpdObj.bmpdCs) { this.bmpdResouce = new this.resBmpdObj.bmpdCs(); } if (this.resBmpdObj.bmpdRes == null && this.resBmpdObj.bmpdCs == null) { throw new Error("resBmpdObj must be not null!"); } if (this.bmpdResouce) { this.bmp_mc.bitmapData = this.bmpMcData; this.addChild(this.bmp_mc); this.parentDpl ? this.parentDpl.addChild(this) : ""; if (this.boolObj.useTimer == true) { addTimerEvent(); } } if (this.boolObj.autoPlay == true) { play(); } else { letItMove(); } } private function addTimerEvent():void { this.boolObj.opentFrameEvent = false; this.frameRate == 0 ? this.frameRate = 30 : ""; this.frameTimer = new Timer(int(1000 / this.frameRate)); this.frameTimer.addEventListener(TimerEvent.TIMER, timerHandler); } /** * 播放 */ public function play():void { if (this.boolObj.useTimer == true) { if (this.frameTimer.hasEventListener(TimerEvent.TIMER)) { this.frameTimer.start(); } else { addTimerEvent(); this.frameTimer.start(); } } else if (this.boolObj.opentFrameEvent == true) { this.addEventListener(Event.ENTER_FRAME, onEnterFrame); } } /** * 停止在第一个画面 */ public function stop():void { this.removeEvent(); this.index = 0; letItMove(); } private function timerHandler(e:TimerEvent):void { letItMove(); } private function onEnterFrame(e:Event):void { letItMove(); } /** * 截取bitmapdata上面的图像生成动画 */ public function letItMove():void { if (this.index < this.vars.control.len) { if (this.rectDataArr) { var obj:Object = this.rectDataArr[this.index]; if (obj==null || obj.xp==null || obj.yp==null || obj.w==null || obj.h==null) { throw new Error(" bitmapData.copyPixels() args of Rectangle got a unable args!"); } this.bmpMcData.copyPixels(this.bmpdResouce, new Rectangle(obj.xp, obj.yp, obj.w, obj.h), new Point((this.width - obj.w) / 2, 0)) } else { var xp:Number = this.vars.startXY.startX + (this.index % this.vars.control.col) * this.vars.sizeDiff.xDiff; var yp:Number = this.vars.startXY.startY + int(this.index / this.vars.control.col) * this.vars.sizeDiff.yDiff; this.bmpMcData.copyPixels(this.bmpdResouce, new Rectangle(xp, yp, this.vars.sizePos.w, this.vars.sizePos.h), this.startPoint); } this.index++; } else if (this.oneTimesFunc != null) { this.firstIsEnd = true; this.oneTimesFunc(); } else { this.index = 0; } } /** * 把自己从显示列表中删除并且删除事件侦听器 */ public function remove():void { this.removeMySelf(); removeEvent(); } /** * 删除事件侦听器 */ public function removeEvent():void { if (this.boolObj.opentFrameEvent == true) { this.removeEventListener(Event.ENTER_FRAME, onEnterFrame); } if (this.boolObj.useTimer == true) { this.frameTimer.removeEventListener(TimerEvent.TIMER, timerHandler); } } } }
制作多帧动画的类MultiFrameBmpMovieClip:
1 package kongfu 2 { 3 import flash.display.DisplayObjectContainer; 4 import flash.events.Event; 5 import flash.utils.Dictionary; 6 7 /** 8 * 多帧位图mc 9 * ... 10 * @author kongfuzhou 11 12 */ 13 public class MultiFrameBmpMovieClip extends DisplaySuper 14 { 15 private var framesObj:Object = new Object(); 16 private var framesArr:Array; 17 public var curFrameBmp_mc:BmpMovieClip; 18 public var totalFrames:int; 19 public var curFrameLabel:String; 20 public var curFrame:int; 21 private var framesDict:Dictionary = new Dictionary(); 22 private var frameLabelsDict:Dictionary = new Dictionary(); 23 private var curIndex:int = 1; 24 25 /** 26 * @param framesObj 每一帧的 27 * @param parentDlp 父层 28 */ 29 public function MultiFrameBmpMovieClip(framesArr:Array, parentDlp:DisplayObjectContainer = null) 30 { 31 super(this); 32 this.parentDpl = parentDlp; 33 this.framesArr = framesArr; 34 init(); 35 36 } 37 38 private function init():void 39 { 40 if (this.framesArr) 41 { 42 var index:int = 0; 43 for (var i in this.framesArr) 44 { 45 index++; 46 if (i is Number) 47 { 48 var str:String = "frame" + (i + 1); 49 this.framesObj[str] = this.framesArr[i]; 50 this.frameLabelsDict[this.framesObj[str]] = str; 51 } 52 else if (i is String) 53 { 54 this.framesObj[i] = this.framesArr[i]; 55 this.frameLabelsDict[this.framesObj[i]] = i; 56 } 57 this.framesDict[this.framesArr[i]] = index; 58 if (index == 1) 59 { 60 setCurFrame(this.framesArr[i]); 61 } 62 63 } 64 setTotalFrame(); 65 gotoPlay(); 66 } 67 else 68 { 69 this.framesArr = new Array(); 70 } 71 if (this.parentDpl) 72 { 73 this.parentDpl.addChild(this); 74 } 75 76 } 77 78 /** 79 * 播放某帧 80 * @param frame 帧名字符串,数字也可以直接输入 81 */ 82 public function gotoStop(frame:String):void 83 { 84 var fm:Number = Number(frame); 85 if (isNaN(fm)) 86 { 87 //不是数字 88 if (this.framesObj[frame]) 89 { 90 setShow(this.framesObj[frame]); 91 } 92 } 93 else 94 { 95 //是数字 96 if (this.framesArr[fm - 1]) 97 { 98 setShow(this.framesArr[fm - 1]); 99 } 100 } 101 } 102 103 /** 104 * 播放所有帧 105 */ 106 public function gotoPlay():void 107 { 108 //trace("gotoPlay: curIndex = "+this.curIndex+" totalFrames = "+this.totalFrames); 109 if (this.curIndex < this.totalFrames) 110 { 111 (this.framesArr[this.curIndex - 1] as BmpMovieClip).oneTimesFunc = playAll; 112 (this.framesArr[this.curIndex - 1] as BmpMovieClip).play(); 113 } 114 115 } 116 117 /** 118 * 控制播放所有帧 119 */ 120 private function playAll():void 121 { 122 if (this.curIndex > this.totalFrames) 123 { 124 for each (var item:BmpMovieClip in this.framesObj) 125 { 126 item.removeEvent(); 127 } 128 return; 129 } 130 if (this.framesArr[this.curIndex - 1]) 131 { 132 if ((this.framesArr[this.curIndex - 1] as BmpMovieClip).firstIsEnd) 133 { 134 this.curIndex++; 135 } 136 else 137 { 138 if (this.numChildren > 1) 139 { 140 while (this.numChildren > 0) 141 { 142 this.removeChildAt(0); 143 } 144 this.addChild(this.framesArr[this.curIndex - 1]); 145 setCurFrame(this.framesArr[this.curIndex - 1]); 146 } 147 else if (this.numChildren == 1) 148 { 149 var child:BmpMovieClip = (this.getChildAt(0) as BmpMovieClip); 150 if (child != this.framesArr[this.curIndex - 1]) 151 { 152 this.removeChildAt(0); 153 this.addChild(this.framesArr[this.curIndex - 1]); 154 setCurFrame(this.framesArr[this.curIndex - 1]); 155 } 156 else 157 { 158 (this.framesArr[this.curIndex - 1] as BmpMovieClip).oneTimesFunc = playAll; 159 (this.framesArr[this.curIndex - 1] as BmpMovieClip).play(); 160 } 161 } 162 else 163 { 164 this.addChild(this.framesArr[this.curIndex - 1]); 165 setCurFrame(this.framesArr[this.curIndex - 1]); 166 } 167 } 168 } 169 } 170 171 private function setCurFrame(bmp_mc:BmpMovieClip):void 172 { 173 if (this.framesDict[bmp_mc]) 174 { 175 this.curFrame = this.framesDict[bmp_mc]; 176 } 177 if (this.frameLabelsDict[bmp_mc]) 178 { 179 this.curFrameLabel = this.frameLabelsDict[bmp_mc]; 180 } 181 this.curFrameBmp_mc = bmp_mc; 182 this.curFrameBmp_mc.play(); 183 this.addChild(this.curFrameBmp_mc); 184 185 } 186 187 /** 188 * 增加帧 189 * @param frame 帧标签 190 * @param addBmpMc 该帧的动画 191 */ 192 public function addFrame(frame:String, addBmpMc:BmpMovieClip):void 193 { 194 var fm:Number = Number(frame); 195 if (isNaN(fm)) 196 { 197 //不是数字 198 if (this.framesObj[frame]) 199 { 200 throw new Error("this framlabel is exit!"); 201 } 202 else 203 { 204 this.framesObj[frame] = addBmpMc; 205 this.frameLabelsDict[addBmpMc] = frame; 206 } 207 208 } 209 else 210 { 211 //是数字 212 if (this.framesArr[fm - 1] || (fm - 1) < 0) 213 { 214 throw new Error("this framlabel is not exit!"); 215 } 216 else 217 { 218 var str:String = "frame" + (this.framesArr.length + 1); 219 this.framesObj[str] = addBmpMc; 220 this.frameLabelsDict[addBmpMc] = str; 221 } 222 223 } 224 this.framesArr.push(addBmpMc); 225 this.framesDict[addBmpMc] = this.framesArr.length; 226 this.setTotalFrame(); 227 228 } 229 230 /** 231 * 删除帧 232 * @param frame 233 */ 234 public function removeFrame(frame:String):void 235 { 236 var fm:Number = Number(frame); 237 if (isNaN(fm)) 238 { 239 //不是数字 240 for (var i in this.framesArr) 241 { 242 if (this.framesArr[i] == this.framesObj[frame]) 243 { 244 this.framesArr.splice(i, 1); 245 break; 246 } 247 } 248 (this.framesObj[frame] as BmpMovieClip).remove(); 249 this.framesObj[frame] = null; 250 } 251 else 252 { 253 //是数字 254 var j:int = int(frame); 255 if (this.framesArr[j - 1]) 256 { 257 for (var frameName in this.framesObj) 258 { 259 if (this.framesObj[frameName] == this.framesArr[j - 1]) 260 { 261 this.framesObj[frameName] = null; 262 break; 263 } 264 } 265 (this.framesArr[j - 1] as BmpMovieClip).remove(); 266 this.framesArr.splice(j - 1, 1); 267 268 } 269 270 } 271 this.setTotalFrame(); 272 setFrameDict(); 273 274 } 275 276 /** 277 * 显示某帧内容 278 * @param showBmp_mc 该帧上的动画 279 */ 280 private function setShow(showBmp_mc:BmpMovieClip):void 281 { 282 while (this.numChildren > 0) 283 { 284 this.removeChildAt(0); 285 } 286 setCurFrame(showBmp_mc); 287 } 288 289 /** 290 * 设置总帧数 291 */ 292 private function setTotalFrame():void 293 { 294 this.totalFrames = this.framesArr.length; 295 } 296 297 /** 298 * 设置每个对象对应的帧 299 */ 300 private function setFrameDict():void 301 { 302 var index:int = 0; 303 for (var i in this.framesObj) 304 { 305 index++; 306 this.framesDict[this.framesObj[i]] = index; 307 this.frameLabelsDict[this.framesObj[i]] = i; 308 } 309 310 } 311 312 public function remove():void 313 { 314 this.removeMySelf(); 315 } 316 317 } 318 319 }
一个使用实例:
1 var obj0:Object = { 2 transParent:true, 3 color:0x00ffffff, 4 startXY:{startX:20,startY:37}, //在原始图片中的那个位置开始切割 5 sizeDiff: { xDiff:106, yDiff:119 }, //xDiff:左右两张图的x坐标间隔,yDiff:上下两张图的y坐标间隔 6 sizePos: { w:80, h:60}, 7 control: { len:12, col:8, row:2 } 8 }; 9 var offBmp_mc:BmpMovieClip=new BmpMovieClip(obj0,{bmpdCs:Global.bmpdCsObj.offBmpdCS},Global.dplLayer,{autoPlay:true}); //动画流畅 Global.dplLayer 10 offBmp_mc.setPosOrCenter(50,50);
使用实例用到的图片(来源于网络):
可以到我的微盘下载完整的测试程序和图片素材!
地址: http://vdisk.weibo.com/s/jH3tR
I love program