/// <summary>
        /// 図解: http://qiita.com/muzudho1/items/7de6e450e1762b993a63
        /// </summary>
        /// <returns></returns>
        public static bool HasColor_Horizontal_ByWinningStairs(int x, int y, ColorBoxDto boxSettings, Texture2D texture2D)
        {
            // 画像の外か判定
            if (texture2D.width <= x || y < 0)
            {
                return(true);
            }

            // 切断形か判定
            Color color = texture2D.GetPixel(x - DELETE_SPACE + boxSettings.GetWinnerStairsDistance() + DataClassFile.GRID_WIDTH / 2, y - boxSettings.GetWinnerStairsDistance());

            return(boxSettings.expectedR == color.r && boxSettings.expectedG == color.g && boxSettings.expectedB == color.b);
        }
        /// <summary>
        /// 図解: http://qiita.com/muzudho1/items/7de6e450e1762b993a63
        /// </summary>
        /// <returns></returns>
        public static bool IsStarting_ByWinningStairs(int x, int y, ColorBoxDto boxSettings, Texture2D texture2D, StringBuilder info_message)
        {
            Color color = texture2D.GetPixel(
                x + boxSettings.GetWinnerStairsDistance()
                , y - boxSettings.GetWinnerStairsDistance()
                );

            if (info_message.Length < 10000)
            {
                info_message.AppendLine("IsStarting_ByWinningStairs: x=[" + (x + boxSettings.GetWinnerStairsDistance()) + "] y=[" + (y - boxSettings.GetWinnerStairsDistance()) + "] color.r,g,b=[" + color.r + "][" + color.g + "][" + color.b + "]");
            }
            return(boxSettings.expectedR == color.r && boxSettings.expectedG == color.g && boxSettings.expectedB == color.b);
        }
        /// <summary>
        /// 図解: http://qiita.com/muzudho1/items/7de6e450e1762b993a63
        /// </summary>
        /// <returns></returns>
        public static bool HasColor_Vertical_WinningStairs(int x, int y, ColorBoxDto boxSettings, Texture2D texture2D)
        {
            // 画像の外か判定
            if (texture2D.width <= x || y < 0)
            {
                return(true);
            }

            // 切断形か判定
            Color color = texture2D.GetPixel(
                x + boxSettings.GetWinnerStairsDistance()
                , y + DELETE_SPACE - boxSettings.GetWinnerStairsDistance() - DataClassFile.GRID_HEIGHT / 2
                );

            return(boxSettings.expectedR == color.r && boxSettings.expectedG == color.g && boxSettings.expectedB == color.b);
        }
        public static void Execute_1Image(ColorBoxDto boxSettings, List <List <SliceRectangleDto> > imageList, string filepath, StringBuilder info_message)
        {
            List <SliceRectangleDto> sliceList = new List <SliceRectangleDto>();

            // 座標系は左下隅スタート
            Texture2D texture2D = PngReaderDao.FromPngFile(filepath);
            //info_message.AppendLine("DataGenerator.SLICE_WIDTH = " + DataGenerator.SLICE_WIDTH + " DataGenerator.SLICE_HEIGHT = " + DataGenerator.SLICE_HEIGHT);
            //info_message.AppendLine("texture2D.width = " + texture2D.width + " texture2D.height = " + texture2D.height);
            //info_message.AppendLine("overX = " + (texture2D.width - DataGenerator.SLICE_WIDTH + 1) + " overY = " + (DataGenerator.SLICE_HEIGHT - 1));

            int sliceNumber = 0;
            // スライス・サイズの画像が四方形のタイル状に敷き詰められているとする。
            // 座標は 0 ~ (サイズ-1) とし、Y は下げていく。
            // tickY、tickXは スライスされた区画の左上隅を指しているものとする。
            // width は overX と読み替え、last の1つ次と考えると分かりやすい。 last < over。
            int thisY_tilefile = texture2D.height - 1;
            int nextY_tilefile = -1;

            for (int tickY = thisY_tilefile; nextY_tilefile < tickY; tickY -= DataClassFile.SLICE_HEIGHT)
            {
                int thisX_tilefile = 0;
                int nextX_tilefile = texture2D.width;
                for (int tickX = thisX_tilefile; tickX < nextX_tilefile; tickX += DataClassFile.SLICE_WIDTH)
                {
                    if (info_message.Length < 3000)
                    {
                        info_message.AppendLine("@Add sliceNumber=[" + sliceNumber + "] tickY=[" + tickY + "] tickX=[" + tickX + "]");
                    }

                    sliceList.Add(Execute_1Slice(boxSettings, sliceList, tickX, tickY, sliceNumber, texture2D, filepath, info_message));

                    sliceNumber++;
                }
            }
            imageList.Add(sliceList);
        }
        /// <summary>
        /// 1スライスにつき、当たり判定は1個所という前提☆
        /// </summary>
        /// <param name="rectList">判定済み判定用</param>
        /// <param name="thisX_slice"></param>
        /// <param name="thisY_slice"></param>
        /// <param name="sliceNumber"></param>
        /// <param name="texture2D"></param>
        /// <param name="file"></param>
        /// <returns></returns>
        public static SliceRectangleDto Execute_1Slice(ColorBoxDto boxSettings, List <SliceRectangleDto> rectList, int thisX_slice, int thisY_slice, int sliceNumber, Texture2D texture2D, string file, StringBuilder info_message)
        {
            int nextX_slice = thisX_slice + DataClassFile.SLICE_WIDTH;
            // Y は下げていく
            int nextY_slice = thisY_slice - DataClassFile.SLICE_HEIGHT;

            if (info_message.Length < 10000)
            {
                info_message.AppendLine("Execute_1Slice(A): sliceNumber = " + sliceNumber + " nextX_slice=[" + nextX_slice + "] nextY_slice=[" + nextY_slice + "] sliceX1=[" + thisX_slice + "] sliceY1=[" + thisY_slice + "]");
            }

            // 当たり判定サイズ単位のグリッドが引かれた方眼紙になっているものとし、
            // その左上角(0+offset,0+offset)の1セルが 指定色だった場合、そのグリッド1つ分 は当たり判定があるものとする。

            // Y は下げていく
            for (int tickY1 = thisY_slice; nextY_slice < tickY1; tickY1 -= DataClassFile.GRID_HEIGHT)
            {
                if (info_message.Length < 10000)
                {
                    info_message.AppendLine("Execute_1Slice(B): tickY1 = " + tickY1 + " thisX_slice=[" + thisX_slice + "] nextX_slice=[" + nextX_slice + "]");
                }

                for (int tickX1 = thisX_slice; tickX1 < nextX_slice; tickX1 += DataClassFile.GRID_WIDTH)
                {
                    // 開始形か 判定
                    if (IsStarting_ByWinningStairs(tickX1, tickY1, boxSettings, texture2D, info_message))
                    {
                        // 既に判定済みならスキップ
                        if (ContainsLocation(tickX1, tickY1, rectList))
                        {
                            if (info_message.Length < 3000)
                            {
                                info_message.AppendLine("Execute_1Slice(D): skipped " + tickX1 + ", " + tickY1);
                            }
                        }
                        else
                        {
                            if (info_message.Length < 10000)
                            {
                                info_message.AppendLine("Execute_1Slice(E): tickY1 = " + tickY1 + " tickX1 = " + tickX1);
                            }

                            // さらに横方向に調査
                            int tickX2_onGrid = tickX1 + DataClassFile.GRID_WIDTH;// 上辺を左から右にスキャン
                            for (; tickX2_onGrid < nextX_slice; tickX2_onGrid += DataClassFile.GRID_WIDTH)
                            {
                                if (!HasColor_Horizontal_ByWinningStairs(tickX2_onGrid, tickY1, boxSettings, texture2D))
                                {
                                    break; // 横の終わり
                                }
                            }

                            // さらに縦方向に調査。左辺を降りていく
                            // Y は下に向かって減っていく
                            int tickY2_onGrid = tickY1 - DataClassFile.GRID_HEIGHT;
                            for (; nextY_slice < tickY2_onGrid; tickY2_onGrid -= DataClassFile.GRID_HEIGHT)
                            {
                                if (!HasColor_Vertical_WinningStairs(tickX1, tickY2_onGrid, boxSettings, texture2D))
                                {
                                    break; // 縦の終わり
                                }
                            }

                            return(new SliceRectangleDto(thisX_slice, thisY_slice, DataClassFile.SLICE_WIDTH, DataClassFile.SLICE_HEIGHT, tickX1, tickY1, tickX2_onGrid - tickX1, tickY1 - tickY2_onGrid));
                        }
                    }
                    else
                    {
                        if (info_message.Length < 10000)
                        {
                            info_message.AppendLine("Execute_1Slice(C)開始形じゃない: tickY1 = " + tickY1 + " tickX1 = " + tickX1);
                        }
                    }
                }
            }//画像スキャン終わり

            return(new SliceRectangleDto());
        }
        public static void Generate(StringBuilder info_message)
        {
            #region Get Filepaths
            // 青、赤、黄と3箱読み取るので、読取ファイル数はファイルの数の3倍になります。
            string[] filepaths = Directory.GetFiles("./Assets/Hitbox2DLorikeet/Editor/Work", "*.png");
            info_message.AppendLine("filepaths.Length = " + filepaths.Length);
            #endregion

            // 大文字・小文字を無視してソート☆
            Array.Sort(filepaths, StringComparer.OrdinalIgnoreCase);

            StringBuilder script = new StringBuilder();
            script.AppendLine(@"namespace DojinCircleGrayscale.Hitbox2DLorikeet
{

    /// <summary>
    /// This file was automatically generated.
    /// It was created by [Generate C# (Data)] button.
    /// </summary>
    public class LorikeetData
    {
        #region Singleton
        static LorikeetData()
        {
            Instance = new LorikeetData();
        }
        /// <summary>
        /// シングルトン・デザインパターンとして作っています。
        /// I am making this class as a singleton design pattern.
        /// </summary>
        public static LorikeetData Instance { get; private set; }
        #endregion

        LorikeetData()
        {
            LorikeetBoxes = new LorikeetBox[]
            {
                HitboxData.Instance,
                WeakboxData.Instance,
                StrongboxData.Instance,
            };
        }
        LorikeetBox[] LorikeetBoxes { get; }
    }
");

            ColorBoxDto[] boxesSettings = new ColorBoxDto[]
            {
                //Utility_BoxScanner.m_blueBox,
                //Utility_BoxScanner.m_yellowBox,
                //Utility_BoxScanner.m_redBox,
                BoxScannerDao.m_redBox,
                BoxScannerDao.m_blueBox,
                BoxScannerDao.m_yellowBox,
            };

            foreach (ColorBoxDto boxSettings in boxesSettings)
            {
                List <List <SliceRectangleDto> > image_to_slice_to_rectangleList = new List <List <SliceRectangleDto> >();
                foreach (string filepath in filepaths)
                {
                    info_message.AppendLine("画像読込 : " + filepath);
                    BoxScannerDao.Execute_1Image(boxSettings, image_to_slice_to_rectangleList, filepath, info_message);
                    info_message.AppendLine("list.Count : " + image_to_slice_to_rectangleList.Count);
                }

                {
                    StringBuilder sb_dammy = new StringBuilder();
                    foreach (List <SliceRectangleDto> list in image_to_slice_to_rectangleList)
                    {
                        foreach (SliceRectangleDto rect in list)
                        {
                            info_message.AppendLine("確認 : rect.SliceNumber=[" + rect.SliceNumber + "] rect.Slice=[" + rect.Slice + "] rect.Collider=[" + rect.Collider + "] rect.GetOffsetX()=[" + rect.GetOffsetX(sb_dammy) + "] rect.GetOffsetY()=[" + rect.GetOffsetY(sb_dammy) + "] rect.GetScaleX()=[" + rect.GetScaleX() + "] rect.GetScaleY()=[" + rect.GetScaleY() + "]");
                        }
                    }
                }

                string text = Hitbox2DClassFile.ToText(boxSettings.m_outputClassName, image_to_slice_to_rectangleList, info_message);
                System.Console.WriteLine(text);
                script.Append(text);
            }

            script.AppendLine("}");
            File.WriteAllText(DataClassFile.FILE_PATH, script.ToString());


            // おわり☆
            System.Console.WriteLine("Please, push any key.");
            System.Console.ReadKey();
        }