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; } } }