tags:

views:

1044

answers:

5

I have this algorithm that are drawing a lot of pixels on a Canvas in an animation. But I have no control of the speed of the animation and it is drawing very fast, so I added a Thread.Sleep(1) but then it is too slow when drawing several thousand pixels. I have tried a Storyboard approach but that ended up to be a very slow.

So are there an alternative to the Thread.sleep for slowing down my loop?

void DrawGasket(object sender, DoWorkEventArgs e)
    {
        Random rnd = new Random();
        Color color = Colors.White;
        while (Counter <= noOfPx)
        {
            switch (rnd.Next(3))
            {
                case 0:
                    m_lastPoint.X = (m_top.X + m_lastPoint.X)/2;
                    m_lastPoint.Y = (m_top.Y + m_lastPoint.Y)/2;
                    color = Colors.White;
                    break;
                case 1:
                    m_lastPoint.X = (m_left.X + m_lastPoint.X)/2;
                    m_lastPoint.Y = (m_left.Y + m_lastPoint.Y)/2;
                    color = Colors.Orange;
                    break;
                case 2:
                    m_lastPoint.X = (m_right.X + m_lastPoint.X)/2;
                    m_lastPoint.Y = (m_right.Y + m_lastPoint.Y)/2;
                    color = Colors.Purple;
                    break;
            }
            Dispatcher.BeginInvoke(() =>
            {
                var px = new Rectangle { 
                                       Height = m_pxSize, 
                                       Width = m_pxSize,
                                       Fill = new SolidColorBrush(color) 
                                       };
                Canvas.SetTop(px, m_lastPoint.Y);
                Canvas.SetLeft(px, m_lastPoint.X);
                can.Children.Add(px);
                lblCounter.Text = Counter.ToString();
            });
            Counter++;
            Thread.Sleep(1);
        }
    }
+12  A: 

Can't you just sleep every N iterations through the loop rather than every iteration?

mattnewport
Doh... Simple is better, that worked out great.
Qwark
+4  A: 

Here's the simple method: You want it to draw at a specific time...during each loop have it look to see what time it is. If it's "time" (whatever) rate you determine that to be, then draw/update. Otherwise, just loop. (For example, if you want 10 updates per second, and you just updated, then store the current time in a variable...and then compare against that variable. Until it is a 10th of a second later, don't redraw, just loop.)

This isn't bad, so long as you can do anything else you need to do within this loop. If this loop must complete, however, before anything else happens, you'll just be burning a lot of cpu cycles just waiting.

If you want to get fancy, and do this right, you can have it see how much time has passed, and then update the visual by the correct amount. So, for example, if you want your object to move 30 pixels per second, you could just update where it is precisely, (if .0047 seconds have gone by, for instance, it should move .141 pixels). You store that value. Of course, visually, it won't have moved at all until another round of the loop, but exactly when it moves and how far will be determined by time, rather than the speed of the computer. This way you'll get it moving 30 pixels per second, regardless of the speed of the machine...it will just be jumpier on a slow machine.

Beska
I sort of like the time idea, even though it may be a bit complex, but it does allow for the loop to run at approximately the same speed on different computers; it would sleep more often on a fast computer than on a slow.
Fredrik Mörk
+1 for suggesting what is (essentially) a timing loop. There are other options (painting in memory and flipping the image only when it's time to display a new one, e.g.), but this addresses the question directly.
Greg D
I will try to implement this later, because it's a better way of doing animation. but for now I'm going with mattnewport's solution.
Qwark
+3  A: 

One option would be to not sleep each time:

if(Counter % 2 == 0) Thread.Sleep(1);

Jon Galloway
+3  A: 

With or without Thread.Sleep(), the render speed is determined by how fast your system is, or by how much time your process gets. -> bad!

You should use the approach that video games are written nowadays. Keep track of the current time, and call BeginInvoke() only x times per second (where x is the frames per second render speed)

In the BeginInvoked function check how much is drawn and how much you still need to draw. Especially don't BeginInvoke for every single Rectangle. Even without a Thread.Sleep() it's always a context switch.

chris166
+4  A: 

The CompositionTarget.Rendering event fires every time Silverlight draws a frame, this is a good place to write any custom drawing code. You can use some other mechanism, like a timer, to keep track of your "game time" and adjust the model appropriately on a separate thread (or at least a separate execution path) from the drawing code. That way when it comes time to draw the UI there are no calculations to perform, you just paint the current state of your model. Basically just move the code in Dispatcher.BeginInvoke to the event handler for CompositionTarget.Rendering and I believe you'll be good.

James Cadd