【问题标题】:Win2d UWP fluid animation canvas lineWin2d UWP流体动画画布线
【发布时间】:2020-01-08 23:18:12
【问题描述】:

我必须获得用 Win2d 绘制的线条的流畅动画。下面是模拟我的问题的代码。

MainPage.xaml:

     <canvas:CanvasAnimatedControl x:Name="animatedControl" 
                                   Margin="0,30,0,0"
                                   Height="500"
                                   Draw="OnDraw"/>

MainPage.xaml.cs:

    private void OnDraw(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedDrawEventArgs args)
    {
        CanvasDrawingSession ds = args.DrawingSession;

        double height = sender.Size.Height;
        double width = sender.Size.Width;

        Random random = new Random();

        double pointHeigth = random.Next(0, 300);

        var point1 = new Vector2((float)(width / 2), (float)height);
        var point2 = new Vector2((float)(width / 2), (float)height - (float)pointHeigth);

        CanvasSolidColorBrush brush = new CanvasSolidColorBrush(sender, Colors.Green);

        ds.DrawLine(point1, point2, brush, (float)10);
    }

这样我得到了一个荷叶边动画我怎样才能得到一个平滑的线条动画?

我声明我必须在 win2d 中使用画布。

提前致谢。

更新(我的代码不起作用)

    private Vector2 _point1;
    private Vector2 _point2;
    private Vector2 _targetPoint;
    private TimeSpan _animationElapsedTime = TimeSpan.FromMilliseconds(100);

    public MainPage()
    {
        this.InitializeComponent();
    }

    private void OnDraw(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedDrawEventArgs args)
    {
        CanvasDrawingSession ds = args.DrawingSession;

        double height = sender.Size.Height;
        double width = sender.Size.Width;


        Random random = new Random();

        double pointHeigth = random.Next(0, 300);

        var _point1 = new Vector2((float)(width / 2), (float)height);

        var _point2 = new Vector2((float)(width / 2), (float)height - (float)pointHeigth);

        CanvasSolidColorBrush brush = new CanvasSolidColorBrush(sender, Colors.Green);

        ds.DrawLine(_point1, _point2, brush, (float)10);
    }

    private Vector2 Tween(Vector2 sourcePoint, Vector2 targetPoint, float percentage)
    {
        return new Vector2(targetPoint.X + (targetPoint.X - sourcePoint.X) * percentage, targetPoint.Y + (targetPoint.Y - sourcePoint.Y) * percentage);
    }

    private void OnUpdate(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedUpdateEventArgs args)
    {
        _animationElapsedTime += args.Timing.ElapsedTime;
        var percentage = Math.Min(_animationElapsedTime.TotalSeconds / 5.0f, 1f);
        _point2 = Tween(_point1, _targetPoint, (float)percentage);
    }

更新 2 我的代码:

    double previuosData = 0;
    bool isDraw = false;

    public MainPage()
    {
        this.InitializeComponent();
    }

    private void OnDraw(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedDrawEventArgs args)
    {
        if (isDraw)
            return;

        CanvasDrawingSession ds = args.DrawingSession;

        double height = sender.Size.Height;
        double width = sender.Size.Width;

        CanvasSolidColorBrush brush = new CanvasSolidColorBrush(sender, Colors.Green);

        Random random = new Random();

        double pointHeigth = random.Next(0, 500);

        var point1 = new Vector2((float)(width / 2), (float)height);

        if (pointHeigth > previuosData)
        {
            for (double a = previuosData; a <= pointHeigth; a++)
            {
                isDraw = true;
                var point2 = new Vector2((float)(width / 2), (float)height - (float)a);
                ds.DrawLine(point1, point2, brush, (float)10);
            }
            isDraw = false;
        }
        else
        {
            for (double a = previuosData; a >= pointHeigth; a--)
            {
                isDraw = true;
                var point2 = new Vector2((float)(width / 2), (float)height - (float)a);
                ds.DrawLine(point1, point2, brush, (float)10);
            }
            isDraw = false;
        }

        previuosData = pointHeigth;
    }

通过这种方式,我使动画更加流畅,但使用 for 循环还不够,我该如何改进?

【问题讨论】:

    标签: c# uwp line win2d


    【解决方案1】:

    您似乎正在使用 Random 并从每个单帧中的给定范围生成一个随机数。所以这意味着每秒60次第二个点会随机上下跳跃。

    与以下内容进行比较:

    private bool _adding = true;
    private int _currentHeightOffset = 0;
    private void OnDraw(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedDrawEventArgs args)
    {
        CanvasDrawingSession ds = args.DrawingSession;
    
        double height = sender.Size.Height;
        double width = sender.Size.Width;
    
        var point1 = new Vector2((float)(width / 2), (float)height);
        var point2 = new Vector2((float)(width / 2), (float)height - (float)_currentHeight);
    
        CanvasSolidColorBrush brush = new CanvasSolidColorBrush(sender, Colors.Green);
    
        ds.DrawLine(point1, point2, brush, (float)10);
        if (_adding)
        {
           _currentHeightOffset++;
        }
        else
        {
           _currentHeightOffset--;
        }
        if (_currentHeightOffset == 0 || _currentHeightOffset == 300 )
        {
           _adding = !_adding;
        }        
    }
    

    现在在这个例子中,我在每一帧中逐个像素地移动点,直到它达到 300,然后回到 0。所以结果应该是一条看起来固定在 point1 中的线并移动和拉伸上下。

    关键是,这些值不再是随机的,而是可以逐帧预测的。

    更新

    正如我在 cmets 中所讨论的,您可以在两点之间进行“补间”效果。

    我们将使用以下方法:

    private Vector2 Tween(Vector2 sourcePoint, Vector2 targetPoint, float percentage)
    {
       return new Vector2( 
           targetPoint.X + (targetPoint.X - sourcePoint.X)*percentage,
           targetPoint.Y + (targetPoint.Y - sourcePoint.Y)*percentage)  
    }
    

    现在,如果您想在这两个点之间设置 5 秒的动画,您可以执行以下操作:

    private Vector2 _point2;
    private TimeSpan _animationElapsedTime = TimeSpan.Zero;
    
    private void OnUpdate(Microsoft.Graphics.Canvas.UI.Xaml.ICanvasAnimatedControl sender, 
          Microsoft.Graphics.Canvas.UI.Xaml.CanvasAnimatedUpdateEventArgs args)
    {
        _animationElapsedTime += args.Timing.ElapsedTime;
        var percentage = Math.Min(_animationElapsedTime.TotalSeconds / 5.0f, 1f);
        _point2 = Tween(_point1, _targetPoint, percentage);
    }
    

    这只是代码外观的快速草图,然而,它很重要 - 一旦您选择了目标点(例如使用随机),您需要决定动画需要多长时间然后将第二个点越来越靠近目标,直到时间结束。

    【讨论】:

    • Random 代表我真正的问题,因为它代表音频频谱的一个频带并且行为方式相同。
    • 如果您需要在一个点和另一个点之间制作动画,您就不能在每次绘制时进行随机计算。相反,您需要计算一次,然后在多次更新中从当前点移动到目标。
    • 我该如何通过多次更新来做到这一点?谢谢你的回答马丁
    • 我已经更新了我的答案,并举例说明了如何进行这样的操作:-)。这只是示例,因此您必须对其进行编辑以匹配您的场景
    • 能否提供完整的代码?我无法让它工作......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多