PG日誌

各記事はブラウザの横幅を1410px以上にすると2カラムの見出しが表示されます。なるべく横に広げてみてください。

C#でHexタイルの位置を計算する

今回は6角形のタイルの座標の計算を行うライブラリの紹介をしたいと思います。

計算した位置をいい感じに描画すると以下のような感じに並べることができます。

f:id:Takachan:20200224222537g:plain

HexLayoutクラス:6角形のタイルを並べる

結構強引に位置を計算していますが、指定した位置を中心に同心円状に並べる処理とX, Yで指定した位置を1つ取得する処理の2種類を用意しています。

/// <summary>
/// 2Dの6角形を配置するための位置を計算するクラス
/// </summary>
public class HexLayout
{
    /// <summary>
    /// 同心円状に配置する位置を取得します。
    /// </summary>
    public static IEnumerable<(float x, float y)> GetPosByConcentricCircle(float size, int level)
    {
        float SIZE_X = size;
        float SIZE_Y = SIZE_X * 0.75f;

        // 左上
        for (int i = 0; i < level; i++)
        {
            float xpos = SIZE_X / 2 * level;
            xpos += SIZE_X / 2 * i;
            float ypos = SIZE_Y * level;
            ypos -= SIZE_Y * i;
            yield return (-xpos, ypos);
        }

        // 左
        for (int i = 0; i < level; i++)
        {
            float xpos = SIZE_X * level;
            xpos -= SIZE_X / 2 * 1 * i;
            float ypos = 0;
            ypos -= SIZE_Y * i;
            yield return (-xpos, ypos);
        }

        // 左下
        for (int i = 0; i < level; i++)
        {
            float xpos = SIZE_X / 2 * level;
            xpos -= SIZE_X * i;
            float ypos = SIZE_Y * -level;
            yield return (-xpos, ypos);
        }

        // 右下
        for (int i = 0; i < level; i++)
        {
            float xpos = SIZE_X / 2 * level;
            xpos += SIZE_X / 2 * i;
            float ypos = SIZE_Y * -level;
            ypos += SIZE_Y * i;
            yield return (xpos, ypos);
        }

        // 右
        for (int i = 0; i < level; i++)
        {
            float xpos = SIZE_X * level;
            xpos -= SIZE_X / 2 * 1 * i;
            float ypos = 0;
            ypos += SIZE_Y * i;
            yield return (xpos, ypos);
        }

        // 右上
        for (int i = 0; i < level; i++)
        {
            float xpos = SIZE_X / 2 * level;
            xpos -= SIZE_X * i;
            float ypos = SIZE_Y * level;
            yield return (xpos, ypos);
        }
    }

    /// <summary>
    /// 指定した座標のHexの位置を取得します。
    /// </summary>
    public static (float x, float y) GetHexPos(int x, int y, float size)
    {
        //
        // 以下のような並び順で配置します:
        //
        // (-1,-2) ( 0,-2) ( 1,-2)
        //     ( 0,-1) ( 1,-1)
        // (-1, 0) ( 0, 0) ( 1, 0)
        //     ( 0, 1) ( 1, 1)
        // (-1, 1) ( 0, 1) ( 1, 1)
        //

        float xpos = Mathf.Abs(size * x);
        if (y % 2f != 0)
        {
            xpos -= size / 2.0f;
        }
        float ypos = Mathf.Abs(size * 0.75f * y);

        if (y > 0)
        {
            ypos *= -1;
        }

        return (xpos, ypos);
    }
}

考えかた

同心円計のGetPosByConcentricCircleメソッドは引数のレベルが何週目の円の位置かを表し、例えば2レベルでは以下のように左回りに位置の計算を行います。

f:id:Takachan:20200224223748p:plain

座標指定のGetHexPosは指定したXとYに従って以下座標系で位置を返します。

f:id:Takachan:20200224224128p:plain

これらの結果を受け取ってUnity上でSpriteに位置の指定を行ったものが冒頭のGifになります。

短いですが以上です。