Flash网页游戏中实现的地图分块加载(卡马克地图)

package com.game.engine.map
{
	import com.game.GlobalConst;
	import com.game.engine.findpath.MapUtil;
	import com.game.load.SourceCache;
	import com.game.load.item.ImageLoader;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Shape;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	
	/**卡马克地图**/
	public class CamakeMap extends Shape{
		//路径
		private var _rootPath     	:String;
		//地图标识
		private var _mapID   		:int;
		//加载类型(1==>普通加载 、2==>分块加载)
		private var _loadType	 	:int;
		//可视化宽
		private var _visualWidth  	:int;
		//可视化高
		private var _visualHeight 	:int;
		//地图的宽
		private var _mapWidth     	:int;
		//地图的高
		private var _mapHeight    	:int;
		//分块宽
		private var _tileWidth    	:int;
		//分块高
		private var _tileHeight   	:int;
		//分块列数
		private var _cols         	:int;
		//分块行数
		private var _rows         	:int;
		//当前位图滚动X轴
		private   var  _bx          :int;
		//当前位图滚动Y轴
		private   var  _by          :int;
		//等于位图滚动位置(0,0)时,px值
		private   var  _tx          :int;
		//等于位图滚动位置(0,0)时,py值
		private   var  _ty          :int;
		//上一次移动到的x轴位置
		private   var  _fx          :int;
		//上一次移动到的y轴位置
		private   var  _fy          :int;
		//当前地图开始行
		private   var  _sRow        :int;
		//当前地图开始列
		private   var  _sCol        :int;
		//当前地图结束行
		private   var  _eRow        :int;
		//当前地图结束列
		private   var  _eCol        :int;
		//当前地图可视化行
		private   var  _vRow        :int;
		//当前地图可视化列
		private   var  _vCol        :int;
		//最小滚动宽
		private   var  _sMinWidth   :int;
		//最小滚动高
		private   var  _sMinHeight  :int;
		//最大滚动宽
		private   var  _sMaxWidth   :int;
		//最大滚动高
		private   var  _sMaxHeight  :int;
		//小地图
		private   var  _smallBmpd   :BitmapData;
		//默认位图
		private   var  _defaultBmpd :BitmapData;
		//地图资源管理器
		private   var  _sourceCach  :SourceCache;
		//位图存储字典
		private   var  _bmpdDic     :Dictionary;
		//位图加载队列
		private   var  _bmpdLoadDic :Dictionary;
		
		public  function CamakeMap(){
			this._bmpdDic     = new Dictionary();
                         //SoureCache 是一个加载管理器,因为代码比较多,暂时不公开,此处是创建一个场景地图加载的管理
                         //如需要使用此类,可以自行修改加载方式
			this._sourceCach  = SourceCache.createSourceCache(GlobalConst.SCENE_CACHE,1);
		}
		/**
		 * 初始化地图
		 * @param String rootPath      地图路径
		 * @param int    mapID         地图标识
		 * @param int    loadType      加载类型
		 * @param int    visualWidth   可视化宽
		 * @param int    visualHeight  可视化高
		 * @param int    mapWidth      地图高
		 * @param int    mapHeight     地图宽
		 * @param int    tileWidth     分块宽
		 * @param int    tileHeight    分块高
		 * **/
		public  function initMap(rootPath:String,mapID:int,loadType:int,visualWidth:int,visualHeight:int,
								 mapWidth:int,mapHeight:int,tileWidth:int =0 ,tileHeight:int =0):void{
			this.dispose();
			this._mapID           = mapID;
			this._rootPath        = rootPath;
			this._loadType        = loadType;
			this._mapWidth        = mapWidth;
			this._mapHeight       = mapHeight;
			this._tileWidth       = tileWidth;
			this._tileHeight      = tileHeight;	
			if(loadType == MapUtil.TYPE_LOAD_NOCUT){
				this.scrollRect    = new Rectangle(0,0,mapWidth,mapHeight);
				this._sMaxWidth    = mapWidth -  this._sMinWidth;
				this._sMaxHeight   = mapHeight - this._sMinHeight;
			}else if(loadType == MapUtil.TYPE_LOAD_CUT){
				//总tile行列大小	
				this._rows         = Math.ceil(mapHeight/tileHeight);
				this._cols         = Math.ceil(mapWidth/tileWidth);
				this._defaultBmpd  = new BitmapData(tileWidth,tileHeight,false,1);
			}
			this.resetMap(visualWidth,visualHeight);
			this.loadSmallMap();
		}
		//加载小地图
		private function loadSmallMap():void{
			 var item:ImageLoader = this._sourceCach.addSource("smallMap"+_mapID,_rootPath+"/"+_mapID+"/small.jpg") as ImageLoader;
			 item.addEventListener(Event.COMPLETE,loadSmallComplete,false,0,true);
			 this._sourceCach.start();
		}
		/**
		 * 重置当前网页窗口的可视化大小
		 * @param int    visualWidth   可视化宽
		 * @param int    visualHeight  可视化高
		 * **/
		public  function resetMap(visualWidth:int,visualHeight:int):void{
			if(this._visualWidth   != visualWidth ||
				this._visualHeight != visualHeight){ //宽高与前面不相同才进行重置
				this._visualWidth   = Math.min(visualWidth,_mapWidth);
				this._visualHeight  = Math.min(visualHeight,_mapHeight);
				if(_loadType == MapUtil.TYPE_LOAD_CUT){
					//可视部分tile大小
					this._sMinWidth     = this._visualWidth/2;
					this._sMinHeight    = this._visualHeight/2;
					var vRow:int        = Math.min(Math.ceil(this._visualHeight/this._tileHeight)+1,this._rows);
					var vCol:int        = Math.min(Math.ceil(this._visualWidth/this._tileWidth)+1,this._cols);
					
					if(this._vRow != vRow ||
						this._vCol != vCol){
						
						this._vRow        = vRow;
						this._vCol        = vCol;
						
						this.scrollRect   = new Rectangle(0,0,this._vCol*this._tileWidth,this._vRow*this._tileHeight); 
					}
					
					this._tx = -1;
					this._ty = -1;
					this._fx = -1;
					this._fy = -1;
				}
			}
		}
		/**获取当前地图相对顶点X轴(普通地图的真实顶点)**/
		public  function get px():int{
			return this._bx + this._tx;
		}
		/**获取当前地图相对顶点Y轴(普通地图的真实顶点)**/
		public  function get py():int{
			return this._by + this._ty;
		}
		/**获取可视区域的宽**/
		public  function get visualWidth():Number{
			return this._visualWidth;
		}
		/**获取可视区域的高**/
		public  function get visualHeight():Number{
			return this._visualHeight
		}
		/**
		 * 滚动位图
		 * @param Number fx 跟随者X轴坐标
		 * @param Number fy 跟随者Y轴坐标
		 * **/
		public  function onScroll(fx:Number,fy:Number):void{
			if(_fx != fx || _fy != fy){
				this.cacheAsBitmap = false;
				this._fx     = fx;
				this._fy     = fy;
				if(this._loadType == MapUtil.TYPE_LOAD_CUT){
				   this.updateTXY(fx,fy);
				   fx -= this._tx;
				   fy -= this._ty;
				}
				this.centerMap(fx,fy);
				this.checkLoad();
			}else{
				this.cacheAsBitmap = true;
			}
		}
		//更新tile的顶点位置
		private function updateTXY(x:Number,y:Number):void{
			this._sRow  = Math.floor((y - this._sMinHeight)/this._tileHeight);
			this._sCol  = Math.floor((x - this._sMinWidth)/this._tileWidth);
			
			if(this._sRow <= 0){   
			   this._sRow  = 0;
			}else if(this._sRow >= (this._rows - this._vRow)){
			   this._sRow        =  this._rows - this._vRow;
			}
			if(this._sCol <= 0){
			   this._sCol  = 0;
			}else if(this._sCol >= (this._cols -this. _vCol)){
			   this._sCol        =  this._cols - this._vCol;
			}
			
			this._eRow  = this._sRow  + this._vRow ;
			this._eCol  = this._sCol  + this._vCol;
			
			if(this._eRow >= this._rows){
			   this._sMaxHeight    = this._mapHeight-this._sRow*this._tileHeight-this._sMinHeight;
			}else{
			   this._sMaxHeight  = this._vRow*this._tileHeight-this._sMinHeight;
			}
			if(this._eCol  >= this._cols){
			   this._sMaxWidth  = this._mapWidth - this._sCol*this._tileWidth-this._sMinWidth;
			}else{
			   this._sMaxWidth  = this._vCol*this._tileWidth -this._sMinWidth;
			}
			
			var tx:int  = this._sCol*this._tileWidth;
			var ty:int  = this._sRow*this._tileHeight;
			
			if(tx != this._tx || this._ty != ty){
			   this._tx    = tx;
			   this._ty    = ty;
			   this.updateAllBmpd();
			}
		}
		//地图居中
		private function centerMap(fx:Number,fy:Number):void{
			var centerX:Number = 0;
			var centerY:Number = 0;
			
			if(fx <= this._sMinWidth){
				centerX  = 0;
			}else if(fx >= this._sMaxWidth){
				centerX =  this._sMaxWidth - this._sMinWidth;
			}else {
				centerX = fx - this._sMinWidth;
			}
			
			if(fy <= this._sMinHeight){
				centerY = 0;
			}else if(fy >= this._sMaxHeight){
				centerY =  this._sMaxHeight - this._sMinHeight;
			}else{
				centerY = fy - this._sMinHeight;
			}
			
			var rect:Rectangle = this.scrollRect;
			rect.x             = centerX;
			rect.y             = centerY;
			
			this.scrollRect    = rect;
			
			this._bx  = centerX;
			this._by  = centerY;
		}
		//检查加载地图,判断地图是否在可视范围内,是的话加入加载队列中
		private function checkLoad():void{
			var item:ImageLoader;
			if(this._loadType == MapUtil.TYPE_LOAD_NOCUT){
				if(this._bmpdLoadDic[this._mapID+"_0_0"] == undefined){
				   item = this._sourceCach.addSource(this._mapID+"_0_0",this._rootPath+"/"+this._mapID+"/big.jpg") as ImageLoader;
				   item.addEventListener(Event.COMPLETE,loadComplete);
				   this._bmpdDic[item.key]  = item;
				   this._bmpdLoadDic[this._mapID+"_0_0"] = true;
				}
			}else if(this._loadType == MapUtil.TYPE_LOAD_CUT){
				for(var i:int=this._sRow;i<this._eRow;i++){
					for(var j:int=_sCol;j<this._eCol;j++){ 
						if(this._bmpdLoadDic[this._mapID+"_"+i+"_"+j]  == undefined){
						   item = _sourceCach.addSource(this._mapID+"_"+i+"_"+j,this._rootPath+"/"+this._mapID+"/"+i+"_"+j+".jpg") as ImageLoader;
						   item.addEventListener(Event.COMPLETE,loadComplete);
                           this._bmpdLoadDic[item.key]  = item;
						   this._bmpdLoadDic[this._mapID+"_"+i+"_"+j] = true
						}
					}
				}
			}
			this._sourceCach.start();
		}
		//加载位图成功
		private function loadComplete(event:Event):void{
			var item:ImageLoader = event.target as ImageLoader
			if(item != null){
				if(this._bmpdDic[item.key] is BitmapData) {
				   this._bmpdDic[item.key].dispose();
				}
				var array:Array         = item.key.split("_");
				this._bmpdDic[item.key] = item.bmpd;
				this.updateBmpd(int(array[1]),int(array[2]));
				item.removeEventListener(Event.COMPLETE,loadComplete);
			}
		}
		//加载小地图成功
		private function loadSmallComplete(event:Event):void{
			var item:ImageLoader = event.target as ImageLoader;
			if(item != null){
				var bmpd   :BitmapData;
				var matrix :Matrix     = new Matrix();
				if(this._loadType == MapUtil.TYPE_LOAD_NOCUT){
					if(this._bmpdDic[this._mapID+"_0_0"] == null){
					  bmpd  = new BitmapData(this._mapWidth,_mapHeight,false);
					  matrix.scale(this._mapWidth/item.bmpd.width,this._mapHeight/item.bmpd.height);
					  bmpd.draw(item.bmpd,matrix,null,null,null,false);
					  this._bmpdDic[this._mapID+"_0_0"] =  bmpd;
					  updateBmpd(0,0);
					}
				}else if(_loadType == MapUtil.TYPE_LOAD_CUT){
					this._smallBmpd    = item.bmpd;
					this.updateAllBmpd();
				}
				item.removeEventListener(Event.COMPLETE,loadSmallComplete);
			}
		}
		//滚动到边缘时需要更新整张位图
		private function updateAllBmpd():void{
			this.graphics.clear();
			for(var i:int=this._sRow;i<=this._eRow;i++){
				for(var j:int=this._sCol;j<=this._eCol;j++){
					var point   :Point   = new Point((j-this._sCol)*this._tileWidth,(i-this._sRow)*this._tileHeight);
					var bmpd    :BitmapData;
					if(this._bmpdDic[this._mapID+"_"+i+"_"+j] is BitmapData){
					   bmpd =  this._bmpdDic[this._mapID+"_"+i+"_"+j];
					}else if(this._smallBmpd != null){
						var matrix :Matrix   = new Matrix();
						var stw  :int        = Math.round(this._smallBmpd.width/this._cols);
						var sth  :int        = Math.round(this._smallBmpd.height/this._rows);
						var sbmpd:BitmapData = new BitmapData(stw,sth);
						matrix.scale(this._tileWidth/stw,this._tileHeight/sth);
						sbmpd.copyPixels(this._smallBmpd,new Rectangle(j*stw,i*sth,stw,sth),new Point());
						bmpd  = new BitmapData(this._tileWidth,this._tileHeight,false);
						bmpd.draw(sbmpd,matrix,null,null,null,false);
						sbmpd.dispose();
						this._bmpdDic[this._mapID+"_"+i+"_"+j]  = bmpd;
					}else{
						bmpd  =   this._defaultBmpd;
					}
					this.graphics.beginBitmapFill(bmpd);
					this.graphics.drawRect(point.x,point.y,bmpd.width,bmpd.height);
				}   
			}
			this.graphics.endFill();
		}
		//更新缓冲位图
		private function updateBmpd(row:int,col:int):void{
			var bmpd:BitmapData;
			if(this._loadType == MapUtil.TYPE_LOAD_NOCUT){
				bmpd     =  this._bmpdDic[_mapID+"_0_0"];
				this.graphics.beginBitmapFill(bmpd);
				this.graphics.drawRect(0,0,bmpd.width,bmpd.height);
			}else if(this._loadType == MapUtil.TYPE_LOAD_CUT){
				bmpd    = this._bmpdDic[this._mapID+"_"+row+"_"+col];
				this.graphics.beginBitmapFill(bmpd);
				this.graphics.drawRect((col-this._sCol)*this._tileWidth,(row-this._sRow)*this._tileHeight,bmpd.width,bmpd.height);
			}
			this.graphics.endFill();
		}
		/**销毁  一般会在切换场景时需要执行此方法,用于清除上一张地图的位图缓存, 回收内存**/
		public  function dispose():void{
                        //执行removeAllSource()将会删除当前加载管理中所有资源,并清除当前加载队列
			this._sourceCach.removeAllSource();
			for each(var temp:Object in _bmpdDic){
				if(temp is ImageLoader)     temp.removeEventListener(Event.COMPLETE,loadComplete);
				else if(temp is BitmapData) temp.dispose();
			}
			if(this._defaultBmpd!= null){this._defaultBmpd.dispose();this._defaultBmpd = null;}
			if(this._smallBmpd   != null ){this._smallBmpd.dispose();this._smallBmpd = null;}
			this._bmpdDic     = new Dictionary();
			this._bmpdLoadDic = new Dictionary();
			this._tx = -1;
			this._ty = -1;
			this._fx = -1;
			this._fy = -1;
		}
	}
}

你可能感兴趣的:(Flash网页游戏中实现的地图分块加载(卡马克地图))