C#でグラデーションの矩形を描画


こんにちは。



この前作ったボンバーマ●ですが、ボンバーマ●のステージを作るのが結構めんどくさいので、暇を見てはステージエディタを作ってます。



作成中ですが、取り敢えず動画をアップロードしました。





ちなみにこのツールはC#で作っております。

C#は滅茶苦茶使いやすいですね!(´∀`)

これからの時代、MFCより断然C#ですね!!

しかも無料だし!!



このツールを作る際、結構苦労したのがグラデーションで線を引く処理ですね。

一定時間ごとに色が変わるようなサンプルとか何処にも載っていなかったので、

需要あるかな?と思って記事にしてみました。

グラデーションの矩形です





グラデーションの線を描画する箇所のソースコードです

public void drawGradientRect(Graphics g)
{
    Point p = startPoint;
    int x = p.X * BLOCK_SIZE;
    int y = p.Y * BLOCK_SIZE;
    int size = BLOCK_SIZE-1;

    Point []pa = new Point[5];
    
    //左端上
    pa[0].X = x + 1;
    pa[0].Y = y + 1;
    //右端上
    pa[1].X = x + size;
    pa[1].Y = y + 1;
    //右端下
    pa[2].X = x + size;
    pa[2].Y = y + size;
    //左端下
    pa[3].X = x + 1;
    pa[3].Y = y + size;
    //左端上
    pa[4].X = x + 1;
    pa[4].Y = y + 1;

    LinearGradientBrush gp1 = new LinearGradientBrush(
            pa[0], pa[1],
            Color.FromArgb(pColor[0].getR(), pColor[0].getG(), pColor[0].getB()),
            Color.FromArgb(pColor[1].getR(), pColor[1].getG(), pColor[1].getB())
        );
    LinearGradientBrush gp2 = new LinearGradientBrush(
            pa[1], pa[2],
            Color.FromArgb(pColor[1].getR(), pColor[1].getG(), pColor[1].getB()),
            Color.FromArgb(pColor[2].getR(), pColor[2].getG(), pColor[2].getB())
        );
    LinearGradientBrush gp3 = new LinearGradientBrush(
            pa[2], pa[3],
            Color.FromArgb(pColor[2].getR(), pColor[2].getG(), pColor[2].getB()),
            Color.FromArgb(pColor[3].getR(), pColor[3].getG(), pColor[3].getB())
        );
    LinearGradientBrush gp4 = new LinearGradientBrush(
            pa[3], pa[0],
            Color.FromArgb(pColor[3].getR(), pColor[3].getG(), pColor[3].getB()),
            Color.FromArgb(pColor[0].getR(), pColor[0].getG(), pColor[0].getB())
        );
    
    Pen pen1 = new Pen(gp1, 2.0f);       //幅2ピクセル
    pen1.DashStyle = DashStyle.Solid;     //ペンを直線に指定

    Pen pen2 = new Pen(gp2, 2.0f);       //幅2ピクセル
    pen1.DashStyle = DashStyle.Solid;     //ペンを直線に指定

    Pen pen3 = new Pen(gp3, 2.0f);       //幅2ピクセル
    pen1.DashStyle = DashStyle.Solid;     //ペンを直線に指定

    Pen pen4 = new Pen(gp4, 2.0f);       //幅2ピクセル
    pen1.DashStyle = DashStyle.Solid;     //ペンを直線に指定

    /*****************************
     * 
     *        ̄ ̄ ̄
     *      
     *      
     ****************************/
    g.DrawLine(pen1, pa[0], pa[1]);

    /*****************************
     * 
     *       ̄ ̄ ̄|
     *              |
     *               |
     *            
     ****************************/
    g.DrawLine(pen2, pa[1], pa[2]);

    /*****************************
     * 
     *       ̄ ̄ ̄|
     *              |
     *      ___|
     *      
     ****************************/
    g.DrawLine(pen3, pa[2], pa[3]);

    /*****************************
     * 
     *      | ̄ ̄|
     *      |     |
     *      |__|
     *      
     ****************************/
    g.DrawLine(pen4, pa[3], pa[0]);

    //リソースを解放
    pen1.Dispose();
    pen2.Dispose();
    pen3.Dispose();
    pen4.Dispose();

    gp1.Dispose();
    gp2.Dispose();
    gp3.Dispose();
    gp4.Dispose();

    /*****************************     
     *      描画色の更新
     *      グラデーションブラシで
     *      描画開始地点からの色を
     *      R,G,Bごとに更新する
     ****************************/
    for (int i = 0; i < (int)GradientColor.COLOR.MAX; i++)
    {
        pColor[i].valueIncrement();
    }

    //計測
    cycleCount++;
    if (cycleCount % (1000 / 8) == 0)
        Console.WriteLine("timer count = " + cycleCount);
}




クラス全体のソースコード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace MapChipTool
{
    /***************************************************/
    /*      範囲選択ツール用のクラス                   */
    /***************************************************/
    class Range
    {

        /***************************************************/
        /*              静的なクラス変数
        /***************************************************/
        private static readonly byte BLOCK_SIZE = GlobalParameter.BLOCK_SIZE;

        /***************************************************/
        /*      グラデーション用構造体                     */
        /***************************************************/
        private struct GradientColor
        {
            public enum COLOR
            {
                RED = 0,
                BLUE,
                GREEN,
                YELLOW,
                MAX,
            };

            private double r, g, b;
            private COLOR nowColor;
            private COLOR aimColor;
            private const int updateCycle = 60; //60FPS...timer interval 16ms...

            //現在の色を変更
            public void setNowColor(COLOR color)
            {
                if (color == COLOR.RED)
                {
                    r = 255.0;
                    g = 0.0;
                    b = 0.0;
                    aimColor = COLOR.YELLOW;
                } else
                if(color == COLOR.BLUE)
                {
                    r = 0.0;
                    g = 0.0;
                    b = 255.0;
                    aimColor = COLOR.RED;
                } else
                if (color == COLOR.GREEN)
                {
                    r = 0.0;
                    g = 255.0;
                    b = 0.0;
                    aimColor = COLOR.BLUE;
                } else
                if (color == COLOR.YELLOW)
                {
                    r = 255.0;
                    g = 255.0;
                    b = 0.0;
                    aimColor = COLOR.GREEN;
                }

                nowColor = color;
            }

            //      赤の要素を整数で取得
            public int getR() { return (int)r; }

            //      緑の要素を整数で取得
            public int getG() { return (int)g; }

            //      赤の要素を整数で取得
            public int getB() { return (int)b; }

            //      変更目標の色を設定
            public void setAimColor()
            {
                switch (nowColor)
                {
                    case COLOR.RED: aimColor = COLOR.YELLOW; break;
                    case COLOR.BLUE: aimColor = COLOR.RED; break;
                    case COLOR.GREEN: aimColor = COLOR.BLUE; break;
                    case COLOR.YELLOW: aimColor = COLOR.GREEN; break;
                }
            }

            //設定した目標の色に向けて、RGB値を増減
            public void valueIncrement()
            {
                const double incv = 255.0 / (double)updateCycle;
                switch (this.nowColor)
                {
                    case COLOR.RED:
                        /*******************************************
                         *      赤から黄色へ
                         *******************************************/
                        switch (this.aimColor)
                        {
                            case COLOR.RED: break;  //not used
                            case COLOR.BLUE: break; //not used
                            case COLOR.GREEN: break;//not used
                            case COLOR.YELLOW:
                                g += incv;
                                if ((int)g >= 255)
                                {
                                    setNowColor(COLOR.YELLOW);
                                    setAimColor();
                                }
                                break;
                            default: break;
                        }
                        break;
                    case COLOR.BLUE:
                        /*******************************************
                         *      青から赤へ
                         *******************************************/
                        switch (this.aimColor)
                        {
                            case COLOR.RED:
                                r += incv;
                                b = (b - incv < 0.0 ? 0.0 : b - incv);
                                if ((int)r >= 255)
                                {
                                    setNowColor(COLOR.RED);
                                    setAimColor();
                                }
                                break;
                            case COLOR.BLUE: break;
                            case COLOR.GREEN: break;
                            case COLOR.YELLOW: break;
                            default: break;
                        }
                        break;
                    case COLOR.GREEN:
                        /*******************************************
                         *      緑から青
                         *******************************************/
                        switch (this.aimColor)
                        {
                            case COLOR.RED: break;
                            case COLOR.BLUE:
                                b += incv;
                                g = (g - incv < 0.0 ? 0.0 : g - incv);
                                if ((int)b >= 255)
                                {
                                    setNowColor(COLOR.BLUE);
                                    setAimColor();
                                }
                                break;
                            case COLOR.GREEN: break;
                            case COLOR.YELLOW: break;
                            default: break;
                        }
                        break;
                    case COLOR.YELLOW:
                        /*******************************************
                         *      黄色から緑へ
                         *******************************************/
                        switch (this.aimColor)
                        {
                            case COLOR.RED: break;
                            case COLOR.BLUE: break;
                            case COLOR.GREEN:
                                r -= incv;
                                if ((int)r < 0)
                                {
                                    setNowColor(COLOR.GREEN);
                                    setAimColor();
                                }
                                break;
                            case COLOR.YELLOW: break;
                            default: break;
                        }
                        break;
                    default: break;
                }
            }
        };

        private Point startPoint;
        private Point endPoint;
        private Point[] oldPoint;
        private bool Twise; //二回クリック判定

        private GradientColor[] pColor;
        private uint cycleCount;

        public Range()
        {
            startPoint = new Point(0, 0);
            endPoint = new Point(0, 0);
            oldPoint = new Point[2];
            Twise = false;
            pColor = new GradientColor[4];
            
            /*****************************
             *    →| ̄ ̄|
             *       |    |
             *       |__|
             *      赤に設定
             ****************************/
            pColor[0].setNowColor(GradientColor.COLOR.RED);

            /*****************************
             *     | ̄ ̄|←
             *      |     |
             *      |__|
             *      青に設定
             ****************************/
            pColor[1].setNowColor(GradientColor.COLOR.BLUE);
            
            /*****************************
             *     | ̄ ̄|
             *      |     |
             *      |__|←
             *      緑に設定
             ****************************/
            pColor[2].setNowColor(GradientColor.COLOR.GREEN);
            
            /*****************************
             *       | ̄ ̄|
             *        |     |
             *     →|__|
             *    黄色に設定
             ****************************/
            pColor[3].setNowColor(GradientColor.COLOR.YELLOW);
            
        }

        public void notUsed()
        {
            Twise = false;
            startPoint.X = startPoint.Y = 0;
            endPoint.X = endPoint.Y = 0;
        }

        public Point getStartPoint()
        {
            return this.startPoint;
        }

        public Point getOldStartPoint()
        {
            return oldPoint[0];
        }

        public Point getOldEndPoint()
        {
            return oldPoint[1];
        }

        /***************************************************************
         *                      自作関数
         *              マップ用配列にマップ定数を格納する処理
         * ************************************************************/
        public int click(ref MapField map, int x, int y)
        {
            if ( !Twise )
            {
                oldPoint[0].X = startPoint.X = x / BLOCK_SIZE;
                oldPoint[0].Y = startPoint.Y = y / BLOCK_SIZE;
                Twise = true;
                return 2;
            }

            int isPush = 0;
            int sx, sy;
            int ex, ey;

            endPoint.X = x / BLOCK_SIZE;
            endPoint.Y = y / BLOCK_SIZE;

            sx = (startPoint.X <= endPoint.X ? startPoint.X : endPoint.X);
            ex = (startPoint.X > endPoint.X ? startPoint.X : endPoint.X);
            sy = (startPoint.Y <= endPoint.Y ? startPoint.Y : endPoint.Y);
            ey = (startPoint.Y > endPoint.Y ? startPoint.Y : endPoint.Y);

            for(int v = sy; v <= ey; v++)
            {
                for(int h = sx; h <= ex; h++)
                {
                    int ret = map.push_mapinfo(h, v, false);
                    if (ret > 0)
                        isPush = ret;
                }
            }

            oldPoint[0].X = startPoint.X;
            oldPoint[0].Y = startPoint.Y;
            oldPoint[1].X = endPoint.X;
            oldPoint[1].Y = endPoint.Y;

            startPoint.X = startPoint.Y = 0;
            endPoint.X = endPoint.Y = 0;
            
            Twise = false;
            return isPush;
        }

        /*********************************************************
         *  Drawing Image ... Gradient RectLine
         *  
         *              | ̄ ̄|
         *              |      |
         *              |__|
         *      
         ********************************************************/
        public void drawGradientRect(Graphics g)
        {
            Point p = startPoint;
            int x = p.X * BLOCK_SIZE;
            int y = p.Y * BLOCK_SIZE;
            int size = BLOCK_SIZE-1;

            Point []pa = new Point[5];
            
            //左端上
            pa[0].X = x + 1;
            pa[0].Y = y + 1;
            //右端上
            pa[1].X = x + size;
            pa[1].Y = y + 1;
            //右端下
            pa[2].X = x + size;
            pa[2].Y = y + size;
            //左端下
            pa[3].X = x + 1;
            pa[3].Y = y + size;
            //左端上
            pa[4].X = x + 1;
            pa[4].Y = y + 1;

            LinearGradientBrush gp1 = new LinearGradientBrush(
                    pa[0], pa[1],
                    Color.FromArgb(pColor[0].getR(), pColor[0].getG(), pColor[0].getB()),
                    Color.FromArgb(pColor[1].getR(), pColor[1].getG(), pColor[1].getB())
                );
            LinearGradientBrush gp2 = new LinearGradientBrush(
                    pa[1], pa[2],
                    Color.FromArgb(pColor[1].getR(), pColor[1].getG(), pColor[1].getB()),
                    Color.FromArgb(pColor[2].getR(), pColor[2].getG(), pColor[2].getB())
                );
            LinearGradientBrush gp3 = new LinearGradientBrush(
                    pa[2], pa[3],
                    Color.FromArgb(pColor[2].getR(), pColor[2].getG(), pColor[2].getB()),
                    Color.FromArgb(pColor[3].getR(), pColor[3].getG(), pColor[3].getB())
                );
            LinearGradientBrush gp4 = new LinearGradientBrush(
                    pa[3], pa[0],
                    Color.FromArgb(pColor[3].getR(), pColor[3].getG(), pColor[3].getB()),
                    Color.FromArgb(pColor[0].getR(), pColor[0].getG(), pColor[0].getB())
                );
            
            Pen pen1 = new Pen(gp1, 2.0f);       //幅2ピクセル
            pen1.DashStyle = DashStyle.Solid;     //ペンを直線に指定

            Pen pen2 = new Pen(gp2, 2.0f);       //幅2ピクセル
            pen1.DashStyle = DashStyle.Solid;     //ペンを直線に指定

            Pen pen3 = new Pen(gp3, 2.0f);       //幅2ピクセル
            pen1.DashStyle = DashStyle.Solid;     //ペンを直線に指定

            Pen pen4 = new Pen(gp4, 2.0f);       //幅2ピクセル
            pen1.DashStyle = DashStyle.Solid;     //ペンを直線に指定

            /*****************************
             * 
             *        ̄ ̄ ̄
             *      
             *      
             ****************************/
            g.DrawLine(pen1, pa[0], pa[1]);

            /*****************************
             * 
             *       ̄ ̄ ̄|
             *              |
             *               |
             *            
             ****************************/
            g.DrawLine(pen2, pa[1], pa[2]);

            /*****************************
             * 
             *       ̄ ̄ ̄|
             *              |
             *      ___|
             *      
             ****************************/
            g.DrawLine(pen3, pa[2], pa[3]);

            /*****************************
             * 
             *      | ̄ ̄|
             *      |     |
             *      |__|
             *      
             ****************************/
            g.DrawLine(pen4, pa[3], pa[0]);

            //リソースを解放
            pen1.Dispose();
            pen2.Dispose();
            pen3.Dispose();
            pen4.Dispose();

            gp1.Dispose();
            gp2.Dispose();
            gp3.Dispose();
            gp4.Dispose();

            /*****************************     
             *      色を更新
             ****************************/
            for (int i = 0; i < (int)GradientColor.COLOR.MAX; i++)
            {
                pColor[i].valueIncrement();
            }

            //計測
            cycleCount++;
            if (cycleCount % (1000 / 8) == 0)
                Console.WriteLine("timer count = " + cycleCount);
        }
    }
}