Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Silverlight animation not smooth

When trying to animate objects time/frame based in Silverlight (in contrast to using something like DoubleAnimation or Storyboard, which is not suitable e.g. for fast paced games), for example moving a spaceship in a particular direction every frame, the movement is jumpy and not really smooth. The screen even seems to tear.

There seems to be no difference between CompositionTarget and DistpatcherTimer. I use the following approach (in pseudocode):

Register Handler to Tick-Event of a DispatcherTimer
In each Tick:
Compute the elapsed time from the last frame in milliseconds
Object.X += movementSpeed * ellapsedMilliseconds

This should result in a smooth movement, right? But it doesn't. Here is an example (Controls: WASD and Mouse): Silverlight Game. Although the effect I described is not too prevalent in this sample, I can assure you that even moving a single rectangle over a canvas produces a jumpy animation.

Does someone have an idea how to minimize this. Are there other approaches to to frame based animation exept using Storyboards/DoubleAnimations which could solve this?

Edit: Here a quick and dirty approach, animating a rectangle with minimum code (Controls: A and D) Animation Sample

Xaml:

 <Grid x:Name="LayoutRoot" Background="Black">
    <Canvas Width="1000" Height="400" Background="Blue">
        <Rectangle x:Name="rect" Width="48" Height="48"
                   Fill="White"
                   Canvas.Top="200"
                   Canvas.Left="0"/>
    </Canvas>
</Grid>

C#:

private bool isLeft = false;
    private bool isRight = false;
    private DispatcherTimer timer = new DispatcherTimer();
    private double lastUpdate;

    public Page()
    {
        InitializeComponent();

        timer.Interval = TimeSpan.FromMilliseconds(1);
        timer.Tick += OnTick;

        lastUpdate = Environment.TickCount;
        timer.Start();
    }

    private void OnTick(object sender, EventArgs e)
    {
        double diff = Environment.TickCount - lastUpdate;

        double x = Canvas.GetLeft(rect);

        if (isRight)
            x += 1 * diff;
        else if (isLeft)
            x -= 1 * diff;

        Canvas.SetLeft(rect, x);

        lastUpdate = Environment.TickCount;
    }

    private void UserControl_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.D)
            isRight = true;

        if (e.Key == Key.A)
            isLeft = true;
    }

    private void UserControl_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.D)
            isRight = false;

        if (e.Key == Key.A)
            isLeft = false;
    }

Thanks! Andrej

like image 545
Andrej Avatar asked Jun 30 '09 15:06

Andrej


1 Answers

Updating the position every 1 millisecond is overkill because silverlight will simply not update the screen that fast. When you modify the position of an object like that (or any other ui update) silverlight marks the framebuffer as dirty and then it will eventually redraw the screen, however it will not redraw the screen more often than the MaxFrameRate.

To set the MaxFrameRate just:

Application.Current.Host.Settings.MaxFrameRate = 60;

This will limit your application to 60 frames per second which should be more than enough.

like image 157
luke Avatar answered Sep 23 '22 16:09

luke