运行多个动画而不会出现明显滞后

时间:2017-02-01 18:12:40

标签: android android-animation 2d-games animationdrawable

我正在开发一款简单的2D游戏。游戏以一个动画开始,然后玩家点击屏幕,另一个动画应该在没有明显滞后的情况下运行,同时切换到下一个动画。我的第一种方法是使用AnimationDrawable和40个PNG [帧]的动画列表。我想使用两个这样的AnimationDrawables。由于android在播放动画之前加载动画的所有帧,因此这种方法会导致OOM。然后我决定将我的单个动画分成4个动画,每个动画10帧。 10帧的第一个动画运行完美,但是当我第二次播放[第一次停止后立即]时,我会收到OOM和app关闭。

1)我遇到了这个解决方案: https://stackoverflow.com/a/10993879/6699069 这看起来像是我问题的完美解决方案。但我不知道解决方案中使用的OnAnimationStoppedListener对象。在developers.android.com或其他任何地方都没有关于它的信息。我想在评论中直接询问@Pinhassi,但由于声望限制为50,无法添加评论。

修改:我发现了几乎类似的解决方案here 工作没有任何错误:D但是与我在 4)中提到的相同 我甚至设置了delayMillis = 0;它仍然以大约10fps的速度运行[观察]

2)帖子已经有5年了,所以我想,现在应该有一个预定义的类来使用长动画而不会导致OOM。如果存在这样的类,请指出它的链接。

3)朋友建议我用gif代替动画。但我想没有办法以编程方式停止/播放gif。此外,一个40帧的GIF似乎是一个幻想。如果有人知道使用gif作为动画的等效物,请遮挡一些光。

4)我的旧方法[当我不知道AnimationDrawable类时]是使用SurfaceView并在循环中的画布上绘制40位图来模拟动画。它工作但帧速率非常慢。当玩家点击屏幕时,它会变慢。此外,不同手机上的帧速率也有很大差异。有人建议我降低图像分辨率。我将我的图像从720p缩小到320p,但没有太大区别。用这种方法加速动画的方法是什么?

如果有人能回答1)和2),我将非常感激。

1 个答案:

答案 0 :(得分:0)

你的问题相当广泛,所以我会尽力帮助(不确定它是否能给出完整答案)。当我在Android中制作动画时,我会尝试尽可能多地使用原生视图,因为性能几乎总是最好的,即使对于旧设备也是如此。如果您需要做一些更复杂的事情,也许您可​​以考虑使用Animator类。

ObjectAnimator是继承Animator类之一,它允许您基于对象的单个属性创建自定义动画。我的建议是创建一个自定义视图,该视图将包含一个名为animationFrame的属性,其值在0-39范围内。然后,当设置该值时,将加载正确的图像作为视图的背景。您可以使用Glide之类的库来优化图像的加载。

所以你的代码应该是这样的:

private class MyAnimation extends View {

    private ObjectAnimator animator = new ObjectAnimator();

    public MyAnimation(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        animator.setTarget(this);
        // the value must match a function with the signature "void setAnimationFrame(int frame)" (using the magic of reflection)
        animator.setPropertyName("animationFrame"); 
        animator.setIntValues(0, 39);
        animator.setRepeatCount(ObjectAnimator.INFINITE);
        animator.setRepeatMode(ObjectAnimator.RESTART);
        animator.setDuration(1000 / 60 * 40);
        animator.setInterpolator(new LinearInterpolator());

        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                // If you need to do something at the end of the animation
            }
        });
    }

    public void startAnimation() {
        animator.start();
    }

    private void setAnimationFrame(int frame) {
        setBackground(getDrawableForFrame(frame));
    }

    private Drawable getDrawableForFrame(int frame) {
        // Here you implement the loading from Glide or any other library or custom code
        return null;
    }
}