六边形格子地图坐标计算与转换

// 世界场景的一些数据管理,如提供坐标转换之类的接口

var WorldMapManager = function () {
    this.mapSize = null;     // 地图大小,像素
    this.curViewPos = null;  // 当前大地图视野坐标

    // 初始化世界地图的数据
    this.init = function (mapSize, tileSize) {
        this.mapSize = {
                width  : globalConsts.WorldMapSize.width * globalConsts.TileSize.width + globalConsts.TileSize.width / 2,
                height : globalConsts.WorldMapSize.height * ((globalConsts.TileSize.height - globalConsts.TileSize.hex) / 2 + globalConsts.TileSize.hex) + 
                            (globalConsts.TileSize.height - globalConsts.TileSize.hex) / 2
            };
        this.tileSize = globalConsts.TileSize;
    };

    // 大地图坐标转成蜂窝cell
    this.mapPosToTile = function (pos) {
        // 算出缩放成正六边形后边长 a 的值
        var a = this.tileSize.width / Math.sqrt(3);
        var x = pos.x, y = (this.mapSize.height - pos.y) / this.tileSize.height * a * 2 + a / 2;    // 加 a / 2 是因为矩形网格计算时会在底部增加 a / 2
        
        //位于矩形网格边线上的三个CELL中心点
        var points = new Array(cc.p(0, 0), cc.p(0, 0), cc.p(0, 0));
        //当前距离的平方
        var dist;
        //      index:被捕获的索引
        var i, index;
        //二分之根号3 边长的平方,如果距离比它还小,就必然捕获
        var g_MinDistance2 = Math.pow(a * Math.sqrt(3) / 2, 2);
        // 网格宽、高
        var g_unitx = a * Math.sqrt(3);     //sqrt(3) * a
        var g_unity = a * 1.5;              //a * 3 / 2
        // 网格对角线平方向上取整
        var mindist= Math.ceil(Math.pow(g_unitx, 2) + Math.pow(g_unity, 2));
        //计算出鼠标点位于哪一个矩形网格中
        var cx = parseInt(x/g_unitx);
        var cy = parseInt(y/g_unity);

        points[0].x = parseInt(g_unitx * cx);
        points[1].x = parseInt(g_unitx * (cx+0.5));
        points[2].x = parseInt(g_unitx * (cx+1));
        //根据cy是否是偶数,决定三个点的纵坐标
        if(cy % 2 == 0)
        {
            //偶数时,三个点组成倒立三角
            points[0].y = points[2].y = parseInt(g_unity * cy);
            points[1].y = parseInt(g_unity * (cy+1));
        }    
        else
        {
            //奇数时,三个点组成正立三角
            points[0].y = points[2].y = parseInt(g_unity * (cy+1));
            points[1].y = parseInt(g_unity * cy);
        }
        
        // 计算两点间距离的平方
        function distance2(x1, y1, x2, y2)
        {
            return ((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
        }

        //现在找出鼠标距离哪一个点最近
        for(i = 0; i < 3; ++i)
        {
            //求出距离的平方
            dist = distance2(x, y, points[i].x, points[i].y);

            //如果已经肯定被捕获
            if(dist < g_MinDistance2)
            {
                index = i;
                break;
            }

            //更新最小距离值和索引
            if(dist < mindist)
            {
                mindist = dist;
                index = i;
            }
        }
        
        // x 第 0 个点的列值减 1 等于cell.x ( x 最左半格有 -1 值 )
        // cy 偶数时中间点 + 1,奇数时两边点 + 1,减 1 是因为初始为了计算方便 y 补了 a / 2 ( y 最上半格 也会存在 -1 )
        return {x : cx - (index > 0? 0 : 1), y : cy + (cy % 2 + index % 2) % 2 - 1};
    };
    
    // 格子坐标转成地图坐标
    this.tilePosToMap = function (pos) {
        var tileCenter, xPixel, yPixel;

        tileCenter = (pos.x * this.tileSize.width) + this.tileSize.width / 2;
        xPixel = tileCenter + (pos.y % 2) * this.tileSize.width / 2;
        yPixel = this.tileSize.height / 2 + pos.y * (this.tileSize.height / 2 + this.tileSize.hex / 2);

        // 因为锚点的关系,y值需要倒过来,这很重要
        yPixel = this.mapSize.height - yPixel;

        return cc.p(xPixel, yPixel);
    };
    
    // 获取相邻两个六边形格子中心点距离
    this.getAdjacentHexagonCenterPointDistance = function (isLeftAndRight) {
        if (isLeftAndRight) {
            return this.tileSize.width;
        } else {
            return Math.sqrt(Math.pow((this.tileSize.height + this.tileSize.hex) / 2, 2) + Math.pow(this.tileSize.width / 2, 2));
        }
    };
};

// 单例

WorldMapManager.sharedInstance = null;

WorldMapManager.getInstance = function(){
    if (WorldMapManager.sharedInstance == null) {
        WorldMapManager.sharedInstance = new WorldMapManager();
        WorldMapManager.sharedInstance.init();
    }
    return WorldMapManager.sharedInstance;
};


var tileCalculate = {

    // 两六边形 tilePos 获取 无视阻挡的最短距离格子数 0~1 return 1
    getTwoTileDistance : function(lightTilePos, findTilePos) {
        var offX = 1, offY = 1;   // 初始 findTilePos 在 lightTilePos 左上,往右下寻
        var tilePos, count;

        if (lightTilePos.y === findTilePos.y) {
            return Math.abs(lightTilePos.x - findTilePos.x);
        } else if (lightTilePos.x === findTilePos.x) {
            return Math.abs(lightTilePos.y - findTilePos.y);
        } else {
            count = 0;
            tilePos = {x:findTilePos.x, y:findTilePos.y};
            // 在右,往左寻
            if (lightTilePos.x < tilePos.x) {
                offX = -1;
            }
            // 在下,往上寻
            if (lightTilePos.y < tilePos.y) {
                offY = -1;
            }
            do {
                ++count;
                tilePos.x += tilePos.y % 2 > 0 ? (offX > 0 ? offX : 0) : (offX < 0 ? offX : 0);
                tilePos.y += offY;
            } while (lightTilePos.x !== tilePos.x && lightTilePos.y !== tilePos.y);
            count += Math.abs(lightTilePos.x - tilePos.x) + Math.abs(lightTilePos.y - tilePos.y);
            return count;
        }
    },

    // 获取格子周围一圈,共六个格子的格子坐标
    getAroundTilePos : function(tilePos) {
        if (tilePos.y % 2 > 0) {
            return [{x : tilePos.x, y : tilePos.y - 1}, {x : tilePos.x, y : tilePos.y + 1}, // 上下
                    {x : tilePos.x - 1, y : tilePos.y}, {x : tilePos.x + 1, y : tilePos.y}, // 左右
                    {x : tilePos.x + 1, y : tilePos.y - 1}, {x : tilePos.x + 1, y : tilePos.y + 1}];    // 右上,右下
        } else {
            return [{x : tilePos.x, y : tilePos.y - 1}, {x : tilePos.x, y : tilePos.y + 1}, // 上下
                    {x : tilePos.x - 1, y : tilePos.y}, {x : tilePos.x + 1, y : tilePos.y}, // 左右
                    {x : tilePos.x - 1, y : tilePos.y - 1}, {x : tilePos.x - 1, y : tilePos.y + 1}];    // 左上,左下
        }
    },

    // 获取格子周围两圈,共十八个格子的格子坐标
    getAroundTwoLapsTilePos : function(tilePos) {
        var i, j, tiles1, tiles2 = [];
        var tilePoses = {};

        // 把第一圈及第一圈每一个的第一圈都收集起来
        tiles1 = this.getAroundTilePos(tilePos);
        for (i in tiles1) {
            tiles2 = this.getAroundTilePos(tiles1[i]);
            for (j in tiles2) {
                if (tiles2[j].x !== tilePos.x || tiles2[j].y !== tilePos.y) {
                    tilePoses[JSON.stringify(tiles2[j])] = tiles2[j];
                }
            }
        }

        return tilePoses;
    },

};


阅读更多
换一批

没有更多推荐了,返回首页