0

I'm making a little math game in WPF and I have some "falling textblocks" that contain multiplications that you have to answer correctly before they reach the bottom of the window.

Currently it looks like this

Screenshot from the game

What I'm doing right now is that each textblock is a custom WPF control that contains a textblock to represent the expression and a textbox where user can input the answer to that expression. These are generated inside of a 40x20 grid where I'm using a DispatcherTimer to continiously move them down the grid until the reach the end of the grid.

There are two main problems with this approach:

  1. The "effect" of falling isn't very smooth, it's very choppy, I have been able to improve the fluidity of the movement somewhat by expanding the grid downwards and decreasing the interval at which the DispatcherTimer ticks but it is at best a band-aid solution and I can still tell that the movement is very mechanical.
  2. The other problem is closely related to the first one, whenever a textbox of these falling expressions is focused the falling becomes far far worse, it really slows to a crawl I'm guessing redrawing each and every control while having focus on a textbox is severely decreasing the performance which is causing this.

Anyhow because of this, I am seeking an alternative way of doing this, preferably it has to be easy to use and easy to integrate with my current code.

Overly Excessive
  • 2,095
  • 16
  • 31
  • 2
    WPF has a very extensive support for animation. You can start here: [http://msdn.microsoft.com/en-us/library/ms752312%28v=vs.110%29.aspx](http://msdn.microsoft.com/en-us/library/ms752312%28v=vs.110%29.aspx) – Fratyx Nov 14 '14 at 08:55

2 Answers2

0

You can use a canvas and change their position inside the DispatcherTimer.

Sample mockup grabbed on a website, implementation was for dragging objects.

void onDragDelta(object sender, DragDeltaEventArgs e)
        {
            Canvas.SetLeft(myThumb, Canvas.GetLeft(myThumb) + e.HorizontalChange);
            Canvas.SetTop(myThumb, Canvas.GetTop(myThumb) + e.VerticalChange);
        }

Here is a related question: Here

Here is the main draggable control article: Here

Community
  • 1
  • 1
DevEstacion
  • 1,947
  • 1
  • 14
  • 28
  • Indeed it seems canvas does work better, unfortunately I still experience the same kind of "lag" whenever a textbox is focused.. – Overly Excessive Nov 14 '14 at 09:26
  • Well maybe the solution here is not smoothness but a different approach when it's focused. I suggest pausing the textbox or, when a certain textbox is focused. display a textbox on the side that's not moving and only for user input, then relay the input to that control. – DevEstacion Nov 14 '14 at 09:30
0

I think you should use "StoryBoard" and "Animation" to handle your UserControl falling. The built-in animations are based on a "Timer" systems but it already handles all problems like "do not post 3 changes to screen if the previous change isn't commited yet", or "abort previous position rendering if the UI Thread didn't have time to start rendering it".

So, I would generate "Storyboard"s programmatically. It is useful knowning that each DependencyProperty could be "animated".

See: Using a Storyboard animation on a programatically-added control

Here is my code to animate a property which has a "Double" type:

    /// <summary>
    /// Create a linear animation
    /// </summary>
    /// <param name="duration"></param>
    public void CreateDoubleLinearAnimation(DependencyObject element, string name, string property, double? valueFrom, double valueTo, TimeSpan timeSpan, Storyboard sb)
    {

        // --- Animation toute bête
        DoubleAnimation animation = new DoubleAnimation();
        animation.Duration = new Duration(timeSpan);
        animation.To = valueTo;
        if (valueFrom != null)
            animation.From = valueFrom.Value;
        animation.SetValue(Storyboard.TargetNameProperty, name);
        animation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(property));

        sb.Children.Add(animation);
    }

Example of call:

Storyboard sb = new Storyboard();
CreateDoubleLinearAnimation(element, "myElement", "(UIElement.Opacity)", 0, 1, TimeSpan.FromSeconds(1), sb);

Examples of "property" parameter:

(Shape.StrokeThickness)
(UIElement.Opacity)
(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)

Best regards,

Community
  • 1
  • 1
Elo
  • 2,234
  • 22
  • 28
  • I'm not sure how this would work, the property that I want to animate isnt a direct property of the control it's an attached property indiciating the relative position of the control in relation to it's parent. – Overly Excessive Nov 14 '14 at 09:56