見出し画像

【Unity】 数に応じていい感じに隊列を整列させたい

今回はタイトルの通り、いい感じに隊列を整列させるための
コードを書いていこうかなと思います!

先に完成品

前提

4個ずつ横に並べたくてオブジェクトの数が9個になった際
普通にfor文で配置していくと1,2列目は4個3列目は1個という不恰好な
列になってしまうため、本コードはこれをいい感じに整列させよう!
というものです。

ちなみに本コードを使用すると
1列目 4個、2列目 3個、2列目 2個という形になります。

今回は隊列にしたいので
常に (n列目 => n + 1列目) になるようにもしています。


コード

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

public class PlayerManager : MonoBehaviour
{
    // 子オブジェクトのプレハブと親オブジェクトを設定
    [SerializeField] GameObject childPrefab;
    [SerializeField] GameObject parentObject;

    // 子オブジェクト同士の距離
    [SerializeField] float distance = 0.8f;

    // 1行に並べる最大数
    [SerializeField] int maxChildrenPerRow = 8;

    // 初期の子オブジェクトの数
    [SerializeField] int initialChildCount = 2;

    // 子オブジェクトのリスト
    List<GameObject> children = new List<GameObject>();

    // 各行の子オブジェクト数
    List<int> childrenInRows = new List<int>();

    // スタート時に初期の子オブジェクトを生成
    void Start()
    {
        CreateChildren(initialChildCount);
    }

    // 指定された数の子オブジェクトを生成/削除する
    public void CreateChildren(int targetCount)
    {
        int childDifference = targetCount - children.Count;

        // 新しい子オブジェクトを生成
        while (childDifference > 0)
        {
            GameObject newChild = Instantiate(childPrefab, parentObject.transform);
            children.Add(newChild);
            childDifference--;
        }

        // 子オブジェクトを削除
        while (childDifference < 0)
        {
            if (children.Count == 1) return;  // 最後の1つは削除しない

            GameObject lastChild = children[children.Count - 1];
            children.Remove(lastChild);
            Destroy(lastChild);
            childDifference++;
        }

        // 子オブジェクトを行に並べる
        ArrangeChildrenInRows();
    }

    // 子オブジェクトを整列させる
    void ArrangeChildrenInRows()
    {
        childrenInRows.Clear();  // 前回の行データをクリア
        CalculateChildrenInRows(childrenInRows, children.Count);  // 行ごとの子オブジェクト数を計算

        float currentY = 0;
        int childIndex = 0;

        // 行ごとに子オブジェクトを並べる
        foreach (var rowCount in childrenInRows)
        {
            bool isRowEven = (rowCount % 2 == 0);  // 行の子オブジェクト数が偶数かどうか

            for (int i = 0; i < rowCount; i++)
            {
                float xPosition = 0.0f;

                if (isRowEven)
                {
                    // 偶数行の場合の配置
                    if (i % 2 == 0)
                        xPosition = (distance / 2) + (distance * (i / 2));
                    else
                        xPosition = (-distance / 2) - (distance * (i / 2));
                }
                else
                {
                    // 奇数行の場合の配置
                    if (i != 0 && i % 2 == 0)
                        xPosition = distance * ((i - 1) / 2 + 1);
                    else if (i != 0)
                        xPosition = -distance * ((i - 1) / 2 + 1);
                }

                // 子オブジェクトの位置を設定
                children[childIndex].transform.localPosition = new Vector3(xPosition, currentY, 0);
                childIndex++;
            }

            // Y軸の位置を1段下げる
            currentY += 1.0f;
        }
    }

    // 行ごとの子オブジェクト数を計算
    void CalculateChildrenInRows(List<int> rows, int totalChildren)
    {
        int row1 = totalChildren / 2 + (totalChildren % 2);  // 最初の行の子オブジェクト数
        int row2 = totalChildren / 2;  // 2番目の行の子オブジェクト数
        int overflow = 0;  // 3行目以降の余剰分

        // 最初の行が最大数を超えた場合の処理
        if (row1 > maxChildrenPerRow && row2 <= maxChildrenPerRow)
        {
            int tempValue = row1 / 2 + (row1 % 2);
            overflow = row1 / 2;
            row1 = row2;
            row2 = tempValue;
        }

        // 両方の行が最大数を超えた場合
        if (row1 > maxChildrenPerRow && row2 > maxChildrenPerRow)
        {
            overflow = (row1 - maxChildrenPerRow) + (row2 - maxChildrenPerRow);
            row1 = maxChildrenPerRow;
            row2 = maxChildrenPerRow;
        }

        // 行に子オブジェクト数を追加
        rows.Add(row1);
        if (row2 > 0) rows.Add(row2);

        // 残りの子オブジェクト数が最大数を超えている場合、再帰的に計算
        if (overflow > maxChildrenPerRow)
        {
            CalculateChildrenInRows(rows, overflow);
            return;
        }

        // 余剰分がある場合、それも行に追加
        if (overflow > 0) rows.Add(overflow);
    }

    // 指定した数の子オブジェクトを追加
    public void AddChildren(int count)
    {
        CreateChildren(children.Count + count);
    }
}

distanceをいじれば子オブジェクト同士の幅の調整も可能

終わりに

何かが後ろにぴょこぴょこついてくるだけで
無機物だとしても愛着湧きますよね!

不思議

ではまた!

ゲームを作るにはやはりお金がないとできることが限られてしまいます。なのでよろしければどうか支援してくださるとうれしいです