六边形网格向量工具

实现了六边形网格的向量工具,

Hex为斜角坐标系,三个轴平面夹角为120度
NetHex为offset型坐标系,xy轴夹角90度
AxialHex为轴坐标系p,r夹角120度,支持互相转换

Hex坐标系方便制作技能范围,寻路等功能
AxialHex坐标系一般用于辅助计算
NetHex坐标系方便存储二维数组数据

同时支持坐标类型生成二维坐标(x,0,z)。后续会加入形状,距离等判断。用于制作复杂技能区域的游戏,并方便进行寻路计算。

图为Hex坐标系

这里写图片描述

图为几种不同的NetHex类型

这里写图片描述

具体数学原理参考redblobgames

下面是代码。

Hex.cs
提供基本数据格式

using System;
using System.Collections.Generic;
using UnityEngine;

namespace GridTool.Hex
{

    public struct Hex
    {
        public int x;
        public int y;
        public int z;

        public Hex(int x, int y, int z)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }


        public int this[int index]
        {
            get
            {
                switch (index)
                {
                    case 0:
                        return x;
                    case 1:
                        return y;
                    case 2:
                        return z;
                    default:
                        throw new IndexOutOfRangeException("Invalid Hex index!");
                }
            }
            set
            {
                switch (index)
                {
                    case 0:
                        x = value;
                        break;
                    case 1:
                        y = value;
                        break;
                    case 2:
                        z = value;
                        break;
                    default:
                        throw new IndexOutOfRangeException("Invalid HexTransform index!");
                }
            }
        }

        //========== 快速构造 ==========

        /// <summary>
        /// 原点
        /// </summary>
        public static Hex zero
        {
            get
            {
                return new Hex(0, 0, 0);
            }
        }


        /// <summary>
        /// 左上
        /// </summary>
        public static Hex LTop
        {
            get
            {
                return new Hex(0, 1, -1);
            }
        }

        /// <summary>
        /// 右上
        /// </summary>
        public static Hex RTop
        {
            get
            {
                return new Hex(1, 0, -1);
            }
        }
        public static Hex Left
        {
            get
            {
                return new Hex(-1, 1, 0);
            }
        }
        public static Hex Right
        {
            get
            {
                return new Hex(1, -1, 0);
            }
        }
        public static Hex LBottom
        {
            get
            {
                return new Hex(-1, 0, 1);
            }
        }
        public static Hex RBottom
        {
            get
            {
                return new Hex(0, -1, 1);
            }
        }


        public static Hex[] Directions
        {
            get
            {
                return new Hex[6] {
                    Hex.LTop,
                    Hex.RTop,
                    Hex.Right,
                    Hex.RBottom,
                    Hex.LBottom,
                    Hex.Left
                };
            }
        }

        //========== 数组操作 =========
        public static Hex[] operator +(Hex[] a, Hex b)
        {
            Hex[] c = new Hex[a.Length];
            for (int i = 0; i < a.Length; i++)
            {
                c[i] = a[i] + b;
            }
            return c;
        }


        public static Hex[] operator -(Hex[] a, Hex b)
        {
            Hex[] c = new Hex[a.Length];
            for (int i = 0; i < a.Length; i++)
            {
                c[i] = a[i] - b;
            }
            return c;
        }

        //========== 运算符 =========

        public static Hex operator +(Hex a, Hex b)
        {
            return new Hex(a.x + b.x, a.y + b.y, a.z + b.z);
        }

        public static Hex operator -(Hex a, Hex b)
        {
            return new Hex(a.x - b.x, a.y - b.y, a.z - b.z);
        }

        public static Hex operator -(Hex a)
        {
            return new Hex(-a.x, -a.y, -a.z);
        }
        public static Hex operator *(Hex a, int d)
        {
            return new Hex(a.x * d, a.y * d, a.z * d);
        }

        public static Hex operator *(int d, Hex a)
        {
            return new Hex(a.x * d, a.y * d, a.z * d);
        }

        public static Hex operator /(Hex a, int d)
        {
            return new Hex(a.x / d, a.y / d, a.z / d);
        }

        public static bool operator ==(Hex lhs, Hex rhs)
        {
            return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
        }

        public static bool operator !=(Hex lhs, Hex rhs)
        {
            return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z;
        }

        //========== 工具 =========
        public static int Distance(Hex from, Hex to)
        {
            return (int)Mathf.Max(Mathf.Abs(from.x - to.x), Mathf.Abs(from.y - to.y), Mathf.Abs(from.z - to.z));
        }



        public override string ToString()
        {
            return String.Format("({0}, {1}, {2})", x, y, z);
        }
        public string ToString(string format)
        {
            return String.Format("({0}, {1}, {2})", x.ToString(format), y.ToString(format), z.ToString(format));
        }




        public void Fix()
        {
            y = -x - z;
        }




    }

    public struct AxialHex
    {
        public int q;
        public int r;
        public AxialHex(int q, int r)
        {
            this.q = q;
            this.r = r;
        }

        public static AxialHex RoundAxial(float q, float r)
        {
            return HexTools.RoundHex(q, -q - r, r).ToAxial();
        }
    }

    public enum HexType
    {
        Odd_r,// 行对齐 偶数行偏左
        Even_r,// 行对齐 偶数行偏右
        Odd_q,// 列对齐 0
        Even_q,//
        NULL//
    }


    public struct NetHex
    {
        public int col;
        public int row;


        public NetHex(int col, int row)
        {
            this.col = col;
            this.row = row;

        }

        public override string ToString()
        {
            return String.Format("({0}, {1})", col, row);
        }
    }
}

工具类
处理各种坐标系之间的转换关系等。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace GridTool.Hex
{
    public static class HexTools
    {
        public static Hex ToHex(this AxialHex ax)
        {
            return new Hex(ax.q, -ax.q - ax.r, ax.r);
        }

        public static AxialHex ToAxial(this Hex hex)
        {
            return new AxialHex(hex.x, hex.z);
        }


        public static Hex ToHex(this NetHex grid, HexType type)
        {
            Hex hex = new Hex(0, 0, 0);
            int col = grid.col;
            int row = grid.row;
            switch (type)
            {
                case HexType.Odd_q:
                    {
                        hex.x = col;
                        hex.z = row - (col - (col & 1)) / 2;
                        hex.y = -hex.x - hex.z;
                    }
                    break;
                case HexType.Even_q:
                    {
                        hex.x = col;
                        hex.z = row - (col + (col & 1)) / 2;
                        hex.y = -hex.x - hex.z;
                    }
                    break;
                case HexType.Odd_r:
                    {
                        hex.x = col - (row - (row & 1)) / 2;
                        hex.z = row;
                        hex.y = -hex.x - hex.z;
                    }
                    break;
                case HexType.Even_r:
                    {
                        hex.x = col - (row + (row & 1)) / 2;
                        hex.z = row;
                        hex.y = -hex.x - hex.z;
                    }
                    break;
                default:
                    break;
            }
            return hex;
        }


        public static NetHex ToNet(this Hex hex, HexType type)
        {
            int col;
            int row;
            switch (type)
            {
                case HexType.Odd_q:
                    {
                        col = hex.x;
                        row = hex.z + (hex.x - (hex.x & 1)) / 2;
                    }
                    break;
                case HexType.Even_q:
                    {
                        col = hex.x;
                        row = hex.z + (hex.x + (hex.x & 1)) / 2;
                    }
                    break;
                case HexType.Odd_r:
                    {
                        col = hex.x + (hex.z - (hex.z & 1)) / 2;
                        row = hex.z;
                    }
                    break;
                case HexType.Even_r:
                    {
                        col = hex.x + (hex.z + (hex.z & 1)) / 2;
                        row = hex.z;
                    }
                    break;
                default:
                    {
                        col = 0;
                        row = 0;
                    }
                    break;
            }
            return new NetHex(col, row);
        }

        //类型是否尖角朝上
        public static bool IsPointTop(this HexType type)
        {
            return type == HexType.Even_r || type == HexType.Odd_r;
        }

        //网格中心相对0点便宜位置,y轴为0。
        public static Vector3 ToPixel(this Hex hex, float size, HexType type)
        {

            AxialHex ax = hex.ToAxial();
            if (IsPointTop(type))
                return new Vector3(
                    size * 1.73205080756887f * (ax.q + ax.r * .5f),
                    0,
                    size * 1.5f * ax.r);
            else
                return new Vector3(size * 1.5f * ax.q,
                    0,
                    size * 1.73205080756887f * (ax.r + ax.q * .5f));
        }


        public static Hex ToHex(this Vector3 pixel, float size, HexType type)
        {
            float q = 0;
            float r = 0;
            if (IsPointTop(type))
            {
                q = ((pixel.x * 1.73205080756887f - pixel.z) / (size * 3));
                r = (pixel.z * 0.666666666666f / size);
            }
            else
            {
                q = (pixel.x * 0.666666666666f / size);
                r = ((pixel.z * 1.73205080756887f - pixel.x) / (size * 3));
            }
            AxialHex ax = AxialHex.RoundAxial(q, r);
            return ax.ToHex();
        }



        public static Hex RoundHex(float x, float y, float z)
        {
            float rx = Mathf.Round(x);
            float ry = Mathf.Round(y);
            float rz = Mathf.Round(z);

            float x_diff = Mathf.Abs(rx - x);
            float y_diff = Mathf.Abs(ry - y);
            float z_diff = Mathf.Abs(rz - z);

            if (x_diff > y_diff && x_diff > z_diff)
                rx = -ry - rz;
            else if (y_diff > z_diff)
                ry = -rx - rz;
            else
                rz = -rx - ry;

            return new Hex((int)rx, (int)ry, (int)rz);
        }


        /// <summary>
        /// 获取相邻坐标组,左上顺时针旋转
        /// </summary>
        /// <param name="hex">目标坐标</param>
        /// <returns>坐标组</returns>
        public static Hex[] GetNeighbor(this Hex hex)
        {
            return Hex.Directions + hex;
        }


        /// <summary>
        /// 获取经过两点之间的坐标组
        /// </summary>
        /// <param name="from">开始坐标</param>
        /// <param name="target">结束坐标</param>
        /// <returns>坐标组</returns>
        public static Hex[] LineTo(this Hex from, Hex target)
        {
            int N = Hex.Distance(from, target);
            Hex[] results = new Hex[N];

            for (int i = 0; i <= N; i++)
            {
                float t = (float) i / (float) N;
                results[i] = HexTools.RoundHex(Mathf.Lerp(from.x,target.x,t), Mathf.Lerp(from.y,target.y,t), Mathf.Lerp(from.z,target.z,t));
            }
            return results;
        }



        /// <summary>
        /// 获取中心点范围内的所有坐标
        /// </summary>
        /// <param name="center">中心点</param>
        /// <param name="radius">范围</param>
        /// <returns>坐标组</returns>
        public static Hex[] Range(this Hex center, int radius)
        {
            List<Hex> results = new List<Hex>();
            for (int dx = -radius; dx <= radius; dx++)
            {
                for (int dy = Math.Max(-radius, -dx-radius); dy <= Math.Min(radius, -dx+radius); dy++)
                {
                    int dz = -dx - dy;
                    results.Add(center + new Hex(dx,dy,dz));
                }
            }
            return results.ToArray();
        }

        /// <summary>
        /// 获取以center为圆心的环形区域,半径为Radius
        /// </summary>
        /// <param name="center">中心位置</param>
        /// <param name="radius">环半径(不为0)</param>
        /// <returns>环形包含的格子</returns>
        public static Hex[] Ring(this Hex center, int radius)
        {
            List<Hex> results = new List<Hex>();


            Hex tmp = center + Hex.Directions[4] * radius;
            for (int i = 0; i < 6; i++)
            {
                for (int j = 0; j < radius; j++)
                {
                    results.Add(tmp);
                    tmp = tmp.GetNeighbor()[i];
                }
            }
            return results.ToArray();
        }




    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值