animation - 如何在 SkiaSharp 中获得流畅的动画

标签 animation xamarin skiasharp

我正在尝试使用 Xamarin SkiaSharp 实现流畅的动画。核心问题是调用 canvasView.InvalidateSurface(); 之间的时间。并点击 mathod OnCanvasViewPaintSurface 进行重绘可以在 3 到 30 毫秒之间变化,当您在屏幕上移动对象时,这会产生一些不稳定的外观。我试图通过在绘图代码中添加一个死循环来缓解这种情况,这对一些人有帮助,但不是一个很好的解决方案。我不明白为什么时间变化如此之大,而且我看不出有任何解决办法。你不能在抽奖代码中 sleep 。游戏如何实现流畅的动画?我的代码如下

    async Task DoAnimationLoop()
    {
        while (DoAnimation)
        {
            AccumulatedTime = StopWatch1.ElapsedMilliseconds;

            await Task.Delay(TimeSpan.FromMilliseconds(5));

            if (AccumulatedTime > 50)
            {
                StopWatch1.Restart();
                MoveItems();
                SKCanvasView canvasView = Content as SKCanvasView;
                TotalBounds = new Size(canvasView.Width, 
                                       canvasView.Height);
                canvasView.InvalidateSurface();
            }
        }
    }

    private void OnCanvasViewPaintSurface(object sender, 
                                          SKPaintSurfaceEventArgs e)
    {
        AccumulatedTime = StopWatch1.ElapsedMilliseconds;

        while (AccumulatedTime < 30)
        {
            AccumulatedTime = StopWatch1.ElapsedMilliseconds;
        }

        e.Surface.Canvas.Clear();
        e.Surface.Canvas.DrawBitmap(Background, 0, 0);

        foreach(Item item in AllItems)
        {
            e.Surface.Canvas.DrawBitmap(item.CurrentBitmap, 
            item.CurrentPositionX, item.CurrentPositionY);

        }
    }

最佳答案

对于 future 的读者: 根据经验,我通过创建 SkiaSharp SKCanvasViews 获得最流畅的动画,这些 SkiaSharp SKCanvasViews 具有可以使用 Xamarin.Forms.Animate 增加的可绑定(bind)属性。 Animate 根据您为其配置的变量处理所有计时和休眠代码。当你想要一个循环时,你可以将 repeat 委托(delegate)设置为在调用 Animate.Commit( ... repeat: () => true ...) 时返回 true/p>

这是一个方法示例,通过增加 ProgressBarPercentageFilled 属性,将进度条“填充”到 100%(不循环)。请注意您可以配置的时间设置:刷新 rate = 11ms(等于“90 fps”:1000ms/90 = 11.11),timeToAnimate 是动画应该的时间长度take 在 ms 内完成,您可以从多个缓动函数中进行选择。

        private void AnimateProgressBar()
    {
        double startPercentage = 0; //start at 0 percent
        double endPercentage = 1; //fill to 100 percent (Forms.Animate will evenly increment
        //between 0 and 1 , and in this case the ProgressBar's OnPaintSurface method knows how to draw based
        //on the given decimal i.e. if PercentageFilled is .5 it will draw the bar to
        //50 percent of its possible max length)

        uint timeToAnimate = 1000;

        Xamarin.Forms.Animation animation = new Animation(v => _ProgressBar.PercentageFilled = (float)v, startPercentage, endPercentage, easing: Easing.CubicOut);

        animation.Commit(_ProgressBar, "FillPercentage", length: timeToAnimate, finished: (l, c) => animation = null, rate: 11);

    }

PercentageFilled 属性更改时,它会通过在 OnPropertyChanged 中调用 InvalidateSurface() 来触发 InvalidateSurface > 方法。为此,请在您的 SKCanvasView 派生类中重写 OnPropertyChanged:

 class ProgressBar: SKCanvasView
    {     
         //...
public BindableProperty PercentageFilledProperty =
        BindableProperty.Create(nameof(PercentageFilled), typeof(float), typeof(ProgressBar), 0f);

    public float PercentageFilled 
    {
        get { return (float)GetValue(PercentageFilledProperty ); }
        set { SetValue(PercentageFilledProperty , value); }
    }


    protected override void OnPropertyChanged(string propertyName = null)
    {
        base.OnPropertyChanged(propertyName);
        
        InvalidateSurface();
    }

 protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
    { 
      //Draws progress bar based on the PercentageFilled filled property 
    }
           //....
}

在问题的代码中,似乎有很多项目正在按顺序移动 (MoveItems();),这种逐一移动绘制项目的技术可能是抖动的原因?但是 MoveItems 似乎是您可能想要使用 Forms.Animate 的地方,您可以使用 MoveItems() 作为 Callback< 创建一个 Forms.Animation/。查看“Custom Animations in Xamarin.Forms”的 Microsoft 文档,了解有关如何使用回调制作动画的更多信息。

另请查看 Medium 上 Konrad Müller 的“The basics to create custom Xamarin.Forms controls using SkiaSharp”,其中包含这段有用的段落,如果您正在制作游戏,可以考虑一下:

The basic SkiaSharp.Views.Forms provides two views you can use as a base for your controls: SKCanvasView and SKGLView. The CanvasView uses the CPU accelerated backend while the GLView uses OpenGL and therefore the GPU. You might intuitively think that using the GPU for graphics operations is always the better choice but in fact, OpenGL has a high overhead when creating the GL context. The CanvasView simply allocates the memory it needs and as long as enough CPU power is available, it can render without problems. In theory, the CanvasView should be better suited for less demanding renderings and GlView better for complex renderings but the power of modern smartphones makes these differences mostly unnoticable. I would recommend to simply stick to the CanvasView and switch to the GlView if the rendering gets to complex and you notice performance problems.

关于animation - 如何在 SkiaSharp 中获得流畅的动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54282665/

相关文章:

android - Android Flipboard样式的动画

html - Css 加载栏改变颜色

ios - 当 UIGravityBehavior 处于事件状态时,UIDynamicAnimator 拒绝达到平衡

javascript - 基于 A 帧时间轴的动画编辑器

c# - 使用 uitableview 加载 UIView

c# - SkiaSharp - 如何在 Canvas 上移动对象

c# - Xamarin IDE 访问路径被拒绝

java - 从 rsa 文件创建 keystore

xamarin - 如何从 Xamarin.forms 方 SkiaSharp 请求 REDRAW?

Xamarin 项目无法在 Android 或 Windows 中找到 SkiaSharp