在Surface View中动画和旋转图像

jax*_*jax 8 android

我想在SurfaceView上制作动画动画.理想情况下,我想在动画结束后收到通知.

例如:我可能有一辆朝北的汽车.如果我想要让它面向南方的动画,持续时间为500毫秒,我该怎么做?

我正在使用SurfaceView所以所有动画必须手动处理,我不认为我可以使用XML或Android Animator类.

此外,我想知道在SurfaceView中连续动画内容的最佳方法(即步行循环)

Ste*_*ley 8

手动旋转图像可能有点痛苦,但这就是我如何做到的.

private void animateRotation(int degrees, float durationOfAnimation){
    long startTime = SystemClock.elapsedRealtime();
    long currentTime;
    float elapsedRatio = 0;
    Bitmap bufferBitmap = carBitmap;

    Matrix matrix = new Matrix();

    while (elapsedRatio < 1){
        matrix.setRotate(elapsedRatio * degrees);
        carBitmap = Bitmap.createBitmap(bufferBitmap, 0, 0, width, height, matrix, true);
        //draw your canvas here using whatever method you've defined
        currentTime = SystemClock.elapsedRealtime();
        elapsedRatio = (currentTime - startTime) / durationOfAnimation;
    }

    // As elapsed ratio will never exactly equal 1, you have to manually draw the last frame
    matrix = new Matrix();
    matrix.setRotate(degrees);
    carBitmap = Bitmap.createBitmap(bufferBitmap, 0, 0, width, height, matrix, true);
    // draw the canvas again here as before
    // And you can now set whatever other notification or action you wanted to do at the end of your animation

}
Run Code Online (Sandbox Code Playgroud)

这会将carBitmap旋转到指定时间内指定的任何角度+绘制最后一帧的时间.然而,有一个问题.这会旋转您的carBitmap而不会正确调整其在屏幕上的位置.根据您绘制位图的方式,最终可能会在位图的左上角保持原位时旋转carBitmap.随着汽车的旋转,位图将拉伸并调整以适应新车的尺寸,用透明像素填充周围的空隙.很难描述这看起来如何,所以这是一个旋转方块的例子:

替代文字

灰色区域表示位图的完整大小,并填充透明像素.要解决此问题,您需要使用三角函数.这是一个有点复杂.如果这最终成为你的一个问题(我不知道你是如何绘制你的位图到画布上,因此可能不是),你不能制定出解决方案,让我知道,我会发布我是如何做到的.

(我不知道这是否是最有效的方法,但只要位图小于300x300左右,它就能顺利运行.也许如果有人知道更好的方法,他们可以告诉我们!)


idb*_*rii 7

你想要多个独立的动画对象吗?如果是这样,那么你应该使用游戏循环.(一个主循环,逐步更新所有游戏对象.)这里是对各种循环实现的一个很好的讨论.(我目前正在为我的Android游戏项目使用"依赖于恒定游戏速度的FPS".)

那么你的车看起来会像这样(很多代码丢失):

class Car {
    final Matrix transform = new Matrix();
    final Bitmap image;

    Car(Bitmap sprite) {
        image = sprite;  // Created by BitmapFactory.decodeResource in SurfaceView
    }
    void update() {
        this.transform.preRotate(turnDegrees, width, height);
    }
    void display(Canvas canvas) {
        canvas.drawBitmap(this.image, this.transform, null);
    }
}
Run Code Online (Sandbox Code Playgroud)

您只需要加载一次位图.因此,如果您有多个Cars,您可能希望为它们分别提供相同的Bitmap对象(在SurfaceView中缓存Bitmap).

我还没有进入步行动画,但最简单的解决方案是拥有多个位图,每次调用显示时只绘制一个不同的位图.

如果您还没有看过Android文档中的lunarlander.LunarView,请查看.


如果您希望在动画完成时收到通知,则应进行回调.

interface CompletedTurnCallback {
    void turnCompleted(Car turningCar);
}
Run Code Online (Sandbox Code Playgroud)

让你的逻辑类实现回调并让你的Car在转弯完成时调用它(in update()).请注意,如果您正在迭代Cars列表update_game()并尝试从回调中的该列表中删除Car,则会收到ConcurrentModificationException .(您可以使用命令队列解决此问题.)