Matrix Rain help (poor performance)

RastHacker

Member
Joined
Oct 22, 2019
Messages
8
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:
Hi, and welcome to the forums.

Nobody is going to download those files. Instead, show your code, and explain the problem you are facing and then ask a specific question.

Instead of posting links to rar files, post a screenshot or two of what you're trying to create, or achieved in making. Do not post screenshots of code, and please post your relevant code in code tags.
 
Okay thanks for reply, i've remaking a washed version of the first to show you my problem (and i will/have remove(d) the rar links)
 
Here Form1.cs :

Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Matrix2
{
    public partial class Form1 : Form
    {
        List<System.Threading.Thread> threadList = new List<System.Threading.Thread>();

        private System.Threading.Thread _createThread;
        private System.Threading.Thread _fallingThread;

        private bool createBool = true;

        public Form1()
        {
            InitializeComponent();

            threadList.Add(_createThread);
            threadList.Add(_fallingThread);

            _createThread = new System.Threading.Thread(createThread_Loop);
            _fallingThread = new System.Threading.Thread(fallingThread_Loop);

            this.Closing += Form1_Closing;
            this.ControlAdded += Form1_ControlAdded;
        }

        private void Form1_ControlAdded(object sender, ControlEventArgs e)
        {
            //Console.WriteLine("added" + e.Control.Name);
        }

        private void Form1_Closing(object sender, CancelEventArgs e)
        {
            e.Cancel = true;

            foreach (var thread in threadList)
            {
                try
                {
                    thread.Abort();
                }
                catch (Exception)
                {
                   
                }
            }
            System.Diagnostics.Process.GetCurrentProcess().Kill();

            e.Cancel = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _createThread.Start();
            _fallingThread.Start();
        }

        async Task<List<char>> getCharList()
        {
            List<char> _result = new List<char>();

            foreach (char c in File.ReadAllText(Application.StartupPath + "\\charList.txt").ToCharArray())
            {
                _result.Add(c);
            }

            return _result;
        }

        async Task<int> threadLoopSpleep()
        {
            int result = 0;

            result = (3 * (this.Controls.Count / 4)) / 2;

            return result;
        }

        async Task<int> getNewRandom(int start, int end)
        {
            int result = new Random().Next(start, end);

            return result;
        }

        async void createThread_Loop()
        {
            var _cList = await getCharList();

            int count = 0;

            Random _rand1 = new Random(25);
            Random _rand2 = new Random(10);

            while (createBool)
            {
                System.Threading.Thread.Sleep(await threadLoopSpleep());

                Label label = new Label();

                string _text = _cList[new Random().Next(_cList.Count - 1)].ToString();

                label.Name = "label_N°" + this.Controls.Count;
                label.ForeColor = Color.White;
                label.Text = _text.First().ToString();
                label.AutoSize = true;
                label.TextAlign = ContentAlignment.MiddleCenter;
                label.Font = new Font("Microsoft Sans Serif", (_rand1.Next(5,30)),
                    System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                label.Location = new Point(_rand2.Next(this.Width), 0);
                label.Tag = "_main";

                Invoke((MethodInvoker)delegate ()
                {
                    this.Controls.Add(label);
                    if (count > 10)
                    {
                        //debug = false;
                    }
                    else
                    {
                        count += 1;
                    }
                });
            }
        }

        async void fallingThread_Loop()
        {
            var _cList = await getCharList();

            int _step = 20;

            while (true)
            {
                System.Threading.Thread.Sleep(30);

                string _consoleResult = "ControlsCount=" + this.Controls.Count;

               
                Console.WriteLine(_consoleResult);

                foreach (Control control in this.Controls)
                {
                    if (control.Tag.ToString() == "_main")
                    {
                        if (control.Location.Y < this.Height)
                        {
                            Label _shadowLabel = await createLabel(control as Label);
                            Timer _disapearT = new Timer();

                            _disapearT.Interval = 10;

                            _disapearT.Tick += delegate (object sender, EventArgs args)
                            {
                                if (_shadowLabel.ForeColor.G < _step)
                                {
                                    Invoke((MethodInvoker)delegate ()
                                    {
                                        _shadowLabel.ForeColor = Color.FromArgb(_shadowLabel.ForeColor.R, 0, _shadowLabel.ForeColor.B);
                                        _disapearT.Stop();
                                        this.Controls.Remove(_shadowLabel);
                                    });
                                   
                                }
                                else
                                {
                                    Invoke((MethodInvoker)delegate ()
                                    {
                                        _shadowLabel.ForeColor = Color.FromArgb(_shadowLabel.ForeColor.R, _shadowLabel.ForeColor.G - _step, _shadowLabel.ForeColor.B);
                                    });
                                }
                            };

                            Invoke((MethodInvoker)delegate ()
                            {
                                this.Controls.Add(_shadowLabel);
                                _disapearT.Start();
                                control.Location = new Point(control.Location.X,control.Location.Y + control.Height);
                                (control as Label).Text =
                                    _cList[new Random().Next(_cList.Count - 1)].ToString().First().ToString();
                            });
                        }
                        else
                        {
                            Invoke((MethodInvoker)delegate ()
                            {
                                this.Controls.Remove(control);
                            });
                        }
                    }
                }
            }
        }

        async Task<Label> createLabel(Label baseLabel)
        {
            Label label = new Label();

            int _step = 1;
            string _text = baseLabel.Text;

            Random _rand3 = new Random(15);

            label.Name = "label_N°" + this.Controls.Count;
            label.ForeColor = Color.FromArgb(0,_rand3.Next(75,195),0);
            label.Text = _text.First().ToString();
            label.AutoSize = true;
            label.TextAlign = ContentAlignment.MiddleCenter;
            label.Font = baseLabel.Font;
            label.Location = baseLabel.Location;
            label.Tag = "_shadow";

            return label;
        }
    }
}

and here short video (not real time speed but laggy) : click here to show on youtube ->
and here short video with my first version even more laggy : click here to show on youtube ->
 
Last edited:
The basic issue here is your architecture choices:
- Using multiple labels instead of painting the characters yourself in the paint handler
- Using multiple timers

Since you are instantiating multiple labels and timers, the pauses that you are seeing are likely due to garbage collection phases that the .NET Framework has to go through to free up more memory.

Also be aware that Windows has limits on the number of timers you can have, as well as, the number of windows you can have.
 
@Skydiver thanks for your reply i remaked the code with you're tells and it's realy better performance ;D

But i face an other problem :/ I want to remove only one Rectangle from control and not clear all Graphics.

Example :

C#:
public class Symbole
    {
        Thread _sThread;
        private Form1 _baseForm;
        private Rectangle _baseRectangle;

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

        public Symbole(Form1 baseform)
        {
            _sThread = new Thread(sThread_Loop);

            _baseForm = baseform;
            _baseRectangle = new Rectangle();
        }

        async private void sThread_Loop()
        {
            while (true)
            {
                Thread.Sleep(100);

                if (_baseRectangle.Y < _baseForm.Height)
                {
                    _baseRectangle.Y += _baseRectangle.Height;
                }
                else
                {
                    //remove _baseRectangle from _baseForm
                }
            }
        }

        async private Task<List<char>> getCharList()
        {
            List<char> _result = new List<char>();

            foreach (char c in Properties.Resources.charList.ToCharArray())
            {
                _result.Add(c);
            }

            return _result;
        }

        async private Task<int> getNewRandom(int _i1, int _i2)
        {
            int result = 0;

            result = new Random(new Random().Next()).Next(_i1, _i2);

            return result;
        }

        async private Task<char> getNewChar()
        {
            char _result = ' ';
            int index = await getNewRandom(0, (_charList.Count - 1));

            _result = _charList[index];

            return _result;
        }
    }
 
So why not just draw a filled rectangle that has the same color as the background?

As an aside, you don't really need threads to accomplish this project.
 
With a simple timer ? Thread as better performance and it abort at end ?
I'll try timer.

I've got an other problem, an unexpected error.

In Form1 paint event handler i said :
C#:
Graphics myGraphics;

private void Form1_Paint(object sender, PaintEventArgs e)
        {
            myGraphics = e.Graphics;
        }
and from an other class :

C#:
public class Symbole
    {
        private Form1 _baseForm;
        private Rectangle _baseRectangle;
        private Graphics _graphics;

        int _random1 = 0;
        int _random2 = 0;
        string _text = "";

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

        public Symbole(Form1 baseform)
        {
            _sThread = new Thread(sThread_Loop);

            _charList = getCharList().Result;

            _baseForm = baseform;
            _graphics = _baseForm.getCurrentGraphics(); // return myGraphics from _baseForm
        }

        async public void addSymbole()
        {
            _random1 = await getNewRandom(0, _baseForm.Width);
            _random2 = await getNewRandom(10, 30);
            _text = (await getNewChar()).ToString();

            _baseRectangle = new Rectangle(_random1,10,_random2,_random2);
            _graphics.FillRectangle(Brushes.Black,_baseRectangle); // Exception thrown: 'System.ArgumentException' in System.Drawing.dll Additional information: Invalid parameter.           
        }

        // more code below but cleared for example
    }

And i don't know why ?
 
Thread as better performance and it abort at end
From your code and post, you seem to have a fascination with Thread Abort. Thread abort should be used with extreme caution, because it can have undesired effects....also read up on the docs for timers :
Be aware that .NET includes four classes named Timer, each of which offers different functionality:
  • System.Timers.Timer (this topic): fires an event at regular intervals. The class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
  • System.Threading.Timer: executes a single callback method on a thread pool thread at regular intervals. The callback method is defined when the timer is instantiated and cannot be changed. Like the System.Timers.Timer class, this class is intended for use as a server-based or service component in a multithreaded environment; it has no user interface and is not visible at runtime.
  • System.Windows.Forms.Timer (.NET Framework only): a Windows Forms component that fires an event at regular intervals. The component has no user interface and is designed for use in a single-threaded environment.
  • System.Web.UI.Timer (.NET Framework only): an ASP.NET component that performs asynchronous or synchronous web page postbacks at a regular interval.
 
From your code and post, you seem to have a fascination with Thread Abort. Thread abort should be used with extreme caution, because it can have undesired effects....also read up on the docs for timers :

I have advanced with code now and no more abort(); xD when try to resize my WinForm it crash so i let the Threads close normaly after finishing loop ;D
THANK YOU ;D
 
When i try to set a Random position and random speed fall it's not really random

See code :

C#:
// example code only (without classes and namespaces)

Control control = new Control();
Random _rand = new Random();

control.Location = new Point(_rand.Next(this.Width),0);

// after in moving symbole thread loop

Control _c = getControl(); // return the control
_c.Location = new Point(_c.Location.X,_c.Location.Y + new Random().Next(3,15));

in my form look like this (left real random, right not real random):

 
Last edited:
Unfortunately, there's not enough context in your sample code to be able to give you any advice. Why not post your code to provide that context?

I do see part of the issue. You are not re-using youl _rand object. You are instantiating a new object here:
C#:
_c.Location = new Point(_c.Location.X,_c.Location.Y + new Random().Next(3,15));
 
Last edited:
Likely not part of the issue par-say, but well spotted. It is a problem if you don't want to be wasting resources though; however small they may be.

I have advanced with code now and no more abort(); xD
It will take you more than dwelling in deep though on an overnighter before you become better at threading, and develop a better understanding of it and all of its methods, and functionality. As I like to tell people, don't take someones criticism or expertise as gospel. Research why people are advising you on what they do. Just like me advising you to be careful aborting threads. The research you do yourself will shape the type of programmer you will become. But I do like that you appear eager to learn and once you continue to fuel that apatite, you will learn fast.

If you have updated your code, post it up so we can see what you changed.
 
Likely not part of the issue par-say, but well spotted. It is a problem if you don't want to be wasting resources though; however small they may be.


It will take you more than dwelling in deep though on an overnighter before you become better at threading, and develop a better understanding of it and all of its methods, and functionality. As I like to tell people, don't take someones criticism or expertise as gospel. Research why people are advising you on what they do. Just like me advising you to be careful aborting threads. The research you do yourself will shape the type of programmer you will become. But I do like that you appear eager to learn and once you continue to fuel that apatite, you will learn fast.

If you have updated your code, post it up so we can see what you changed.

Thanks ;D

With all yours tells, no more Thread, no more ABORT xD, here's the code (remaked again xD) for now : PasteBin

And here's result : Youtube
 
That's better, but now you should try cleaning your code, and remove irrelevant lines, and work on shortening your current code possibly by using some Linq. There is a lot of room for improvement.

Btw, please keep your code on our forums, and not on external sites such as pastebin. If your code is ever removed from pastebin, there is no way for future readers to benefit from availing of the solution you used. If you have problems pasting loads of code, paste them as two separate posts, by splitting your code in half. I've added your own code below.

C#:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Matrix4
{
    public partial class Form2 : Form
    {
        Timer _spawnTimer = new Timer();
        Timer _checkTimers = new Timer();
        List<Spawn> _spawnList = new List<Spawn>();
        List<Timer> _timerList = new List<Timer>();
      
        private Graphics _myGrpahics;
 
        public Form2()
        {
            InitializeComponent();
 
            _spawnTimer.Interval = 500;
            _spawnTimer.Tick += _spawnTimer_Tick;
 
            _checkTimers.Interval = 100;
            _checkTimers.Tick += _checkTimers_Tick;
 
            this.Paint += Form2_Paint;
        }
 
        private void _checkTimers_Tick(object sender, EventArgs e)
        {
            if (!_spawnTimer.Enabled)
            {
                int _result = 0;
 
                foreach (Timer timer in _timerList)
                {
                    if (timer.Enabled)
                    {
                        _result += 1;
                    }
                }
 
                if (_result > 0)
                {
                    Console.WriteLine(_result + " Timers left for " + _spawnList.Count + " Spawns");
                }
            }
        }
 
        private void _spawnTimer_Tick(object sender, EventArgs e)
        {
            for (int i = 0; i < 3; i+=1)
            {
                Spawn _spawn = new Spawn(this);
 
                _spawn._onSpawn = true;
                _spawn._spawned = true;
                _spawn._waitTo = false;
                _spawn._onDespawn = false;
 
                Random _theRandom = new Random();
 
                int _Size = _theRandom.Next(10, 30);
 
                _spawn._width = _Size;
                _spawn._height = _Size;
 
                _spawn._waitValue = 50;
 
                int _speedIntervalSetting = (_Size * 20) / 3;
 
                if (_speedIntervalSetting < 1)
                {
                    _speedIntervalSetting = 1;
                }
 
                _spawn._speedInterval = _speedIntervalSetting;
 
                _spawn._x = _theRandom.Next(this.Width);
                _spawn._y = _theRandom.Next(-(this.Height / 2), this.Height / 2);
 
                _spawn._colorValue = _theRandom.Next(90, 200);
                _spawn._currColorValue = 10;
                _spawn._colorStepValue = 35;
 
                _spawn._startSpawn();
 
                _spawnList.Add(_spawn);
                //Console.WriteLine("there is " + _spawnList.Count + " Spawn for now");
            }
        }
 
        private void Form2_Paint(object sender, PaintEventArgs e)
        {
            _myGrpahics = Graphics.FromHwnd(this.Handle);
 
            _checkTimers.Start();
        }
 
        private void Form2_Load(object sender, EventArgs e)
        {
 
        }
 
        private void label1_Click(object sender, EventArgs e)
        {
            if (_spawnTimer.Enabled)
            {
                _spawnTimer.Stop();
                label1.Text = "Start";
 
                Timer _waitT = new Timer();
 
                _waitT.Interval = 2000;
                _waitT.Tick += delegate(object o, EventArgs args)
                {
                    try
                    {
                        foreach (var timer in _timerList)
                        {
                            timer.Stop();
                        }
                    }
                    catch (Exception)
                    {
 
                    }
 
                    Console.WriteLine("All timers cleared");
                    this.Invalidate();
                    _waitT.Stop();
                };
 
                _waitT.Start();
            }
            else
            {
                _spawnTimer.Start();
                label1.Text = "Stop";
            }
        }
}
 
Back
Top Bottom