Как создать плавную анимацию в коде во время выполнения? - PullRequest
3 голосов
/ 03 февраля 2011

На моей странице я создаю бомбы, которые должны быть сброшены на указанные цели. Моя проблема заключается в том, что при использовании (Timer, DoubleAnimation, KeyFrameAnimation) движение падающих бомб выглядит прерывистым. Может кто-нибудь подсказать, как создавать безудержную анимацию (в коде). Спасибо ..

Ответы [ 3 ]

4 голосов
/ 03 февраля 2011

Прежде всего, тестирование анимации немного проблематично.Я сделал несколько анимаций, которые работают ужасно в эмуляторе (хотя я и отвечаю всем требованиям, таким как WDDM 1.1), но они отлично работают на устройстве.Просто нужно проверить его на устройстве.

Чтобы создать такую ​​игру, я предлагаю класс DispatcherTimer для имитации игрового цикла (я создал свою игру HelloWorld, которая ее использует).У вас будет общий таймер, который поможет вам со всеми анимациями.

Я думаю, что лучше всего подходит DobuleAnimation.Итак, давайте закодируем (внутри обработчика событий Timer Tick):

        Random random = new Random();
        // Create the bomb.
        Bomb bomb = new Bomb();
        bomb.IsFalling = true;

        //Easing function
        var easefall = new QuadraticEase();
        easefall.EasingMode = EasingMode.EaseIn;

        // make some bombs bigger and goes faster
        var randNumber = random.Next(0, 100);
        if (randNumber < 15)
        {
            bomb.Scale.ScaleX = bomb.Scale.ScaleY = 0.8;
            Canvas.SetZIndex(bomb, 1);
        }

        // Position the bomb.            
        bomb.SetValue(Canvas.LeftProperty, (double)(random.Next(0, (int)(canvasBackground.ActualWidth - 30))));
        bomb.SetValue(Canvas.TopProperty, -200.0);

        // Attach ManipulationStarted click event (for defusing the bomb).
        bomb.ManipulationStarted += bomb_ManipulationStarted;

        // Create the animation for the falling bomb.
        Storyboard storyboard = new Storyboard();
        DoubleAnimation fallAnimation = new DoubleAnimation();
        fallAnimation.To = canvasBackground.ActualHeight;
        fallAnimation.Duration = TimeSpan.FromSeconds(m_secondsToFall);
        fallAnimation.EasingFunction = easefall;

        StoryBoardHelper.SetTarget(fallAnimation, bomb);
        Storyboard.SetTargetProperty(fallAnimation, new PropertyPath("(Canvas.Top)"));
        storyboard.Children.Add(fallAnimation);

        // Create the animation for the bomb "wiggle."
        DoubleAnimation wiggleAnimation = new DoubleAnimation();
        wiggleAnimation.To = 40;
        wiggleAnimation.Duration = TimeSpan.FromSeconds(0.3);
        wiggleAnimation.RepeatBehavior = RepeatBehavior.Forever;
        wiggleAnimation.AutoReverse = true;
        var easewiggle = new CircleEase();

        easewiggle.EasingMode = EasingMode.EaseInOut;
        wiggleAnimation.EasingFunction = easewiggle;

        StoryBoardHelper.SetTarget(wiggleAnimation, ((TransformGroup)bomb.RenderTransform).Children[0]);
        Storyboard.SetTargetProperty(wiggleAnimation, new PropertyPath("Angle"));
        storyboard.Children.Add(wiggleAnimation);

        // Add the bomb to the Canvas.
        canvasBackground.Children.Add(bomb);

        // Add the storyboard to the tracking collection.            
        m_storyboards.Add(bomb, storyboard);

        // Configure and start the storyboard.
        storyboard.Duration = fallAnimation.Duration;
        storyboard.Completed += storyboard_Completed;
        storyboard.Begin();

Также было бы здорово иметь некоторую анимацию, когда бомба ловится / взрывается.Пример:

    // display falling bombs
    private void bomb_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
    {
        FrameworkDispatcher.Update();
        // Get the bomb.
        Bomb bomb = (Bomb)sender;
        bomb.IsFalling = false;

        // Get the bomb's current position.
        Storyboard storyboard = m_storyboards[bomb];
        double currentTop = Canvas.GetTop(bomb);

        // Stop the bomb from falling.
        storyboard.Stop();

        // Play the sound
        m_beep.Play();

        // Reuse the existing storyboard, but with new animations.
        // Send the bomb on a new trajectory by animating Canvas.Top
        // and Canvas.Left.
        storyboard.Children.Clear();

        DoubleAnimation riseAnimation = new DoubleAnimation();
        riseAnimation.From = currentTop;
        riseAnimation.To = 0;
        riseAnimation.Duration = TimeSpan.FromSeconds(2);

        StoryBoardHelper.SetTarget(riseAnimation, bomb);
        Storyboard.SetTargetProperty(riseAnimation, new PropertyPath("(Canvas.Top)"));
        storyboard.Children.Add(riseAnimation);

        DoubleAnimation slideAnimation = new DoubleAnimation();
        double currentLeft = Canvas.GetLeft(bomb);
        // Throw the bomb off the closest side.
        if (currentLeft < canvasBackground.ActualWidth / 2)
        {
            slideAnimation.To = -100;
        }
        else
        {
            slideAnimation.To = canvasBackground.ActualWidth + 100;
        }
        slideAnimation.Duration = TimeSpan.FromSeconds(1);
        StoryBoardHelper.SetTarget(slideAnimation, bomb);
        Storyboard.SetTargetProperty(slideAnimation, new PropertyPath("(Canvas.Left)"));
        storyboard.Children.Add(slideAnimation);

        // Start the new animation.
        storyboard.Duration = slideAnimation.Duration;
        storyboard.Begin();
    }

Вы можете найти помощник здесь

PS: я люблю Silverlight:)

1 голос
/ 03 февраля 2011

Вы не можете надежно использовать таймер для анимации - поскольку рождение таймера Windows всегда опускалось почти до самого низа списка приоритетов, когда речь идет о приоритете обработки, - поэтому вы просто не можете получить гарантированные высокочастотные тактовые импульсы с низким джиттером даже когда ваше приложение бездействует.

Вы можете использовать событие CompositionTarget.Rendering для выполнения ручной анимации, но будьте осторожны, чтобы не использовать слишком много математики (или другого кода) в этом событии, поскольку это может замедлить скорость рендеринга кадров.

Наконец, вы также можете использовать классы раскадровки / анимации для выполнения анимации. Я сделал это во многих демонстрационных случаях и видел хорошие, плавные эффекты - особенно при использовании реального телефона, а не при использовании эмулятора (я не уверен на 100%, как собственный рисунок эмулятора часы срабатывают!)

Как предполагает Дерек, возможно, стоит посмотреть на то, что вы анимируете, - замените ваши текущие анимированные объекты простыми фигурами (например, прямоугольниками) и посмотрите, будут ли они анимироваться более плавно.

1 голос
/ 03 февраля 2011

Я подозреваю, что проблема заключается в том, что вы пытаетесь оживить, и в отношениях между ними и их окружением, а не в том, как вы настраиваете анимацию. Я предлагаю вам взглянуть на некоторые из следующих ресурсов:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...