COC建筑拖动的实现

最近在玩COC,多体验一下手游的体验,因为自己毕竟一直是做页游的,有些观念需要转变一下。

好像偏了,玩了几次之后突然想起COC那个地图拖动的自己之前实现过,那是2010年左右的时候,模拟经营类页游大行其道的时候,我做了个类似的功能。

核心内容应该是通过直线方程确定建筑的位置,想想那时候的自己还是干劲十足的,哪像现在,犹豫踟蹰,徘徊不前,对未来充满迷茫。

特从旧电脑上把相关的几个类拷下来,公布于此,虽然今时今日去看,粗糙得很,有很多需要改进的地方,但是还是觉得有一些学习的意义的。

为了填满全页,主要的类不折叠了,如下:

package com.app.map.smallMap
{
    import com.app.facilities.model.FacilityModel;
    import com.app.facilities.model.vo.FacilityVO;
    import com.core.ServiceID;
    import com.core.manage.MainManager;
    import com.core.manage.MaterialUIManager;
    import com.core.manage.UIManager;
    import com.core.ui.loader.MaterialLoader;
    import com.core.utils.Tool;

    import flash.display.DisplayObject;
    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.GlowFilter;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    import org.ds.HashMap;
    import org.manager.RootManager;

    /**
     *
     * 用来摆放建筑和设施的小地图</BR>
     * 为方便管理,请勿直接new构造器,请使用<code>getMap(key:String):SmallMap</code>方法取实例
     * @author Ado
     *
     */
    public class SmallMap extends Sprite
    {
        /**
         * 安置事件类型
         */
        public static const SETTLE_EVENT:String = "settle_event";
        /**
         * 皮肤加载完成
         */
        public static const SKIN_LOADED:String = "skin_loaded";

        private var mc:MovieClip;
        private var _row:int = 1;
        private var _column:int = 1;

        private static var maps:HashMap = new HashMap();

        private var _building:BuildingTile;//拖动的建筑
        public var tempSkin:Skin;//拖动建筑的皮肤
        private var tempSkinIsShowed:Boolean;//临时皮肤是否已经显示
        private var loadedOver:Boolean;
        private var _mapData:Object;
        private var _buidlingData:Array = [];
        /**
         * 是否支持连续建筑
         */
        public var isMultiSettlable:Boolean;
        //已安放的建筑列表信息
        private var _settledBuildings:Array = [];
        //已安放的建筑信息
        private var settledBuilding:Object;
        /**
         *是否是在进行固有建筑移除操作
         */
        public var isRemove:Boolean;
        /**
         *建筑安放的回调函数
         */
        public var callBack:Function;
        /**
         * 拖动参照物
         */
        public var moveRefer:Sprite;

        //本地图上的皮肤数据
        public var skins:Array = [];
        private var skinLoader:MaterialLoader;
        private var needSkins:Array = [];//皮肤加载队列

        private var _availiableSize:Array;//可以放置的尺寸
        private var _derectorAvailiable:Boolean;//是否可以安置设施
        /**
         * 摆放建筑的小地图
         *
         */
        public function SmallMap()
        {
            mc = UIManager.getMovieClip("small_map");
            mc.name="_smallMap";
            skinLoader = new MaterialLoader();
            this.addChild(mc);
        }
        /**
         * 根据传入的key值取得或者新建小地图
         * @param key key值通常是面板的完整路径名
         * @return
         *
         */
        public static function getMap(key:String):SmallMap
        {
            if(maps.containsKey(key))
            {
                return maps.getValue(key);
            }else
            {
                var map:SmallMap = new SmallMap();
                maps.add(key, map);
                return map;
            }
        }
        /**
         *
         * @param _mapData            地图数据
         * @param buildingTile        建筑底座
         * @param _callBack            回调函数
         * @param isMultiSettlable    是否可以重复放置
         *
         */
        public function initMap(_mapData:Object, buildingTile:BuildingTile = null, _callBack:Function=null, isMultiSettlable:Boolean=false):void
        {
            mapData = _mapData;
            this.isMultiSettlable = isMultiSettlable;
            if(buildingTile!=null)
            {
                building = buildingTile;
            }
            callBack = _callBack;
        }
        /**
         * 在小地图上拖动的事件监听器
         * @param e
         *
         */
        private function startMoveHandler(e:MouseEvent = null):void
        {
            if(e!=null)
            {
                e.stopImmediatePropagation();
            }
            _building.removeEventListener(MouseEvent.CLICK, startMoveHandler);
            moveRefer.addEventListener(MouseEvent.ROLL_OVER, bgOverHandler);

            moveRefer.dispatchEvent(new MouseEvent(MouseEvent.ROLL_OVER));
        }
        /**
         * 背景滑过事件监听:当前建筑的事件监听,开始移动
         * @param e
         *
         */
        private function bgOverHandler(e:MouseEvent):void
        {
            moveRefer.addEventListener(MouseEvent.ROLL_OUT, bgOutHandler);
            moveRefer.removeEventListener(MouseEvent.ROLL_OVER, bgOverHandler);

            tempSkin.startDrag(true, new Rectangle(moveRefer.x-x,
                moveRefer.y - y,
                moveRefer.width - _building.width,
                moveRefer.height - _building.height/2));
            RootManager.stage.addEventListener(MouseEvent.MOUSE_MOVE, checkHandler);
            moveRefer.addEventListener(MouseEvent.CLICK, positionHandler);
        }
        /**
         * 背景滑出事件监听:移除当前建筑的所有事件,且停止移动
         * @param e
         *
         */
        private function bgOutHandler(e:MouseEvent):void
        {
            moveRefer.removeEventListener(MouseEvent.ROLL_OUT, bgOutHandler);
            moveRefer.addEventListener(MouseEvent.ROLL_OVER, bgOverHandler);

            if(_building)
            {
                _building.stopDrag();
                _building.x=mc["bg"].width;
                _building.y=mc["bg"].height;
                tempSkin.x=mc["bg"].width;
                tempSkin.y=mc["bg"].height;
            }
            RootManager.stage.removeEventListener(MouseEvent.MOUSE_MOVE, checkHandler);
            _building.settlable = false;
            moveRefer.stage.removeEventListener(MouseEvent.CLICK, positionHandler);
        }

        /**
         * 根据是否可以放置建筑而更换底座颜色<br>
         * 所有的小块坐标都是以下两个系列的线条的交点<br>
         * <li>0.5 * x + y - 87.5 = k1 * 25;</li>
         * <li>0.5 * x - y + 87.5 = k2 * 25;</li><br/>
         * 由于长宽变化公式已变化
         * k1,k2均为整数,四舍五入取值
         * k1 取值范围: 0 ~  (建筑行 - 1)
         * k2 取值范围: 0 ~  (建筑列 - 1)
         * 以下以2*2的建筑为例 取值范围0 ~ (7-2)
         * 7为小地图横竖的单元格个数
         * **/
        private function checkHandler(e:MouseEvent):void
        {
            var refX:int = 7 - building.col;
            var refY:int = 7 - building.row;
            var ny:Number = Math.round((tempSkin.x * 5 / 9 + tempSkin.y - 70) / 20);
            var nx:Number = Math.round((tempSkin.x * 5 / 9 - tempSkin.y + 70) / 20);

            if(nx < 0 || nx > refX || ny < 0 || ny > refY)
            {
                _building.settlable = false;
                _building.visible = false;
            }else if(!checkSettlable(nx+1,ny+1,_building))
            {
                _building.settlable = false;
                _building.visible = true;
                tempSkin.alpha = 0.7;
            }else
            {
                _building.settlable = true;
                _building.visible = true;
                tempSkin.alpha = 0.7;
            }
            //设置位置
            _building.x = (ny + nx) * 18;
            _building.y = 10 * (ny - nx  + 7);

            //只有建筑才需要
            if(_building.row > 1)
            {
                _building.settleFactor = checkPoints(nx+1,ny+1);
            }
        }
        /**
         * 检测建筑的每个点
         * @param checkCol
         * @param checkRow
         *
         */
        private function checkPoints(checkCol:int, checkRow:int):Array
        {
            var a:Array = [];
            for(var i:int = 0; i < _building.row; i++)
            {
                for(var j:int = 0; j < _building.col; j++)
                {
                    if(checkCol + j <= 0 || checkCol + j > 7 || checkRow + i <= 0 || checkRow + i > 7 || !pointCheck(checkRow+i,checkCol+j))
                    {
                        a.push(i+"_"+j);
                    }
                }
            }
            return a;
        }
        /**
         * 检测某点是否可以安置,你妹的,我要崩溃了
         * @param checkCol
         * @param checkRow
         * @param point
         * @return
         *
         */
        private function pointCheck(checkRow:int, checkCol:int):Boolean
        {
            var result:Boolean = true;
            var referCheck:Array = _buidlingData.concat(_settledBuildings);
            if(referCheck.length)
            {
                for each(var i:BuildingTile in referCheck)
                {
                    if(i.row == 1)
                    {
                        if(i.buildingData.unit_col0 == checkCol && i.buildingData.unit_row0 == checkRow)
                        {
                            result = false;
                            break;
                        }
                    }else
                    {
                        if(i.buildingData.unit_col1+1 > checkCol && checkCol >= i.buildingData.unit_col0 - 1 &&
                            i.buildingData.unit_row1+1 > checkRow && checkRow >= i.buildingData.unit_row0 - 1)
                        {
                            result = false;
                            break;
                        }
                    }
                }
            }else
            {
                result = true;
            }
            return result;
        }
        /**
         * 检测是否可以安放
         * @param checkCol     接受检测的行
         * @param checkRow     接受检测的列
         * @param bld         接受检测的BuildingTile
         * @return
         *
         */
        private function checkSettlable(checkCol:int, checkRow:int, bld:BuildingTile):Boolean
        {
            var result:Boolean = true;
            var referCheck:Array = _buidlingData.concat(_settledBuildings);
            if(referCheck.length)
            {
                for each(var i:BuildingTile in referCheck)
                {
                    if(bld.buildingData.referCol == 1)//设施摆放
                    {
                        if(!(i.buildingData.unit_col1 <= checkCol || i.buildingData.unit_row1 <= checkRow ||
                            i.buildingData.unit_col0 >= checkCol+bld.buildingData.referCol ||
                            i.buildingData.unit_row0 >= checkRow+bld.buildingData.referRow))
                        {
                            result = false;
                            break;
                        }
                    }else
                    {
                        if(i.row == 1)
                        {
                            if(!(i.buildingData.unit_col1 <= checkCol || i.buildingData.unit_row1 <= checkRow ||
                                i.buildingData.unit_col0 >= checkCol+bld.buildingData.referCol ||
                                i.buildingData.unit_row0 >= checkRow+bld.buildingData.referRow))
                            {
                                result = false;
                                break;
                            }
                        }else
                        {
                            if(!(i.buildingData.unit_col1+1 <= checkCol || i.buildingData.unit_row1+1 <= checkRow ||
                                i.buildingData.unit_col0 >= checkCol+bld.buildingData.referCol+1 ||
                                i.buildingData.unit_row0 >= checkRow+bld.buildingData.referRow+1))
                            {
                                result = false;
                                break;
                            }
                        }
                    }
                }
            }else
            {
                result = true;
            }
            return result;
        }
        /**
         * 安放建筑或者设施
         * @param e
         *
         */
        private function positionHandler(e:MouseEvent):void
        {
//            e.stopImmediatePropagation();
            if(_building.settlable)
            {
                var ny:Number = Math.round((building.x * 5 / 9 + building.y - 70) / 20);
                var nx:Number = Math.round((building.x * 5 / 9 - building.y + 70) / 20);

                var tempX:Number = (ny + nx) * 18;
                var tempY:Number = 10 * (ny - nx  + 7);
                tempSkin.stopDrag();
                moveRefer.removeEventListener(MouseEvent.CLICK, positionHandler);
                RootManager.stage.removeEventListener(MouseEvent.MOUSE_MOVE, checkHandler);
                moveRefer.removeEventListener(MouseEvent.ROLL_OVER, bgOverHandler);
                moveRefer.removeEventListener(MouseEvent.ROLL_OUT, bgOutHandler);
                _building.y = tempY;
                _building.x = tempX;
//                _building.alpha = 0.2;    

                building.buildingData.unit_col0 = nx + 1;
                building.buildingData.unit_row0 = ny + 1;
                building.buildingData.unit_col1 = building.buildingData.unit_col0 + building.col;
                building.buildingData.unit_row1 = building.buildingData.unit_row0 + building.row;

                //安置皮肤数据
                tempSkin.alpha = 1;
                tempSkin.x = tempX;
                tempSkin.y = tempY;
                tempSkin.depth = _building.n;

                editModel = true;

                if(isMultiSettlable)
                {
                    _settledBuildings.push(building);
                    tempSkin.addEventListener(MouseEvent.ROLL_OVER, skinOverHandler);
                    this._building = null;
                }else if(callBack != null)
                {
                    callBack();
                }
                //更新皮肤,重新排列皮肤
                skins.push(tempSkin);
                skins.sortOn("depth");

                for(var i:int = 0; i < skins.length; i++)
                {
                    mc.addChild(skins[i]);
                }
                this.dispatchEvent(new Event(SETTLE_EVENT));
            }else
            {
                tempSkin.startDrag(true, new Rectangle(moveRefer.x-x,
                    moveRefer.y - y,
                    moveRefer.width - _building.width,
                    moveRefer.height - _building.height/2));
            }
        }
        /**
         * 皮肤鼠标滑过事件处理
         * @param e
         *
         */
        private function skinOverHandler(e:MouseEvent):void
        {
            e.target.filters = [new GlowFilter(0xff0000,0.8)];
            e.target.addEventListener(MouseEvent.ROLL_OUT, skinOutHandler);
            e.target.removeEventListener(MouseEvent.ROLL_OVER, skinOverHandler);
        }
        /**
         * 皮肤鼠标滑出事件处理
         * @param e
         *
         */
        private function skinOutHandler(e:MouseEvent):void
        {
            e.target.filters = [];
            e.target.removeEventListener(MouseEvent.ROLL_OUT, skinOutHandler);
            e.target.addEventListener(MouseEvent.ROLL_OVER, skinOverHandler);
        }

        //取得皮肤:队列形式
        private function getSkins():void
        {
            if(needSkins.length)
            {
                skinLoader.getSwf(needSkins[0],needSkins[0]);
                needSkins.shift();
                if(skinLoader)
                {
                    skinLoader.setCompleteFunc = function(e:Event):void
                    {
                        getSkins();
                    }
                }
            }else
            {
                loadedOver = true;
                skinLoader.setCompleteFunc = null;
                displaySkins();
            }
        }
        /**
         * 显示皮肤数据
         */
        private function displaySkins():void
        {
            for each(var i:BuildingTile in _buidlingData)
            {
                var skin:Skin;//此处要实现对缓存数据的重用
                if(i.iconSource)
                {
                    skin = new Skin(i.iconSource);
                    skin.depth = i.depth;
                    skin.firstSort = i.buildingData.firstSort;
                    skin.id = i.buildingData.id;
                    skin.x = i.x;
                    skin.y = i.y;
                    skins.push(skin);
                    i.visible = false;
                }
            }
            skins.sortOn(["firstSort", "depth"], Array.NUMERIC);
            if(_building && tempSkin && !tempSkinIsShowed)
            {
                tempSkin.srcUrl = _building.iconSource;
                tempSkinIsShowed = true;
            }

            for each(var j:Skin in skins)
            {
                mc.addChild(j);
                j.visible = true;
            }
            dispatchEvent(new Event(SKIN_LOADED));
        }
        /**
         * 根据皮肤取建筑块 ,由于临时建筑无id
         * @param s Skin
         * @return
         *
         */
        public function getTileBySkin(s:Skin):BuildingTile
        {
            var tile:BuildingTile;
            for each(var i:BuildingTile in _settledBuildings)
            {
                if(i.x == s.x && i.y == s.y)
                {
                    tile = i;
                    break;
                }
            }
            return tile;
        }
        /**
         * 移除设施
         * @param buildingData
         *
         */
        public function removeBuildingTile(buildingData:Object):void
        {
            for each(var i:BuildingTile in _settledBuildings)
            {
                if(i.buildingData.unit_col0 == buildingData.unit_col0 && i.buildingData.unit_row0 == buildingData.unit_row0)
                {
                    mc.removeChild(i);
                    _settledBuildings.splice(_settledBuildings.indexOf(i),1);
                    for each(var j:Skin in skins)
                    {
                        if(j.x == i.x && j.y == i.y)
                        {
                            mc.removeChild(j);
                            i.graphics.clear();
                            j.removeEventListener(MouseEvent.ROLL_OUT, skinOutHandler);
                            j.removeEventListener(MouseEvent.ROLL_OVER, skinOverHandler);
                            skins.splice(skins.indexOf(j),1);
                            break;
                        }
                    }
                    i.graphics.clear();
                    this.dispatchEvent(new Event(SETTLE_EVENT));
                    return;
                }
            }
        }
        /**
         * 计算可容纳的尺寸
         *
         */
        private function cauculateMaxSize():void
        {
            var reference:Array = [
                "2*2","2*3","3*2","3*3",
                "3*4","4*3","3*5","5*3",
                "4*4","4*5","5*4","4*6",
                "4*7","7*4","5*7","7*5",
                "6*4","5*5","5*6","6*5",
                "6*6","6*7","7*6","7*7",];
            _availiableSize = [];

            if(_buidlingData.length==0)
            {
                _availiableSize = reference;
                _derectorAvailiable = true;
                return;
            }

            var referTile:BuildingTile = new BuildingTile(null,true);
            for(var i:int=0; i < reference.length; i++)
            {
                var temp:Array = reference[i].split("*");
                referTile.buildingData = {referRow:int(temp[0]), referCol:int(temp[1]), type:1, layer:1};
                var limit:int = (7 - referTile.buildingData.referRow) * 7 + (7 - referTile.buildingData.referCol) + 1;
                for(var n1:int =1; n1 <= limit; n1++)
                {
                    var referC:int = (n1%7 == 0 ? 7 : n1%7);
                    var referR:int = Math.ceil(n1/7);
                    if(referC + referTile.col <= 8 && referR + referTile.row <= 8 && checkSettlable(referC,referR,referTile))
                    {
                        _availiableSize.push(reference[i]);
                        break;
                    }
                }
            }

            var num:int = 0;
            for each(var j:BuildingTile in _buidlingData)
            {
                num += j.row * j.col;
            }
            if(num >= 49)
            {
                _derectorAvailiable = false;
            }else
            {
                _derectorAvailiable = true;
            }
        }
        /**
         * 根据id取建筑块
         * @param id
         * @return
         *
         */
        public function getTileByDepth(d:int):BuildingTile
        {
            var tile:BuildingTile;
            for each(var i:BuildingTile in _buidlingData)
            {
                if(i.depth == d)
                {
                    tile = i;
                    break;
                }
            }
            return tile;
        }
        /**
         * 根据id取皮肤
         * @param s
         *
         */
        public function getSkinByDepth(d:int):Skin
        {
            var s:Skin;
            for each(var i:Skin in skins)
            {
                if(i.depth == d)
                {
                    s = i;
                    break;
                }
            }
            return s;
        }
        /**
         * 显示指定类型的皮肤
         * @param type
         *
         */
        public function showSpecifiedSkin(type:int):void
        {
            for each(var i:BuildingTile in _buidlingData)
            {
                if(i.buildingData is FacilityVO)
                {
                    if(i.buildingData.type == type)
                    {
                        getSkinByDepth(i.depth).visible = true;
                        getTileByDepth(i.depth).visible = false;
                    }else
                    {
                        getSkinByDepth(i.depth).visible = false;
                        getTileByDepth(i.depth).visible = true;
                        getTileByDepth(i.depth).alpha = 0.2;
                    }
                }
            }
        }
        /**
         * 更新需要安置的建筑的数据
         * @param data
         *
         */
        public function updateBuildingData(data:Object):void
        {
            var needSkinUpdated:Boolean = false;
            editModel = false;

            if(_building.buildingData.referRow > 1)
            {
                needSkinUpdated = data.layer != _building.buildingData.layer || data.referRow != _building.buildingData.referRow || data.referCol != _building.buildingData.referCol;
            }

            if(_building.buildingData.type != data.type || needSkinUpdated)
            {
                _building.buildingData = data;
                if(tempSkin && _building.iconSource != tempSkin.srcUrl)
                {
                    if(MaterialUIManager.contains(_building.iconSource))
                    {
                        tempSkin.srcUrl = _building.iconSource;
                    }else
                    {
                        skinLoader.getSwf(_building.iconSource,_building.iconSource);
                        skinLoader.setCompleteFunc = loadComplete;
//                            function(e:Event):void
//                        {
//                            tempSkin.srcUrl = _building.iconSource;
//                        }
                    }
                }
            }
            if(skins.indexOf(tempSkin) >= 0)
            {
                skins.splice(tempSkin);
            }
            startMoveHandler();
//            tempSkin.alpha = 0.7;
//            _building.alpha = 1;
        }
        /**
         * 取得当前地图可安放的最大尺寸
         * @return
         *
         */
        public function get availiableSize():Array
        {
            return _availiableSize;
        }
        /**
         * 设置地图上店铺皮肤显示与否
         * @param flag
         *
         */
        public function setShopSkinVisible(flag:Boolean):void
        {
            for each(var i:BuildingTile in _buidlingData)
            {
                if(i.row > 1)
                {
                    getSkinByDepth(i.depth).visible = flag;
                    i.visible = !flag;
                    i.alpha = 0.7;
                }
            }
        }
        /**
         * 设置地图上所有皮肤的可显示与否
         * @param vis
         *
         */
        public function setSkinVisible(vis:Boolean,_id:int=0):void
        {
            for each(var i:BuildingTile in _buidlingData)
            {
                if(i.buildingData.id!=_id || i.buildingData is FacilityVO)
                {
                    getSkinByDepth(i.depth).visible = vis;
                    i.visible = !vis;
                    i.alpha = 0.7;
                }

            }
        }
        /**
         * 清空地图上的信息
         * 循环方法待修改,修改依据:旧数据的重用
         */
        public function cleanMap():void
        {
            //清理皮肤数据
            for each(var j:Skin in skins)
            {
                if(mc.contains(j))
                {
                    j.recycle();
                    mc.removeChild(j);
                }
                j.removeEventListener(MouseEvent.ROLL_OUT, skinOutHandler);
                j.removeEventListener(MouseEvent.ROLL_OVER, skinOverHandler);
            }
            skins = [];

            //清理已有店铺设施
            for each(var i:BuildingTile in _buidlingData)
            {
                i.recycle();
                if(mc.contains(i))
                {
                    mc.removeChild(i);
                }
            }
            _buidlingData = [];
            //清理展示摆放的店铺设施
            for each(i in _settledBuildings)
            {
                if(mc.contains(i))
                {
                    mc.removeChild(i);
                }
            }
            _settledBuildings = [];

            //清理临时建筑
            if(_building != null && mc.contains(_building))
            {
                if(mc.contains(_building))    mc.removeChild(_building);
                if(mc.contains(tempSkin))
                {
                    mc.removeChild(tempSkin);
                    tempSkin.recycle();
                }
                tempSkin.stopDrag();
                _building = null;
                tempSkin = null;
            }
            RootManager.stage.removeEventListener(MouseEvent.MOUSE_MOVE, checkHandler);

            if(moveRefer)
            {
                moveRefer.removeEventListener(MouseEvent.CLICK, positionHandler);
                moveRefer.removeEventListener(MouseEvent.ROLL_OUT, bgOutHandler);
                moveRefer.removeEventListener(MouseEvent.ROLL_OVER, bgOverHandler);
            }
        }
        /**
         * 将待建设施转换成已建设施
         * */
        public function doTransform(id:int):void
        {
            for each(var i:BuildingTile in settledBuildings)
            {
                if(i.buildingData.id == id)
                {
                    settledBuildings.splice(settledBuildings.indexOf(i),1);
                    buidlingData.push(i);
                }
            }
        }
        /**
         * 获取建筑花费
         * @return
         */
        public function getCost():Number
        {
            var cost:Number = 0;
            for each(var i:BuildingTile in settledBuildings)
            {
                cost += int(i.buildingData.price);
            }
            return cost;
        }
        /**
         * 获取设施加成
         * @return
         *
         */
        public function getBouns():Number
        {
            var bouns:Number = 0;
            for each(var i:BuildingTile in settledBuildings)
            {
                bouns += int(i.buildingData.value);
            }
            return bouns;
        }
        /**
         * @param child 外部向小地图上添加子显示对象
         * @param child
         */
        public function addChildToMap(child:DisplayObject):void
        {
            mc.addChild(child);
            child.x = mc.mouseX;
            child.y = mc.mouseY;
        }
        /**
         * 从小地图上移除子显示对象
         * @param child
         */
        public function removeChildFromMap(child:DisplayObject):void
        {
            if(mc.contains(child))
            {
                mc.removeChild(child);
                if(child is Skin && skins.indexOf(child) > -1)
                {
                    skins.splice(skins.indexOf(child),1);
                }else if(child is BuildingTile && _buidlingData.indexOf(child) > -1)
                {
                    _buidlingData.splice(_buidlingData.indexOf(child),1);
                }
            }
        }
        /**
         * 地图固有的建筑信息
         * */
        public function set buidlingData(value:Array):void
        {
            cleanMap();
            _buidlingData = value;

            for each(var i:BuildingTile in value)
            {
                i.x = (i.buildingData.unit_col0 + i.buildingData.unit_row0 - 2) * BuildingTile.unitWidth / 2;
                i.y = (i.buildingData.unit_row0 - i.buildingData.unit_col0 + 7 ) * BuildingTile.unitHeight / 2;
                mc.addChild(i);
                i.visible = false;
                i.settlable = true;
                if(i.iconSource && needSkins.indexOf(i.iconSource) == -1 && !MaterialUIManager.contains(i.iconSource))
                {
                    needSkins.push(i.iconSource);
                }
            }

            cauculateMaxSize();

            if(needSkins.length)
            {
                getSkins();
            }else
            {
                displaySkins();
                loadedOver = true;
            }
        }
        /**
         * 地图建筑数据
         * */
        public function get buidlingData():Array
        {
            return _buidlingData;
        }

        /**
         * 地图上安置的建筑或者设施
         * @return
         *
         */
        public function get settledBuildings():Array
        {
            return _settledBuildings;
        }
        /**
         *
         * @param value 建筑数据,待建造的建筑,其中必须包含建筑素材地址和建筑尺寸例如(2*2,1*1)
         *
         */
        public function set building(value:BuildingTile):void
        {
            if(value)
            {
                editModel = false;
                _building = value;
                _row = value.buildingData.row;
                _column = value.buildingData.col;

                _building.x = mc["bg"].x + (mc["bg"].width - _building.width);
                _building.y = mc["bg"].y + (mc["bg"].height - _building.height);
                mc.addChild(building);
                tempSkin = new Skin();

                if(MaterialUIManager.contains(_building.iconSource))
                {
                    tempSkin.srcUrl = _building.iconSource;
                }else
                {
                    if(!loadedOver && needSkins.indexOf(_building.iconSource) == -1)
                    {
                        needSkins.push(_building.iconSource);
                        tempSkinIsShowed = false;
                    }else
                    {
                        skinLoader.getSwf(_building.iconSource,_building.iconSource);
                        skinLoader.setCompleteFunc = loadComplete;
                    }
                }
                mc.addChild(tempSkin);
                startMoveHandler();
                tempSkin.x = _building.x;
                tempSkin.y = _building.y;
            }else
            {
                editModel = true;
                if(_building != null && mc.contains(_building))
                {
                    mc.removeChild(_building);
                    _building.stopDrag();
                    _building.removeEventListener(MouseEvent.CLICK, startMoveHandler);
                    moveRefer.removeEventListener(MouseEvent.ROLL_OUT, bgOutHandler);
                    moveRefer.removeEventListener(MouseEvent.ROLL_OVER, bgOverHandler);
                }

                if(tempSkin && mc.contains(tempSkin))
                {
                    mc.removeChild(tempSkin);
                }
                RootManager.stage.removeEventListener(MouseEvent.MOUSE_MOVE, checkHandler);
                moveRefer.removeEventListener(MouseEvent.CLICK, positionHandler);
                _building = null;
            }
        }
        private function loadComplete(e:Event):void
        {
            try
            {
                tempSkin.srcUrl = _building.iconSource;
            }catch(e:Error)
            {
                trace("加载出错");
            }finally
            {

            }
        }
        /**
         * 设置是否是编辑模式 :
         * true 编辑模式下地图接收鼠标事件
         * false 非编辑模式下不接收鼠标事件
         * @param value
         *
         */
        public function set editModel(value:Boolean):void
        {
            this.mouseEnabled = value;
            this.mouseChildren = value;
        }
        /**
         * 选中的建筑
         * @return
         *
         */
        public function get building():BuildingTile
        {
            return _building;
        }
        /**
         * 地图数据
         * @return
         *
         */
        public function get mapData():Object
        {
            return _mapData;
        }
        /**
         *
         * @param value 地图数据,包括地图上已经建造好了的建筑数据
         *
         */
        public function set mapData(value:Object):void
        {
            _mapData = value;
        }

        public function get derectorAvailiable():Boolean
        {
            return _derectorAvailiable;
        }

    }
}

其他几个相关的类:

package com.app.map.smallMap
{
    import com.app.facilities.controller.FacilityController;
    import com.app.facilities.model.pool.FacilityPool;
    import com.app.facilities.model.vo.FacilityVO;
    import com.app.shop.model.vo.ShopVO;
    import com.core.info.DoMainInfo;

    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Matrix;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.text.TextFormatAlign;

    import org.ds.HashMap;

    /**
     * 在小地图上摆放的菱形小方块
     * @author Ado
     *
     */
    public class BuildingTile extends Sprite
    {
        /**
         * 建筑皮肤所存位置前缀
         */
        public static const BUILD_URL:String = "swf/build/";
        /**
         * 设施皮肤所存位置前缀
         */
        public static const FACIL_URL:String = "swf/decorator/";
        /**
         * 店铺皮肤所存位置前缀
         */
        public static const SHOP_URL:String = "swf/shop/";
        /**
         * 是否是模拟的:<br/>
         * 是模拟的的话不用进行绘制<br/>
         * 是真实的的话要进行绘制
         */
        private var isSimulate:Boolean = false;;
        public static const unitWidth:Number = 36;//单位长度
        public static const unitHeight:Number = 20;//单位高度

        private var _settlable:Boolean;
        private var _buildingData:Object;
        public var row:int;
        public var col:int;

        private var _n:int = 1;

        public var iconSource:String;

        private var tiles:HashMap = new HashMap();
        /**
         *
         * @param data 建筑数据
         * @param isSimulate 是否是模拟的建筑
         *
         */
        public function BuildingTile(data:Object=null,_isSimulate:Boolean=false)
        {
            isSimulate = _isSimulate;
            buttonMode = true;
            if(data == null) return;
            buildingData = data;
        }

        private function initTiles():void
        {
            graphics.clear();
            var t:int = col > 1 ? 2 : 1;

            tiles.eachKey(function(s:String):void{
                trace(s);
                removeChild(tiles.getValue(s));
                tiles.remove(s);
            });
            for(var i:int = 0; i < row; i++)
            {
                for(var j:int = 0; j < col; j++)
                {
                    var tile:Unit;
                    if(tiles.containsKey(i+"_"+j))
                    {
                        tile = tiles.getValue(i+"_"+j);
                    }else
                    {
                        tile = new Unit(t);
                    }
                    tile.x = (j + i) * unitWidth /2;
                    tile.y = (i - j) * unitHeight/2;
                    tile.setteld = buildingData is ShopVO || buildingData is FacilityVO;
                    addChild(tile);
                    tiles.add(i+"_"+j,tile);
                }
            }
        }

        private function updateBase():void
        {
            tiles.eachKey(function(s:String):void{
                (tiles.getValue(s) as Unit).settlable = _settlable;
            });
        }
        /**
         * 是否可以安置,鼠标拖动的时候为true
         * @return
         *
         */
        public function get settlable():Boolean
        {
            return _settlable;
        }

        public function set settlable(value:Boolean):void
        {
            _settlable = value;
            if(row == 1)//店铺和建筑不一样
            {
                updateBase();
            }
        }
        /**
         * 不合适的点Array
         * @param factor
         *
         */
        public function set settleFactor(factor:Array):void
        {
            tiles.eachKey(function(k:String):void
            {
                if(factor.indexOf(k) > -1)
                {
                    (tiles.getValue(k) as Unit).settlable = false;
                }else
                {
                    (tiles.getValue(k) as Unit).settlable = true;
                }
            });
        }

        public function get buildingData():Object
        {
            return _buildingData;
        }

        /**
         * 回收
         *
         */
        public function recycle():void
        {
            tiles.eachKey(function(k:String):void
            {
                removeChild(tiles.getValue(k) as Unit);
                tiles.remove(k);
            });
        }
        /**
         * 摄入建筑(包括店铺和设施)信息
         * @param value
         *
         */
        public function set buildingData(value:Object):void
        {
            _buildingData = value;
            if(value.hasOwnProperty("referRow"))
            {
                row = value["referRow"];
                col = value["referCol"];
            }else
            {
                n = _buildingData.n;
            }
            if((_buildingData is FacilityVO) || (row == 1 && col == 1))
            {
                iconSource = DoMainInfo.assetsUrl + FACIL_URL + FacilityPool.SystemFacility[_buildingData.type-1]["icon"];
            }else if(_buildingData)
            {
                iconSource = DoMainInfo.assetsUrl + SHOP_URL + ShopVO.getFolder(_buildingData.type) + row + "_" + col + "_" + _buildingData.layer +".swf";
            }
            if(!isSimulate) initTiles();
//            settlable = false;
        }
        /**
         * 获取深度
         * @return
         * 计算方式 行*10 + (7 - 列)
         * 原理,行大者排前,列小者排前
         */
        public function get depth():Number
        {
            return (_buildingData.unit_row0 * 10 + (7 - _buildingData.unit_col0));
        }

        public function get n():int
        {
            return (_buildingData.unit_row0 - 1) * 7 + _buildingData.unit_col0;
        }

        public function set n(value:int):void
        {
            _n = value;

            if(_n%7 == 0)
            {
                _buildingData.unit_col0 = 7;
            }else
            {
                _buildingData.unit_col0 = _n%7;
            }
            _buildingData.unit_row0 = Math.ceil(_n/7);

            if(_buildingData is FacilityVO)
            {
                row = 1;
                col = 1;
            }else
            {
                row = _buildingData.length;
                col = _buildingData.width;
            }
            _buildingData.unit_row1 = _buildingData.unit_row0 + row;
            _buildingData.unit_col1 = _buildingData.unit_col0 + col;
        }
    }
}

BuildingTile.as

package com.app.map.smallMap
{
    import com.core.manage.MaterialUIManager;
    import com.core.utils.Tool;

    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.ProgressEvent;

    /**
     * 由于加载属于异步,所以用显示对象将其包装起来,直接使用此类即可,<br/>加载完后显示对象会自动添加到本类实例当中;<br/>
     * 此皮肤需要在添加到舞台之前设入深度depth与对应店铺设施之id,此二字段的默认值皆为0
     * @author Ado
     *
     */
    public class Skin extends Sprite
    {
        /**
         * 对应之建筑,设施或者店铺之id
         */
        public var id:int = 0;
        /**
         * 此皮肤对应之BuildingTile之深度,显示排序用
         */
        public var depth:Number = 0;
        private var mc:MovieClip;
        private var _srcUrl:String;
        private var loader:Loader;
//        private var _referWidth:Number;
        public var firstSort:int = 0;
        /**
         * 是否需要告知转换完毕
         */
        public var needNotice:Boolean;
        /**
         * 转换完毕的事件监听器
         */
        public static const CONVERT_COMPLETE:String = "CONVERT_COMPLETE";
        public function Skin(url:String = null)
        {
            loader = new Loader();

            if(url != "" && url != null)
            {
                srcUrl = url;
            }
            this.buttonMode = true;
        }
        /**
         * 回收资源
         * */
        public function recycle():void
        {
            loader.unloadAndStop();
            _srcUrl = "";
        }

        public function get srcUrl():String
        {
            return _srcUrl;
        }

        public function set srcUrl(value:String):void
        {
            _srcUrl = value;
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, convertComHandler);
            loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
            if(MaterialUIManager.contains(_srcUrl))
            {
                loader.loadBytes(Tool.clone(MaterialUIManager.getLoader(_srcUrl)));
            }
        }
        private function progressHandler(e:ProgressEvent):void
        {
            trace(e.bytesLoaded+":"+e.bytesTotal);
        }
        private function convertComHandler(e:Event):void
        {
            if(mc != null)
            {
                mc.stop();
                this.removeChild(mc);
                mc = null;
            }

            mc = e.target.loader.content;
            mc.cacheAsBitmap = true;
            addChild(mc);

            loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, convertComHandler);

            if(needNotice)
            {
                dispatchEvent(new Event(CONVERT_COMPLETE));
            }
        }
    }
}

Skin.as

package com.app.map.smallMap
{
    import flash.display.Sprite;

    public class Unit extends Sprite
    {
        private var color:uint;
        private var _settlable:Boolean = true;
        private var _setteld:Boolean = true;
        /**
         *
         * @param t 1代表设施底座 2代表店铺底座
         * @author Ado
         */
        public function Unit(t:int)
        {
            color = t == 1 ? 0xe0ec22 : 0xc02f0d;
            super();
        }

        private function updateBase():void
        {
            graphics.clear();
            var targetColor:uint = _setteld ? color : (_settlable ? 0x00ff00 : 0xff0000);
            graphics.beginFill(targetColor);

            graphics.moveTo(0.5,0);
            graphics.lineTo((BuildingTile.unitWidth - 1) /2, -(BuildingTile.unitHeight - 1)/2);
            graphics.lineTo((BuildingTile.unitWidth -1), 0);
            graphics.lineTo((BuildingTile.unitWidth - 1)/2, (BuildingTile.unitHeight - 1)/2)
            graphics.lineTo(0.5,0);
            graphics.endFill();
        }
        public function get settlable():Boolean
        {
            return _settlable;
        }

        public function set settlable(value:Boolean):void
        {
            _settlable = value;
            updateBase();
        }

        public function get setteld():Boolean
        {
            return _setteld;
        }

        public function set setteld(value:Boolean):void
        {
            _setteld = value;
            updateBase();
        }
    }
}

Unit.as

因为老的电脑太卡了,所以没有去跑起来,所以没办法出效果图,就这么留念一下吧。

时间: 2024-10-12 22:42:30

COC建筑拖动的实现的相关文章

Cocos实战篇[3.4]——仿COC的一个小Demo总结

[唠叨] 今天结束了本学期任务最为艰巨的项目实训课程,由于项目组里其他成员基本都已经找到实习了,然后他们都去实习了.只留下我和一个小伙伴在一起搞项目实训的小游戏.经过一个月与小伙伴的配合开发,做了一个勉强可以玩的一个小游戏demo,因为平时其他课程也比较繁重,所以游戏做得非常烂~(>_<)~. 我们本来打算做一款类似COC.海盗奇兵.口袋侏罗纪.城堡争霸的城战类的单机Demo.结果--哎说多了都是泪啊,经验不足,吸取教训了. [经验教训] 由于时间比较紧张,加上自身也没有大项目开发的经验,所以

COC+RTS+MOR游戏开发 一(游戏特色分析,和实践)

本场比赛的临时名称 游戏特色(-):COC风格 ,塔防养成类游戏. 一款史诗般的战斗策略游戏.玩家须要建立村庄,成千上万的网友训练玩家的军队和战斗. 游戏中玩家须要不断的提高军队的作战实力.而且能够完毕一定的任务后创建部落.玩家也能够对各种武器进行升级  游戏涉及到的技术:UI类:可伸缩菜单.地图随爽指的缩放.平移,多点与单点触摸,弹出相关UIbox 逻辑类:建筑的新建.拖放.回收.属性(攻击特效,防护,生命值~) 角色的单个/多个控制(攻击,移动,死亡) A star 角色智能寻路(单个/

*C#(WPF)--矩阵拖动和矩阵动画(拖动展开,不足动画效果)

最近在研发新的项目,遇到了一个桌面模式下的难点--展开动画.之前动画这方面没做过,也许很多人开始做的时候也会遇到相关问题,因此我把几个重点及实际效果图总结展示出来: 我的开发环境是在VS2017下进行的,这个工具条主要功能是:一个工具条,可进行拖拉.可进行拖拉展开,可在拖动之后不足展开并反向继续展开剩下的部分: 一.[拖动]   拖动的核心代码是通过矩阵进行定位和拖动的,定位是以父容器为模板的.以下是核心代码(及效果图): 1 /// <summary> 2 /// 这里TitleBar代指最

换现有建筑ARCHLine.XP 2016 x64 160502b248-Up7

CSI.ETABS.2016.v16.0.2.1539 CSI.XRevit.2017 成千上万的专业人士在建筑和室内设计,家具制造和许多其他领域使用ARCHLine.XP.ARCHLine.XP,直观 的三维CAD / BIM设计软件ARCHLine.XP是BIM软件,使您能够使3 d建筑,室内设计和家具设计的质量和效率 .ARCHLine.XP需要一个创新的方法来重用和转换现有的建筑. ARCHLine.XP 2016 x64 160502b248-Up7 ITI.SimulationX.V

可拖动GridView的实现,类似支付宝界面

1.概述 之前实现过一个仿支付宝界面的代码,可拖动网格视图.其实实现的原理网上都可以找到,我也是参考网上实现的方法,实现了自己需要的界面.并对实现的原理和方法进行了分析,现在进行总结,放太久都快忘记自己做过这回事了.原理和实现网上大部分地方都可以找到,我是根据自己的理解进行分析的,现在对之前的工作进行总结,了解实现的基本过程和方法.GridView拖动的源码来源于网上,根据需求修改成了需要的效果,下面简单说明下实现过程. 在说明实现之前,先上一张总体的界面效果图: 为了更好说明程序种各个变量的意

在Canvas上拖动产生文字

拖动的幅度越大,字就会越大. <!DOCTYPE html> <html> <head lang="en"> <style> html, body { width: 100%; height: 100%; margin: 0px; overflow: hidden; } canvas { cursor: crosshair; } span { font-family: 'Georgia', cursive; font-size: 40px

Unity3D拖动任意对象GameObject移动到任意地方

今天不是很忙,研究了一下拖拽GameObject移动到任意位置,沿x轴和z轴移动,其他的也就不说了,上代码: using UnityEngine; using System.Collections; public class DragAndDrog : MonoBehaviour {     private GameObject target;     private bool isMouseDrag;     private Vector3 screenPosition;     privat

CentOS6下基于Nginx搭建mp4/flv流媒体服务器(可随意拖动)并支持RTMP/HLS协议(含转码工具)

1.先添加几个RPM下载源 1.1)安装RPMforge的CentOS6源      [[email protected] ~]# wget -c http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm      [[email protected] ~]# rpm –import http://apt.sw.be/RPM-GPG-KEY.dag.txt      [[email 

Winform 图片鼠标滚动查看(放大,缩小,旋转,拖动查看)[日常随笔]

方法千千万,我只是其中一笔[通过控制PictureBox来控制图片,图片完全施展在控件中]...几久不做,还真有点陌生! 窗体构造中添加鼠标滚动: 1 /// <summary> 2 /// 窗体构造方法 3 /// </summary> 4 public CandidateForm() 5 { 6 InitializeComponent(); 7 this.MouseWheel += new MouseEventHandler(CandidateForm_MouseWheel);