【Unity】二维坐标映射成ID

        在平面上,格子坐标通常是个二维坐标(X,Y),但是二维坐标有很多不方便的地方,且如果作为键值,其取值效率不高。因此大部分情况下,需要将二维坐标转换成ID来使用(且能从ID转换回坐标)。

        常用的方式就是X*N+Y,N为一个足够大的数。但是这种方式有问题,其只能支持全正数或者全负数,一旦有正有负,就会坐标转换失败。因此需要一种较为便捷的算法,能将二维坐标映射成ID,且能互相转换。

1、简述

        基本原理如下图所示:

         这就是ID的生成顺序,以一个螺旋形状进行生成。

        这种生成方式的优点之一,便是可以仅仅通过转换出来的ID就能判定其里坐标原点的距离,存数组的时候可以视作有序。缺点便是其性能并不是最优。

2、代码

        原理没什么好说的,就是纯计算。直接上代码:

        2.1 : 坐标转成ID

        public int ToInt(Vector2Int grid)
        {
            if (grid.x == 0 && grid.y == 0) return 0;

            int k = math.max(math.abs(grid.x), math.abs(grid.y));
            if (grid.x > grid.y)
                return 4 * k * k + 1 + 2 * k + grid.x + grid.y;
            else
                return 4 * k * k + 1 - 2 * k - grid.x - grid.y;
        }

        2.2: ID转换回坐标

        ID转换回坐标略复杂一些,代码如下:

        public Vector2Int GetMapGrid(int index)
        {
            if (index == 0) return Vector2Int.zero;
            float sqrtX = math.sqrt(index);
            int k = (int)((sqrtX + 1) / 2);
            if (sqrtX > 2 * k)
            {
                int xAy = index - (4 * k * k + 1) - 2 * k;
                if (xAy < 0)
                {
                    int y = -1 * k;
                    int x = xAy - y;
                    return new Vector2Int(x, y);
                }
                else
                {
                    int x = k;
                    int y = xAy - x;
                    return new Vector2Int(x, y);
                }
            }
            else
            {
                int xAy = (4 * k * k + 1) - index - 2 * k;
                if (xAy < 0)
                {
                    int x = -k;
                    int y = xAy - x;
                    return new Vector2Int(x, y);
                }
                else
                {
                    int y = k;
                    int x = xAy - y;
                    return new Vector2Int(x, y);
                }
            }
        }

3、使用Long实现

        当然,还有一种其他的方法可以实现二维坐标转ID。原理简单,就是用一个long(int64)来储存,前32存x,后32位存y。这种处理方式很重要的一点,就是要避免进行加减法计算,只能使用位运算进行拼接。

        代码如下:

        public long GetID(int q, int r)
        {
            long rt = (long)q << 32;
            rt = rt | (r & 0xffffffff);
            return rt;
        }

        public Vector2Int GetCoordinate(long id)
        {
            int x = (int)(id >> 32);
            int y = (int)id;
            return new Vector2Int(x, y);
        }

        这个方法的缺点,就是转换后的值会变得特别大,而且不能仅通过观察数值大小就能确定其距离坐标原点的远近。

        优点是理解容易,且性能更佳。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值