2010-03-13 36 views
7

Tôi muốn tạo hiệu ứng chuyển động trên SurfaceView. Lý tưởng nhất là tôi cũng muốn được thông báo khi hoạt ảnh đã kết thúc.Hoạt hình và xoay hình ảnh ở Chế độ xem bề mặt

Ví dụ: Tôi có thể có ô tô quay về hướng Bắc. Nếu tôi muốn animate nó để nó phải đối mặt với Nam trong một thời gian 500ms, làm thế nào tôi có thể làm điều đó?

Tôi đang sử dụng SurfaceView nên mọi hoạt ảnh phải được xử lý thủ công, tôi không nghĩ mình có thể sử dụng XML hoặc các lớp Animator android.

Ngoài ra, tôi muốn biết cách tốt nhất để animate một cái gì đó liên tục bên trong một SurfaceView (ví dụ. Một chu kỳ đi bộ)

Trả lời

8

quay hình ảnh bằng tay có thể là một chút đau đớn, nhưng đây là cách tôi đã thực hiện nó.

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 

} 

Điều này sẽ xoay carBitmap của bạn thành bất kỳ góc nào bạn chỉ định trong thời gian được chỉ định + thời gian để vẽ khung cuối cùng. Tuy nhiên, có một nhược điểm. Điều này quay carBitmap của bạn mà không điều chỉnh vị trí của nó trên màn hình đúng cách. Tùy thuộc vào cách bạn đang vẽ bitmap của bạn, bạn có thể kết thúc với carBitmap của bạn xoay trong khi góc trên bên trái của bitmap vẫn ở vị trí. Khi chiếc xe quay, bitmap sẽ giãn ra và điều chỉnh để vừa với kích thước xe mới, lấp đầy khoảng trống xung quanh nó bằng các pixel trong suốt. Thật khó để diễn tả này sẽ trông như thế nào, vì vậy đây là một ví dụ xoay một hình vuông:

alt text

Khu vực màu xám biểu thị kích thước đầy đủ của bitmap, và được làm đầy với điểm ảnh trong suốt. Để giải quyết vấn đề này, bạn cần sử dụng lượng giác. Đó là một chút phức tạp ... nếu điều này kết thúc là một vấn đề cho bạn (Tôi không biết làm thế nào bạn đang vẽ bitmap của bạn để vải vì vậy nó có thể không được), và bạn không thể làm việc ra các giải pháp, hãy tôi biết và tôi sẽ đăng lên làm thế nào tôi đã làm nó.

(Tôi không biết đây có phải là cách hiệu quả nhất để làm điều đó không, nhưng nó hoạt động trơn tru cho tôi miễn là bitmap nhỏ hơn 300x300 hoặc hơn. Có lẽ nếu ai đó biết cách tốt hơn, họ có thể hãy cho chúng tôi biết!)

+0

Bạn có khả năng gặp sự cố về hiệu suất nếu bạn liên tục tạo bitmap của mình. Thay vào đó, hãy tạo nó một lần và sau đó chuyển ma trận của bạn vào 'canvas.drawBitmap()'. Ngoài ra, vòng lặp while đó sẽ ngăn chặn bất kỳ thứ gì khác từ hoạt ảnh cho đến khi bạn hoàn tất. Thử vòng lặp trò chơi: http://www.koonsolo.com/news/dewitters-gameloop/ – idbrii

7

Bạn có muốn nhiều đối tượng hoạt ảnh độc lập không? Nếu có, thì bạn nên sử dụng vòng lặp trò chơi. (Một vòng lặp chính trong khi cập nhật dần tất cả các đối tượng trò chơi.) Here's a good discussion trên các lần triển khai vòng lặp khác nhau. (Tôi hiện đang sử dụng "FPS phụ thuộc vào tốc độ game liên tục" cho dự án game Android của tôi.)

Vì vậy, sau đó xe của bạn sẽ trông giống như thế này (rất nhiều mã mất tích):

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); 
    } 
} 

Bạn chỉ cần tải bitmap của bạn một lần. Vì vậy, nếu bạn có nhiều xe ô tô, bạn có thể muốn cung cấp cho họ mỗi đối tượng Bitmap giống nhau (cache Bitmap trong SurfaceView của bạn).

Tôi chưa đi vào hoạt ảnh đi bộ, nhưng giải pháp đơn giản nhất là có nhiều Bitmap và chỉ vẽ một bitmap khác nhau mỗi lần hiển thị được gọi.

Hãy xem lunarlander.LunarView in the Android docs nếu bạn chưa có.


Nếu bạn muốn được thông báo khi hoạt ảnh hoàn tất, bạn nên gọi lại.

interface CompletedTurnCallback { 
    void turnCompleted(Car turningCar); 
} 

Yêu cầu lớp học của bạn thực hiện gọi lại và gọi xe khi đến lượt hoàn tất (trong update()). Lưu ý rằng bạn sẽ nhận được ConcurrentModificationException nếu bạn đang lặp qua danh sách Ô tô trong update_game() và bạn cố gắng xóa một chiếc xe khỏi danh sách đó trong cuộc gọi lại của mình. (Bạn có thể giải quyết vấn đề này với hàng đợi lệnh.)

Các vấn đề liên quan