我想在SurfaceView上制作动画动画。理想情况下,我想在动画结束后收到通知。
例如: 我可能有一辆朝北的汽车。如果我想为它设置动画以使其面向南方持续500毫秒,我该怎么办呢?
我使用的是SurfaceView,因此必须手动处理所有动画,我认为我不能使用XML或Android Animator类。
另外,我想知道在SurfaceView中连续动画内容的最佳方法(即步行循环)
答案 0 :(得分: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
}
这会将carBitmap旋转到指定时间内指定的任何角度+绘制最后一帧的时间。然而,有一个问题。这会旋转您的carBitmap,而无需在屏幕上正确调整其位置。根据您绘制位图的方式,最终可能会在位图的左上角保持原位时旋转carBitmap。随着汽车的旋转,位图将拉伸并调整以适应新车的尺寸,用透明像素填充周围的空隙。很难描述它的外观,所以这是一个旋转正方形的例子:
灰色区域表示位图的完整大小,并填充透明像素。要解决此问题,您需要使用三角函数。这有点复杂...如果这最终成为你的问题(我不知道你是如何将你的位图绘制到画布上所以它可能不是),你无法解决问题,让我知道,我会发布我是如何做到的。
(我不知道这是否是最有效的方法,但只要位图小于300x300左右,它就能顺利运行。也许如果有人知道更好的方法,他们可以告诉我们!)
答案 1 :(得分:7)
你想要多个独立的动画对象吗?如果是这样,那么你应该使用游戏循环。 (一个主循环,逐步更新所有游戏对象。)Here's a good discussion在各种循环实现上。 (我目前正在为我的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);
}
}
您只需加载一次位图。因此,如果您有多个Cars,您可能希望为它们分别提供相同的Bitmap对象(在SurfaceView中缓存Bitmap)。
我还没有进入步行动画,但最简单的解决方案是使用多个位图,每次调用显示时只绘制不同的位图。
如果您还没有,请查看lunarlander.LunarView in the Android docs。
如果您希望在动画完成时收到通知,则应进行回调。
interface CompletedTurnCallback {
void turnCompleted(Car turningCar);
}
让你的逻辑类实现回调并让你的Car在转弯完成时调用它(在update()
中)。请注意,如果您正在迭代update_game()
中的汽车列表并尝试从回调中的该列表中删除汽车,则会收到ConcurrentModificationException。 (您可以使用命令队列解决此问题。)