Matrix Rain help (poor performance)

RastHacker

Member
Joined
Oct 22, 2019
Messages
12
Programming Experience
1-3
Hi, i learn my self to making winforms in c# with vs 2015 since my 15 yo.

And today for fun i wanna make a matrix rain with rasta colors but in winform not console application.I have finished but i've got poor performance, and maybe because i'm not very good to C# coding ;D, to explain what i've done, i just have to show you ;D

(show below post 3 ...)

thanks for all the comunity for helping ;D (not registered but using this forum since a while ^^)
 
Last edited:
C#:
private void textBox1_TextChanged(object sender, EventArgs e)

{
    try

    {
        _spawnTimer.Interval = Int32.Parse(textBox1.Text);

        textBox1.BackColor = Color.White;
    }
    catch (Exception)

    {
        textBox1.BackColor = Color.Pink;
    }
}

public void addTimerToList(Timer _timer)

{
    _timerList.Add(_timer);
}
    }

    public class Spawn

{
    private Timer mainTimer = new Timer();

    private Graphics _myGraphics;

    private List<char> _charList = new List<char>();

    public bool _onSpawn = false;

    public bool _spawned = false;

    public bool _waitTo = false;

    public bool _onDespawn = false;

    private bool _isDespawing = false;

    private bool _deSpawnFinished = false;

    public int _width;

    public int _height;

    public int _x;

    public int _startY;

    private int _endY;

    public int _y;

    public int _colorValue;

    public int _currColorValue;

    public int _waitValue;

    private int _currWaitValue;

    public int _colorStepValue;

    public int _speedInterval = 1;

    private int _maxColorValue = 0;

    private int _previousColorValue = 0;

    private char _theChooserChar;

    private int _maxHeightValue;

    private int _currRepeatCount = 0;

    private int _currLocation;// = _startY - 10;

    private int _curr2 = 0;

    private Form2 _currForm;

    public Spawn(Form2 form1)

    {
        _currForm = form1;

        _currForm.addTimerToList(mainTimer);

        _maxHeightValue = _currForm.Height;// + _height*2;//_currForm.Height/2;

        _myGraphics = Graphics.FromHwnd(_currForm.Handle);

        _charList = getCharList();

        mainTimer.Interval = _speedInterval;

        mainTimer.Tick += MainTimer_Tick;
    }

    private List<char> getCharList()

    {
        var _result = new List<char>();

        foreach (char c in Properties.Resources.charList.ToCharArray())

        {
            _result.Add(c);
        }

        return _result;
    }

    private int getIndex()

    {
        int _result = 0;

        Random _getIndexRandom = new Random();

        _result = _getIndexRandom.Next(_charList.Count - 1);

        if (_result < 0)

        {
            _result = 0;
        }

        return _result;
    }
 
Last edited:
C#:
private void MainTimer_Tick(object sender, EventArgs e)

{
    if (_previousColorValue < _currColorValue)

    {
        _maxColorValue = _currColorValue;
    }

    _previousColorValue = _currColorValue;

    if (_deSpawnFinished)

    {
        mainTimer.Stop();
    }

    if (_isDespawing)

    {
        int _pathToTrace = _endY - _startY;

        int _repeatCount = 2;

        if (_currRepeatCount < _repeatCount)

        {
            if (_currLocation < _endY)

            {
                for (int i = 1; i < _repeatCount; i += 1)

                {
                    _currLocation += (_height / 4) * 3;

                    Rectangle _main = new Rectangle(_x, _y, _width, _height);

                    Rectangle _shadow = new Rectangle(_x, _currLocation, _width + (_width + 0), _height + 0);

                    Font _mainFont = new Font("Microsoft Sans Serif", _width - 6, System.Drawing.FontStyle.Regular,

                        System.Drawing.GraphicsUnit.Point, ((byte)(0)));

                    Color _selectedColor = new Color();

                    int _currCharIndex = getIndex();

                    if (_currColorValue - ((_currForm.Height / _height) * _height) > 0)

                    {
                        _currColorValue = _currColorValue - (((_currForm.Height / _height) * _height) / 2);
                    }
                    else

                    {
                        _currColorValue = 0;
                    }

                    _selectedColor = Color.FromArgb(150, 0, _currColorValue, 0);

                    //_myGraphics.FillRectangle(Brushes.Black, _main);

                    _myGraphics.FillRectangle(new SolidBrush(Color.FromArgb(new Random().Next(100, 200), 0, 0, 0)), _shadow);

                    //_myGraphics.DrawString(_charList[_currCharIndex].ToString(), _mainFont, new SolidBrush(Color.White), _main);

                    //_myGraphics.DrawString(_charList[_currCharIndex].ToString(), _mainFont,new SolidBrush(_selectedColor), _shadow);
                }

                _curr2 += 1;
            }
            else

            {
                _currLocation = _startY - 100;

                _currRepeatCount += 1;

                _curr2 = 0;
            }
        }
        else

        {
            _deSpawnFinished = true;
        }
    }
    else

    {
        if (_y < _maxHeightValue)//+ _height*2)

        {
            _y += (_height / 4) * 3;

            Rectangle _main = new Rectangle(_x, _y, _width, _height);

            Rectangle _shadow = new Rectangle(_x, _y - _height, _width, _height);

            Font _mainFont = new Font("Microsoft Sans Serif", _width - 6, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

            Color _selectedColor = new Color();

            int _currCharIndex = getIndex();

            if (_currColorValue - 10 > 0 && _currColorValue + 10 < 255)

            {
                _selectedColor = Color.FromArgb(0,

                    new Random().Next(_currColorValue - 10, _currColorValue + 10), 0);
            }
            else

            {
                if (_currColorValue > 100)

                {
                    _currColorValue = 255;
                }
                else

                {
                    _currColorValue = 0;
                }
            }

            _myGraphics.FillRectangle(Brushes.Black, _main);

            _myGraphics.FillRectangle(Brushes.Black, _shadow);

            _myGraphics.DrawString(_charList[_currCharIndex].ToString(), _mainFont, new SolidBrush(Color.White), _main);

            _myGraphics.DrawString(_charList[_currCharIndex].ToString(), _mainFont, new SolidBrush(_selectedColor), _shadow);
        }
        else

        {
        }

        if (_onSpawn)

        {
            if (_currColorValue < _colorValue)

            {
                _currColorValue += _colorStepValue;

                Rectangle _main = new Rectangle(_x, _y, _width, _height);

                Font _mainFont = new Font("Microsoft Sans Serif", _width - 6, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

                _myGraphics.FillRectangle(Brushes.Black, _main);

                _myGraphics.DrawString(_theChooserChar.ToString(), _mainFont, new SolidBrush(Color.FromArgb(0, _currColorValue, 0)), _main);
            }
            else

            {
                _onSpawn = false;

                //_spawned = true;

                _waitTo = true;

                _currWaitValue = 0;
            }
        }
        else

        {
            if (_spawned)

            {
                if (_waitTo)

                {
                    if (_currWaitValue < _waitValue)

                    {
                        //Console.WriteLine("Started wait to = " + _currWaitValue + " / " + _waitValue);

                        _currWaitValue += 1;
                    }
                    else

                    {
                        //Console.WriteLine("Finished wait to");

                        _waitTo = false;

                        _endY = _y;

                        _currLocation = _startY - 100;

                        _isDespawing = true;

                        mainTimer.Interval = 1;

                        //_onDespawn = true;
                    }
                }
                else

                {
                    if (_onDespawn)

                    {
                        if (!(_currColorValue - _colorStepValue < 0))

                        {
                            _currColorValue -= _colorStepValue;

                            /*int _xVar = _currForm.Height / _height;

                            int _xFunc = _xVar * _height;

                            for (int i = 1; i < _xFunc + 1; i += 1)

                            {
                                //System.Threading.Thread.Sleep(1);

                                Rectangle _despawnShadow = new Rectangle(_x, _y + 100 - _height * i, _width, _height);

                                Font _mainFont = new Font("Microsoft Sans Serif", _width - 6, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

                                int _colorDespawnValue = (_maxColorValue / i);

                                int _currCharIndex = getIndex();

                                if (!((_currColorValue - _colorDespawnValue) > 0))

                                {
                                    _currColorValue = 0;
                                }

                                _myGraphics.FillRectangle(Brushes.Black, _despawnShadow);

                                _myGraphics.DrawString(_charList[_currCharIndex].ToString(), _mainFont, new SolidBrush(Color.FromArgb(0, _currColorValue, 0)), _despawnShadow);
                            }*/
                        }
                        else

                        {
                            _currColorValue = 0;

                            _onSpawn = false;

                            _spawned = false;

                            _waitTo = false;

                            _onDespawn = false;
                        }
                    }
                    else

                    {
                        mainTimer.Stop();
                    }
                }
            }
            else

            {
            }
        }
    }
}

public void _startSpawn()

{
    _startY = _y;

    mainTimer.Start();
}
}
 
Some quick and dirty code to do my preferred version of digital rain:
MainForm.cs:
using System;
using System.Drawing;
using System.Windows.Forms;

namespace WinFormsDigitalRain
{
    class MainForm : Form
    {
        readonly Timer _timer = new Timer();
        readonly Scene _scene;
        readonly Font _font = new Font("Consolas", 12.0f, FontStyle.Regular);
        readonly SolidBrush[] _brush = new SolidBrush[256];

        public MainForm(bool fullScreen)
        {
            FormBorderStyle = FormBorderStyle.None;
            BackColor = Color.Black;
            DoubleBuffered = true;
            Bounds = GetScreenBounds();
            KeyPress += (o, e) => Close();
            Click += (o, e) => Close();
            Paint += (o, e) => Render(e.Graphics);

            CreateBrushes();
            _scene = new Scene(100, ClientSize, GetFontWidth(), _font.Height, _brush.Length - 1);

            _timer.Interval = 100;
            _timer.Tick += (o, e) => { _scene.Update(); Invalidate(); };
            _timer.Start();

            Rectangle GetScreenBounds()
            {
                var bounds = Screen.FromControl(this).Bounds;
                if (!fullScreen)
                {
                    bounds.Width /= 2;
                    bounds.Height /= 2;
                }
                return bounds;
            }

            int GetFontWidth()
            {
                using (var g = this.CreateGraphics())
                    return (int)g.MeasureString("W", _font).Width;
            }

            void CreateBrushes()
            {
                for (int i = 0; i < _brush.Length - 1; i++)
                    _brush[i] = new SolidBrush(Color.FromArgb(0, i, 0));
                _brush[_brush.Length - 1] = new SolidBrush(Color.White);
            }
        }

        void Render(Graphics g)
        {
            SetGraphicsToMirror();
            foreach (var glyph in _scene.Glyphs)
                g.DrawString(glyph.Char, _font, _brush[glyph.Brightness], glyph.Position.X, glyph.Position.Y);

            void SetGraphicsToMirror()
            {
                g.TranslateTransform(Bounds.Width, 0);
                g.ScaleTransform(-1, 1);
            }
        }

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm(true));
        }
    }
}

Scene.cs:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace WinFormsDigitalRain
{
    class Scene
    {
        static Random _random = new Random();

        readonly Column[] _columns;
        readonly List<Glyph> _glyphs = new List<Glyph>();
        readonly Queue<Glyph> _recyle = new Queue<Glyph>();
        int _columnCount;
        int _screenHeight;
        int _fontWidth;
        int _brightest;
        bool _updating;

        public IEnumerable<Glyph> Glyphs => _glyphs.Where(g => g.IsAlive);

        public Scene(int activeColumnCount, Size screen, int fontWidth, int fontHeight, int brightest)
        {
            _screenHeight = screen.Height;
            _fontWidth = fontWidth;
            _brightest = brightest;

            _columnCount = screen.Width / fontWidth + 1;
            _columns = Enumerable.Range(0, activeColumnCount)
                                 .Select(_ => new Column(fontHeight))
                                 .ToArray();
        }

        void CreateNewColumns()
        {
            foreach(var column in _columns.Where(c => !c.IsAlive))
                column.Initialize(_random.Next(_columnCount) * _fontWidth, _random.Next(_screenHeight));
        }

        void AgeExistingGlyphs()
        {
            foreach (var glyph in _glyphs)
            {
                if (!glyph.Update())
                    _recyle.Enqueue(glyph);
            }
        }

        void CreateGlyph(Point position)
        {
            Glyph glyph;
            if (_recyle.Count > 0)
            {
                glyph = _recyle.Dequeue();
            }
            else
            {
                glyph = new Glyph();
                _glyphs.Add(glyph);
            }
            glyph.Initialize(position, _brightest);
        }

        void CreateNewGlyphs()
        {
            foreach (var column in _columns)
            {
                if (column.Update())
                    CreateGlyph(column.Position);
            }
        }

        public void Update()
        {
            if (!_updating)
            {
                _updating = true;
                CreateNewColumns();
                AgeExistingGlyphs();
                CreateNewGlyphs();
                _updating = false;
            }
        }
    }
}

Column.cs:
using System;
using System.Drawing;

namespace WinFormsDigitalRain
{
    class Column
    {
        static Random _random = new Random();

        int _maxY = 0;
        Point _position;
        int _fontHeight;

        public Point Position => _position;
        public bool IsAlive => Position.Y < _maxY;

        public Column(int fontHeight)
            => _fontHeight = fontHeight;

        public void Initialize(int x, int maxY)
        {
            _position = new Point(x, 0);
            _maxY = maxY;
        }

        public bool Update()
        {
            if (_random.Next(100) < 33)
                return false;

            _position.Y += _fontHeight;
            return true;
        }
    }
}


Glyph.cs:
using System;
using System.Collections.Generic;
using System.Drawing;

namespace WinFormsDigitalRain
{
    class Glyph
    {
        static Random _random = new Random();
        static List<string> _pool = new List<string>();
        
        static Glyph()
        {
            AddCharRangeToPool(0x0020, 0x007F); // ASCII
//            AddCharRangeToPool(0x00A0, 0x024F); // Latin-1, Latin Extended-A, Latin Extended-B
//            AddCharRangeToPool(0x0370, 0x03FF); // Greek
//            AddCharRangeToPool(0x0400, 0x04FF); // Cyrillic
            AddCharRangeToPool(0xFF61, 0xFF9F); // Halfwidth Katakana
        }

        static void AddCharRangeToPool(int low, int high)
        {
            for (char ch = (char)low; ch < (char)high; ch++)
            {
                if (!char.IsWhiteSpace(ch))
                    _pool.Add(ch.ToString());
            }
        }

        public string Char { get; private set; } = String.Empty;
        public Point Position { get; private set; }
        public int Brightness { get; private set; } = 0;

        public bool IsAlive => Brightness > 0;

        public void Initialize(Point position, int brightest)
        {
            Position = position;
            Brightness = brightest;
            RandomizeGlyph();
        }

        void RandomizeGlyph()
            => Char = _pool[_random.Next(_pool.Count)];

        public bool Update()
        {
            if (_random.Next(100) < 5)
                RandomizeGlyph();

            Brightness -= 10;
            return IsAlive;
        }
    }
}

As I said, the code above is quick and dirty. There are still lots of embedded magic numbers/strings which should be moved into the app.config.

I'm not experiencing any lagging from the code above until I start doing more than 3000 active columns at the same time. And that's on an old PC built in 2012. On my newer laptop I can go up even higher. From my analysis, the lagging I'm getting is the sheer number of glyphs that need to be updated and drawn, and not due to garbage collection pauses. Of course, with those many columns, the display is not as aethetistically pleasing anymore.
 
Hello everyone!!
GOOD YEAR!!

I want to thanks you all for your help. After many tries here what it look like ;D

( The only control used in code is panel1, its a classic panel nothing special, if u want full source code i can post it here ;D )

C#:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Timer = System.Windows.Forms.Timer;

namespace Moving_Particles
{
    public partial class Form1 : Form
    {
        BackgroundWorker worker = new BackgroundWorker();
        Timer workerLoop = new Timer();
        Timer renderLoop = new Timer();

        private Bitmap renderBitmap;
        private Graphics finalGraphics;
      
        List<DrawElement> ElementsList = new List<DrawElement>();
        Random randomVar = new Random();

        private int minElements = 20;
        private int currMaxElements = 40;
        private int maxElement = 150;

        private int timeToUpMaxElement = 10;
        private int currTime = 0;

        private string CharactersToChoose = "ハミヒーウシナモニサワツオリアホテマケメエカキムユラセネスタヌヘヲイクコソチトノフヤヨルレロン";

        List<char> getKanas()
        {
            return CharactersToChoose.ToCharArray().ToList();
        }

        Char getRandomKana()
        {
            List<char> kanas = getKanas();

            char result = kanas[randomVar.Next(0, kanas.Count - 1)];

            return result;
        }

        public Form1()
        {
            SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
            UpdateStyles();

            InitializeComponent();

            worker.DoWork += Worker_DoWork;
            worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
            workerLoop.Tick += WorkerLoop_Tick;
            renderLoop.Tick += RenderLoop_Tick;

            workerLoop.Interval = 50;
            renderLoop.Interval = 60;

            panel1.MouseDoubleClick += Panel1_MouseDoubleClick;
        }

        private void Panel1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                finalGraphics = panel1.CreateGraphics();
                renderBitmap = new Bitmap(panel1.Width, panel1.Height);

                workerLoop.Start();
                renderLoop.Start();

                //addCursorTracker();

                AddUnlimitedMatrixChars(100);
            }
        }

        async private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Bitmap bitRender = e.Result as Bitmap;
            await DrawRenderPic(bitRender);
        }

        async Task DrawRenderPic(Bitmap referPic)
        {
            Graphics rGraph = Graphics.FromImage(renderBitmap);

            rGraph.DrawImageUnscaled(referPic, new Point(0, 0));
            rGraph.Dispose();
            referPic.Dispose();
        }

        private void RenderLoop_Tick(object sender, EventArgs e)
        {
            finalGraphics.DrawImageUnscaled(renderBitmap,new Point(0,0));
        }

        private void WorkerLoop_Tick(object sender, EventArgs e)
        {
            if (!worker.IsBusy)
            {
                worker.RunWorkerAsync();

                if (currTime < timeToUpMaxElement)
                {
                    currTime += 1;
                }
                else
                {
                    currTime = 0;
                    if (currMaxElements < maxElement)
                    {
                        currMaxElements += 1;
                    }
                }
            }
            else
            {
                if (currMaxElements > minElements)
                {
                    currMaxElements -= 1;
                    currTime = 0;
                }
            }
        }

        private void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            Bitmap tempPic = new Bitmap(panel1.Width,panel1.Height);
            List<DrawElement> tempList = new List<DrawElement>();
            Graphics tempPicGraphs = Graphics.FromImage(tempPic);

            tempList.AddRange(ElementsList);

            tempPicGraphs.Clear(panel1.BackColor);

            foreach (DrawElement drawElement in tempList)
            {
                drawElement.Draw(tempPicGraphs);

                if (drawElement.DeleteMySelf)
                {
                    ElementsList.Remove(drawElement);
                }
            }

            e.Result = tempPic;
            tempPicGraphs.Dispose();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
          
        }

        void AddMatrixChars(int count)
        {
            Timer t = new Timer();

            t.Interval = 500;

            int curr = 0;

            t.Tick += delegate(object sender, EventArgs args)
            {
                if (curr < count)
                {
                    curr += 1;
                    addMatrixChar();
                }
                else
                {
                    t.Stop();
                }
            };

            t.Start();
        }

        void AddUnlimitedMatrixChars(int interval)
        {
            Timer t = new Timer();

            t.Interval = interval;

            int curr = 0;

            t.Tick += delegate (object sender, EventArgs args)
            {
                if (ElementsList.Count < currMaxElements)
                {
                    addMatrixChar();
                }
                this.Text = ElementsList.Count + "/" + currMaxElements;
            };

            t.Start();
        }

        void addCursorTracker()
        {
            DrawElement el = new DrawElement();

            el.Location = new PointF(10,10);
            el.Size = new SizeF(20,20);
            el.BackColor = Color.Red;

            float x = 10;
            float y = 10;

            panel1.MouseMove += delegate(object sender, MouseEventArgs args)
            {
                x = args.X;
                y = args.Y;
            };

            Action<Graphics> draw = delegate(Graphics graphics)
            {
              
            };

            Action update = delegate
            {
                el.Location = new PointF(x,y);
            };

            el.DrawAction = draw;
            el.Update = update;

            ElementsList.Add(el);
        }

        void addAutoMovingBall()
        {
            DrawElement el = new DrawElement();

            el.Location = getRandomPoint();

            int randomSize = new Random().Next(10,30);

            el.Size = new SizeF(randomSize, randomSize);
            el.BackColor = getRandomColor(0,255);

            int timeToCChange = 1;
            int currentTime = 0;

            int timeToBlink = 2;
            int currBlink = 0;

            bool blink = false;
            bool follow = false;

            Color desiredColor = getRandomColor(155,255);

            float Speed = new Random().Next(1,2);

            PointF Destination = getRandomPoint();

            panel1.MouseDoubleClick += delegate(object sender, MouseEventArgs args)
            {
                if (args.Button == MouseButtons.Left)
                {
                    //Destination = new PointF(args.X,args.Y);
                    follow = !follow;
                }
            };

            panel1.MouseMove += delegate(object sender, MouseEventArgs args)
            {
                if (follow)
                {
                    Destination = new PointF(args.X,args.Y);
                }
            };

            Action<Graphics> draw = delegate (Graphics graphics)
            {
                graphics.SmoothingMode = SmoothingMode.AntiAlias;

                float step = el.Size.Width / 2;
                int count = 0;

                int minAlpha = 10;
                int checkAlpha = 100;
                bool reverse = false;

                Color baseColor = el.BackColor;

                for (float i = 0; i < step; i+=1)
                {
                    RectangleF r = new RectangleF((el.Location.X)+(el.Size.Width / 2) - i, (el.Location.Y)+(el.Size.Height / 2) - i, (i * 2), (i * 2));

                    int iInt32 = (int) i;

                    int alpha = fixColor(150)-((150/((int)step))*((int)i));
                    int red = fixColor(baseColor.R - iInt32 * 2);
                    int green = fixColor(baseColor.G - iInt32 * 2);
                    int blue = fixColor(baseColor.B - iInt32 * 2);

                    Color toApply = Color.FromArgb(alpha, red, green, blue);

                    //g.FillEllipse(new SolidBrush(toApply), r);
                    graphics.DrawEllipse(new Pen(toApply, 1.9f), r);
                }
            };

            Action update = delegate
            {
                bool xOk = false;
                bool yOk = false;

                bool redOk = false;
                bool greenOk = false;
                bool blueOk = false;

                int newRed = el.BackColor.R;
                int newGreen = el.BackColor.G;
                int newBlue = el.BackColor.B;

                int StepC = 1;

                if (currentTime < timeToCChange)
                {
                    currentTime += 1;
                }
                else
                {
                    currentTime = 0;

                    if (el.BackColor.R > desiredColor.R)
                    {
                        newRed = el.BackColor.R - StepC;
                    }
                    else
                    {
                        if (el.BackColor.R < desiredColor.R)
                        {
                            newRed = el.BackColor.R + StepC;
                        }
                        else
                        {
                            if (el.BackColor.R == desiredColor.R)
                            {
                                redOk = true;
                            }
                        }
                    }

                    if (el.BackColor.G > desiredColor.G)
                    {
                        newGreen = el.BackColor.G - StepC;
                    }
                    else
                    {
                        if (el.BackColor.G < desiredColor.G)
                        {
                            newGreen = el.BackColor.G + StepC;
                        }
                        else
                        {
                            if (el.BackColor.G == desiredColor.G)
                            {
                                greenOk = true;
                            }
                        }
                    }

                    if (el.BackColor.B > desiredColor.B)
                    {
                        newBlue = el.BackColor.B - StepC;
                    }
                    else
                    {
                        if (el.BackColor.B < desiredColor.B)
                        {
                            newBlue = el.BackColor.B + StepC;
                        }
                        else
                        {
                            if (el.BackColor.B == desiredColor.B)
                            {
                                blueOk = true;
                            }
                        }
                    }

                    el.BackColor = Color.FromArgb(newRed, newGreen, newBlue);

                    if (redOk && greenOk && blueOk)
                    {
                        if (currBlink < timeToBlink)
                        {
                            currBlink += 1;
                            desiredColor = getRandomColor(155, 255);
                        }
                        else
                        {
                            currBlink = 0;
                            desiredColor = Color.Black;
                        }
                      
                    }
                }

                if (el.Location.X < Destination.X)
                {
                    el.Location.X += Speed;
                }
                else
                {
                    if (el.Location.X > Destination.X)
                    {
                        el.Location.X -= Speed;
                    }
                    else
                    {
                        if (el.Location.X == Destination.X)
                        {
                            xOk = true;
                        }
                    }
                }
                if (el.Location.Y < Destination.Y)
                {
                    el.Location.Y += Speed;
                }
                else
                {
                    if (el.Location.Y > Destination.Y)
                    {
                        el.Location.Y -= Speed;
                    }
                    else
                    {
                        if (el.Location.Y == Destination.Y)
                        {
                            yOk = true;
                        }
                    }
                }

                if (xOk && yOk)
                {
                    Destination = getRandomPoint();
                }
            };

            el.DrawAction = draw;
            el.Update = update;

            ElementsList.Add(el);
        }

        void addMatrixChar()
        {
            DrawElement el = new DrawElement();

            el.Location = new PointF(randomVar.Next(0,panel1.Width), -350);
            el.Size = new SizeF(20, 20);
            el.BackColor = Color.White;

            int step = randomVar.Next(3,15);
            float fStep = (float) (step/10);

            int kanaChangeTime = 2;
            int currKanaChange = 0;

            float textWidth = randomVar.Next(8, 32);

            int shadowCount = randomVar.Next(6,31);
          
            Action<Graphics> draw = delegate (Graphics graphics)
            {
                string character = el.Tag.ToString();
                GraphicsPath gp = new GraphicsPath();

                gp.AddString(character, this.Font.FontFamily, 0, textWidth, el.Location, StringFormat.GenericDefault);

                for (int i = 1; i < shadowCount; i++)
                {
                    string shadowChar = "";

                    int shadowTagIndex = (el.TagHistory.Count - 1) - i;
                    if (shadowTagIndex >= 0)
                    {
                        shadowChar = el.TagHistory[shadowTagIndex].ToString();
                    }

                    GraphicsPath gpShadow = new GraphicsPath();
                    int alpha = 255 - ((230/shadowCount)*i);

                    float yLocation = el.Location.Y - (((float)(textWidth*1.2))*i);

                    gpShadow.AddString(shadowChar, this.Font.FontFamily, 0, textWidth, new PointF(el.Location.X,yLocation), StringFormat.GenericDefault);
                    graphics.FillPath(new SolidBrush(Color.FromArgb(alpha,Color.Green)), gpShadow);
                }

                int maxHalo = ((int)(textWidth / 2));

                if (maxHalo > 9)
                {
                    maxHalo = 9;
                }

                for (int i = 1; i < maxHalo; ++i)
                {
                    Pen pen = new Pen(Color.FromArgb(32, el.BackColor), i);
                    pen.LineJoin = LineJoin.Round;
                    graphics.DrawPath(pen, gp);
                    pen.Dispose();
                }

                graphics.FillPath(new SolidBrush(el.BackColor), gp);
            };

            Action update = delegate
            {
                if (el.Location.Y < panel1.Height + ((float)(textWidth * 1.2) * shadowCount))
                {
                    el.Location.Y += step;
                    if (currKanaChange < kanaChangeTime)
                    {
                        currKanaChange += 1;
                    }
                    else
                    {
                        currKanaChange = 0;
                        el.AddTag(getRandomKana().ToString());
                    }
                }
                else
                {
                    el.DeleteMySelf = true;
                }
            };

            el.AddTag(getRandomKana().ToString());

            el.DrawAction = draw;
            el.Update = update;

            ElementsList.Add(el);
        }

        void addErrorMatrixChar()
        {
            DrawElement el = new DrawElement();

            el.Location = new PointF(randomVar.Next(0, panel1.Width), -350);
            el.Size = new SizeF(20, 20);
            el.BackColor = Color.DarkRed;

            int step = randomVar.Next(3, 15);
            float fStep = (float)(step / 10);

            int kanaChangeTime = 2;
            int currKanaChange = 0;

            float textWidth = randomVar.Next(8, 32);

            int shadowCount = randomVar.Next(6, 31);

            Action<Graphics> draw = delegate (Graphics graphics)
            {
                string character = el.Tag.ToString();
                GraphicsPath gp = new GraphicsPath();

                gp.AddString(character, this.Font.FontFamily, 0, textWidth, el.Location, StringFormat.GenericDefault);

                for (int i = 1; i < shadowCount; i++)
                {
                    string shadowChar = "";

                    int shadowTagIndex = (el.TagHistory.Count - 1) - i;
                    if (shadowTagIndex >= 0)
                    {
                        shadowChar = el.TagHistory[shadowTagIndex].ToString();
                    }

                    GraphicsPath gpShadow = new GraphicsPath();
                    int alpha = 255 - ((230 / shadowCount) * i);

                    float yLocation = el.Location.Y - (((float)(textWidth * 1.2)) * i);

                    gpShadow.AddString(shadowChar, this.Font.FontFamily, 0, textWidth, new PointF(el.Location.X, yLocation), StringFormat.GenericDefault);
                    graphics.FillPath(new SolidBrush(Color.FromArgb(alpha, Color.Green)), gpShadow);
                }

                for (int i = 1; i < 14; ++i)
                {
                    Pen pen = new Pen(Color.FromArgb(16, el.BackColor), i);
                    pen.LineJoin = LineJoin.Round;
                    graphics.DrawPath(pen, gp);
                    pen.Dispose();
                }

                graphics.FillPath(new SolidBrush(el.BackColor), gp);
            };

            Action update = delegate
            {
                if (el.Location.Y < panel1.Height + ((float)(textWidth * 1.2) * shadowCount))
                {
                    el.Location.Y += step;
                    if (currKanaChange < kanaChangeTime)
                    {
                        currKanaChange += 1;
                    }
                    else
                    {
                        currKanaChange = 0;
                        el.AddTag(getRandomKana().ToString());
                    }
                }
                else
                {
                    el.DeleteMySelf = true;
                }
            };

            el.AddTag(getRandomKana().ToString());

            el.DrawAction = draw;
            el.Update = update;

            ElementsList.Add(el);
        }

        PointF getRandomPoint()
        {
            return new PointF(randomVar.Next(0,panel1.Width),randomVar.Next(0,panel1.Height));
        }

        Color getRandomColor(int min,int max)
        {
            return Color.FromArgb(randomVar.Next(min,max),randomVar.Next(min,max),randomVar.Next(min,max));
        }

        int fixColor(int input)
        {
            int result = 0;

            if (input < 0)
            {
                result = 0;
            }
            else
            {
                if (input > 254)
                {
                    result = 254;
                }
                else
                {
                    result = input;
                }
            }

            return result;
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {

        }
    }

    public class DrawElement
    {
        public PointF Location;
        public SizeF Size;
        public Color BackColor;
        public Object Tag;

        public Action<Graphics> DrawAction;
        public Action Update;

        public List<Object> TagHistory = new List<object>();

        public bool DeleteMySelf = false;

        public DrawElement()
        {
          
        }

        public void AddTag(string tagString)
        {
            if (Tag != null)
            {
                TagHistory.Add(Tag);
                Tag = tagString;
            }
            else
            {
                Tag = tagString;
            }
        }

        async public void Draw(Graphics g)
        {
            DrawAction(g);
            Update();
        }
    }
}

Here's result (as a gif converted from mp4)

ezgif-2-f36cc3098b.gif


And again sorry for my bad english ;D
 
Last edited by a moderator:
Have you tried using a profiler on your code to narrow down where the time is being spent?

Or if you don't have a profiler, have you tried isolating which bit of code is slow? Just scanning the code on my phone, it looks like your have two or three different types of animation all running.
 
Have you tried using a profiler on your code to narrow down where the time is being spent?

Or if you don't have a profiler, have you tried isolating which bit of code is slow? Just scanning the code on my phone, it looks like your have two or three different types of animation all running.

I don't know how to use profiler, i learn c# by myself with tutos, i'll investigate more on that profiler, what do you mean with "it looks like your have two or three different types of animation all running" ?
 
Has it really been 5.5 years in the making ?

Nope ^^, when im bored to do useful softwares i make useless, like matrix rain just for fun.
The goal here was to generate bitmap async and render it smooth. (like double bufferring) and i love that but i don't know how to optimize more the generation.

I've seen a dev making a Switch emulator on windows with c#, so a simple smooth matrix rain...
 
I don't know how to use profiler, i learn c# by myself with tutos, i'll investigate more on that profiler, what do you mean with "it looks like your have two or three different types of animation all running" ?

 
what do you mean with "it looks like your have two or three different types of animation all running" ?

As I was scanning through the code, I saw multiple el.Update = update; lines. That suggested to me that you have multiple kinds of drawing happening.
 
Back
Top Bottom