如何在运行时在代码中创建平滑动画?

时间:2011-02-03 14:07:22

标签: animation windows-phone-7

在我的页面中,我正在创建应该放在指定目标上的炸弹。 我的问题是使用什么(Timer,DoubleAnimation,KeyFrameAnimation)坠落炸弹的运动显得生涩。 任何人都可以建议如何创建无混蛋动画(在代码中)。 感谢..

3 个答案:

答案 0 :(得分:4)

首先,测试动画有点问题。我制作了一些在累积器中表现糟糕的动画(即使我满足了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();
    }

您可以找到helper here

PS:我喜欢Silverlight:)

答案 1 :(得分:1)

我怀疑问题在于你试图制作动画的东西以及它们与周围环境之间的关系,而不是你如何设置动画。我建议你看一下以下的一些资源:

答案 2 :(得分:1)

您无法可靠地使用计时器进行动画制作 - 因为在处理优先级时,Windows计时器的诞生总是降到优先级列表的底部 - 因此您无法保证高频低抖动计时器滴答声即使您的应用程序处于空闲状态。

您可以使用CompositionTarget.Rendering事件来执行手工制作的动画 - 但请注意不要在此事件中执行过多的数学(或其他代码),因为它会降低帧渲染速度。

最后,您还可以使用Storyboard / Animation类来执行动画。我已经在很多demo cases now中完成了这个并且看到了很好的平滑效果 - 特别是在使用真正的手机而不是使用模拟器时(我不是100%确信模拟器自己的绘图时钟是如何触发的! )

正如Derek所说,可能值得看看你的动画效果 - 用简单的形状(例如矩形)替换你当前的动画对象,看看它们是否更加流畅。