BmpCacheMovieClip

package LibCore.ui.core
{
	import LibCore.utils.ClassUtils;
	import LibCore.utils.DisplayObjectUtils;
	import LibCore.utils.NumberUtils;
	
	import flash.display.Bitmap;
	import flash.display.FrameLabel;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	
	/**
	 * 采用位图缓存处理的影片剪辑
	 * <p>
	 * <li>对于内容复杂(尤其是使用了很多滤镜)但固定的影片剪辑,非常耗CPU,而Flash自带的位图缓存机制又无法加以优化,因此采用手动方式实现</li>
	 * <li>将原影片剪辑的每帧缓存为一张位图,并始终保存,实际使用时用位图代替原影片剪辑显示,且支持多个实例间共享</li>
	 * </p>
	 * @author	Fictiony
	 * @version	2017/3/21
	 */	
	public class BmpCacheMovieClip extends MovieClip
	{
		static private var _bmpCacheMap:Dictionary = new Dictionary();	//位图缓存表:{原影片剪辑类或实例: [帧缓存信息]}
		static private var _mcCacheMap:Dictionary = new Dictionary();	//影片剪辑实例缓存表:{原影片剪辑类: 影片剪辑实例}
		static private var _tempOffset:Point = new Point();				//临时偏移坐标记录
		
		private var _sourceClass:Class;				//原影片剪辑类(null表示构造时指定的是实例)
		private var _sourceMC:MovieClip;			//原影片剪辑实例
		private var _content:Bitmap;				//内容位图(用于显示每帧的缓存位图)
		private var _totalFrames:int = 0;			//总帧数
		private var _currentFrame:int = 0;			//当前帧序号
		private var _isPlaying:Boolean = false;		//是否正在播放
		private var _labels:Array;					//原影片剪辑的所有帧标签列表(不考虑场景)
		private var _labelMap:Dictionary;			//帧标签表:{帧标签: 帧序号}
		private var _originSize:Point;				//指定的原始大小
		
		/**
		 * 构造函数
		 * @param sourceMC			原影片剪辑类或实例
		 * @throws ArgumentError	若sourceMC不为影片剪辑类或实例,则抛出异常
		 */		
		public function BmpCacheMovieClip( sourceMC:Object )
		{
			super();
			
			if (sourceMC is MovieClip)
			{
				_sourceMC = sourceMC as MovieClip;
			}
			else if (sourceMC is Class && ClassUtils.extendsClass(sourceMC as Class, MovieClip))
			{
				_sourceClass = sourceMC as Class;
			}
			else
			{
				throw new ArgumentError("Parameter sourceMC should be a subclass or instance of MovieClip: " + sourceMC);
			}
			init();
		}

		/**
		 * 总帧数
		 */		
		override public function get totalFrames():int
		{
			return _totalFrames;
		}

		/**
		 * 当前帧序号
		 */		
		override public function get currentFrame():int
		{
			return _currentFrame;
		}

		/**
		 * 当前是否正在播放
		 */		
		override public function get isPlaying():Boolean
		{
			return _isPlaying;
		}
		
		/**
		 * 所有帧标签列表
		 */		
		override public function get currentLabels():Array
		{
			return _labels;
		}
		
		/**
		 * 指定的原始大小(null表示不指定)
		 */
		public function get originSize():Point
		{
			return _originSize ? _originSize.clone() : null;
		}
		public function set originSize( val:Point ):void
		{
			_originSize = val ? new Point(Math.max(1, val.x || 0), Math.max(1, val.y || 0)) : null;
		}
		
		/**
		 * 宽度
		 */
		override public function get width():Number
		{
			return _originSize ? _originSize.x * this.scaleX : super.width;
		}
		override public function set width( val:Number ):void
		{
			if (_originSize)
			{
				this.scaleX = (val || 0) / this.originSize.x;
			}
			else
			{
				super.width = val;
			}
		}

		/**
		 * 高度
		 */
		override public function get height():Number
		{
			return _originSize ? _originSize.y * this.scaleY : super.height;
		}
		override public function set height( val:Number ):void
		{
			if (_originSize)
			{
				this.scaleY = (val || 0) / this.originSize.y;
			}
			else
			{
				super.height = val;
			}
		}
		
		/**
		 * 初始化
		 */		
		private function init():void
		{
			if (_sourceClass)	//指定类
			{
				if (_sourceClass in _bmpCacheMap)
				{
					_sourceMC = _mcCacheMap[_sourceClass] as MovieClip;
				}
				else
				{
					_sourceMC = new _sourceClass();
					_bmpCacheMap[_sourceClass] = new Vector.<FrameCacheInfo>(_sourceMC.totalFrames, true);
					_mcCacheMap[_sourceClass] = _sourceMC;
				}
			}
			else	//指定实例
			{
				if (!(_sourceMC in _bmpCacheMap))
				{
					_bmpCacheMap[_sourceMC] = new Vector.<FrameCacheInfo>(_sourceMC.totalFrames, true);
				}
			}
			
			//初始化影片剪辑参数
			_totalFrames = _sourceMC.totalFrames;
			_labels = _sourceMC.currentLabels;
			if (_labels && _labels.length > 0)
			{
				_labelMap = new Dictionary();
				for each (var label:FrameLabel in _labels)
				{
					_labelMap[label.name] = label.frame;
				}
			}

			//创建内容,并显示第一帧
			_content = new Bitmap();
			_content.smoothing = true;
			addChild(_content);
			gotoFrame(1);
		}
		
		/**
		 * 开始播放
		 */		
		override public function play():void
		{
			if (_isPlaying || this.totalFrames < 2) return;
			addEventListener(Event.ENTER_FRAME, onFrame);
			_isPlaying = true;
		}
		
		/**
		 * 停止播放
		 */		
		override public function stop():void
		{
			if (!_isPlaying) return;
			removeEventListener(Event.ENTER_FRAME, onFrame);
			_isPlaying = false;
		}
		
		/**
		 * 跳转到指定帧并播放
		 * @param frame		帧序号或帧标签
		 */		
		override public function gotoAndPlay( frame:Object, scene:String=null ):void
		{
			gotoFrame(frame);
			play();
		}
		
		/**
		 * 跳转到指定帧并停止
		 * @param frame		帧序号或帧标签
		 */		
		override public function gotoAndStop( frame:Object, scene:String=null ):void
		{
			gotoFrame(frame);
			stop();
		}

		/**
		 * 跳转到上一帧并停止
		 */		
		override public function prevFrame():void
		{
			gotoFrame(this.currentFrame > 1 ? this.currentFrame - 1 : this.totalFrames);
			stop();
		}
		
		/**
		 * 跳转到下一帧并停止
		 */		
		override public function nextFrame():void
		{
			gotoFrame(this.currentFrame < this.totalFrames ? this.currentFrame + 1 : 1);
			stop();
		}
		
		/**
		 * 跳转到指定帧
		 * @param frame		帧序号或帧标签
		 */
		protected function gotoFrame( frame:* ):void
		{
			if (_labelMap && frame in _labelMap)
			{
				frame = _labelMap[frame];
			}
			frame = NumberUtils.limit(int(frame), 1, this.totalFrames);
			if (frame == _currentFrame) return;
			_currentFrame = frame;
			
			//若该帧缓存位图尚未创建,则先创建
			var cache:Vector.<FrameCacheInfo> = _bmpCacheMap[_sourceClass || _sourceMC];
			if (!cache) return;
			var info:FrameCacheInfo = cache[_currentFrame - 1];
			if (!info)
			{
				_sourceMC.gotoAndStop(_currentFrame);
				info = new FrameCacheInfo();
				info.bitmap = DisplayObjectUtils.drawToBitmap(_sourceMC, 0, _tempOffset);
				info.offsetX = _tempOffset.x;
				info.offsetY = _tempOffset.y;
				cache[_currentFrame - 1] = info;
			}

			//刷新内容
			_content.bitmapData = info.bitmap;
			_content.x = info.offsetX;
			_content.y = info.offsetY;
		}
		
		/**
		 * 每帧处理
		 */		
		private function onFrame( e:Event ):void
		{
			gotoFrame(this.currentFrame < this.totalFrames ? this.currentFrame + 1 : 1);
		}
		
		/**
		 * 清除位图缓存(清除后所有已存在的相关影片剪辑都将不再刷新内容,但新创建的不受影响)
		 * @param sourceMC	原影片剪辑类或实例
		 */
		public function clearBmpCache():void
		{
			BmpCacheMovieClip.clearBmpCache(_bmpCacheMap);
		}
		static public function clearBmpCache( sourceMC:Object ):void
		{
			var cache:Vector.<FrameCacheInfo> = _bmpCacheMap[sourceMC];
			if (cache)
			{
				for each (var info:FrameCacheInfo in cache)
				{
					info.bitmap.dispose();
				}
				delete _bmpCacheMap[sourceMC];
				delete _mcCacheMap[sourceMC];
			}
		}
	}
}

import flash.display.BitmapData;

/**
 * 帧缓存信息
 */
class FrameCacheInfo
{
	public var bitmap:BitmapData;	//该帧的缓存位图
	public var offsetX:int;			//偏移X坐标
	public var offsetY:int;			//偏移Y坐标
}

  

原文地址:https://www.cnblogs.com/dt1991/p/14841286.html