Animasi di applet Java

Artikel ini menjelaskan cara mengimplementasikan animasi menggunakan Java applet API. Ini menjelaskan teknik yang umum digunakan dan memberikan contoh sederhana untuk menggambarkan setiap teknik.

Teknik animasi dasar

Banyak bentuk animasi dimungkinkan di Java. Kesamaan dari semuanya adalah bahwa mereka menciptakan semacam gerakan di layar dengan menggambar bingkai yang berurutan pada kecepatan yang relatif tinggi (biasanya sekitar 10-20 kali per detik).

Kita akan mulai dengan membuat applet template sederhana untuk melakukan animasi dan perlahan-lahan menguraikannya hingga kita sampai pada applet yang cukup lengkap.

Menggunakan utas

Untuk mengupdate layar beberapa kali per detik, Anda perlu membuat thread Java baru yang berisi loop animasi. Loop animasi bertanggung jawab untuk melacak frame saat ini dan untuk meminta pembaruan layar berkala. Untuk menerapkan utas, Anda harus membuat subkelas Threadatau mematuhi Runnableantarmuka.

Kesalahan umum adalah meletakkan loop animasi dalam paint()metode applet. Melakukannya akan memiliki efek samping yang aneh karena akan menahan utas AWT utama, yang bertanggung jawab atas semua gambar dan penanganan kejadian.

Sebagai contoh, saya telah menulis applet template kecil, yang disebut Example1Applet, yang menggambarkan garis besar umum applet animasi. Example1Applet menunjukkan cara membuat utas dan memanggil repaint()metode pada interval tetap. Jumlah frame per detik ditentukan dengan memasukkan parameter applet. Berikut adalah contoh yang akan Anda masukkan ke dalam dokumen HTML Anda:


  

Berikut adalah Example1Applet.

catatan:

Applet ini sebenarnya belum menggambar apa pun di layar. Menggambar ke layar dijelaskan nanti. Perhatikan juga bahwa applet menghancurkan untaian animasinya setiap kali pengguna meninggalkan halaman (yang mengakibatkan metode applet stop()dipanggil). Ini memastikan bahwa applet tidak akan membuang waktu CPU saat halamannya tidak terlihat.

Menjaga frekuensi gambar konstan

Dalam contoh di atas, applet hanya tidur selama jangka waktu tertentu di antara bingkai. Ini memiliki kekurangan yaitu terkadang Anda menunggu terlalu lama. Untuk mendapatkan 10 frame per detik, Anda tidak boleh menunggu 100 milidetik antar frame, karena Anda kehilangan waktu hanya untuk menjalankan utas.

Applet berikut, Example2Applet, menunjukkan bagaimana menjaga waktu dengan lebih baik. Ini hanya menghitung penundaan yang benar antara bingkai dengan melacak waktu mulai. Ini menghitung perkiraan penundaan yang diperlukan antara bingkai berdasarkan waktu saat ini.

Berikut adalah Example2Applet.

Lukisan setiap bingkai

Yang tersisa adalah mengecat setiap bingkai. Dalam contoh sebelumnya, kita memanggil repaint()setiap frame, yang menyebabkan metode applet paint()dipanggil. Example3Applet memiliki paint()metode yang menarik nomor bingkai saat ini ke layar.

Berikut adalah Example3Applet beraksi, diikuti dengan daftar kode.

catatan:

Jika Anda menetapkan frekuensi gambar menjadi sangat tinggi (katakanlah 100 bingkai per detik), run()metode akan memanggil repaint()100 kali per detik. Namun, ini tidak selalu menghasilkan 100 panggilan menjadi paint()per detik karena ketika Anda mengeluarkan permintaan pengecatan ulang terlalu cepat, panggilan tersebut akan diciutkan menjadi pembaruan layar tunggal. Inilah sebabnya mengapa kami melacak nomor bingkai saat ini di run()metode daripada di paint()metode.

Menghasilkan grafik

Sekarang mari kita animasikan sesuatu yang sedikit lebih sulit untuk digambar. Example4Applet menggambarkan kombinasi gelombang sinus. Untuk setiap koordinat x, ini menggambar garis vertikal pendek. Semua garis ini bersama-sama membentuk grafik sederhana yang berubah untuk setiap bingkai. Sayangnya, Anda akan menemukan bahwa pendekatan ini menyebabkan banyak flashing. Kami akan menjelaskan penyebab flashing dan beberapa solusi di bagian selanjutnya.

Berikut adalah Example4Applet beraksi, diikuti dengan daftar kode.

Mencegah flashing berlebihan

Kedipan yang Anda lihat di Example4Applet memiliki dua penyebab: mengecat setiap bingkai membutuhkan waktu terlalu lama (karena jumlah komputasi yang diperlukan selama pengecatan ulang) dan seluruh latar belakang dibersihkan sebelum paint()dipanggil. Saat komputasi frame berikutnya sedang berlangsung, pengguna melihat latar belakang animasi.

Waktu singkat antara pembersihan latar belakang dan lukisan gelombang sinus ini terlihat sebagai kilatan. Pada beberapa platform seperti PC, flashing lebih jelas daripada di X Windows. Alasannya adalah karena grafik X Windows disangga, yang membuat flash sedikit lebih pendek.

Anda dapat sangat mengurangi flashing menggunakan dua trik sederhana: menerapkan update()metode dan menggunakan buffering ganda (terkadang disebut menggunakan backbuffer ).

Mengganti metode update ()

Ketika AWT menerima permintaan pengecatan ulang untuk applet, itu memanggil metode applet update(). Secara default, update()metode ini membersihkan latar belakang applet dan kemudian memanggil paint()metode tersebut. Dengan mengganti update()metode untuk memasukkan kode gambar yang dulu ada dalam paint()metode, kita menghindari seluruh area applet dibersihkan dengan setiap pengecatan ulang.

Sekarang latar belakang tidak lagi dihapus secara otomatis, kita perlu melakukannya sendiri dalam update()metode ini. Sekarang kita dapat menghapus setiap garis vertikal grafik satu per satu sebelum menggambar garis baru, menghilangkan kedipan sepenuhnya. Efek ini ditampilkan di Example5Applet.

Berikut adalah Example5Applet beraksi, diikuti dengan daftar kode.

catatan:

Setiap kali Anda mengganti update()metode ini, Anda masih perlu menerapkannya paint(). Ini karena paint()metode ini dipanggil langsung oleh sistem gambar AWT setiap kali "kerusakan" terjadi pada area gambar applet - misalnya, ketika jendela yang menutupi bagian dari area gambar applet dihilangkan dari layar. paint()Penerapan Anda cukup memanggil update().

Buffering ganda

Cara lain untuk mengurangi flashing antar frame adalah dengan menggunakan buffering ganda. Teknik ini digunakan di banyak applet animasi.

Prinsip umumnya adalah Anda membuat gambar di luar layar, Anda menggambar bingkai ke dalam gambar, dan kemudian Anda menampar seluruh gambar ke layar dengan satu panggilan ke drawImage(). Keuntungannya adalah sebagian besar gambar dilakukan di luar layar. Pengecatan akhir gambar di luar layar ke layar biasanya jauh lebih efisien daripada mengecat bingkai langsung ke layar.

Applet gelombang sinus dengan buffering ganda ditunjukkan pada Example6Applet. Anda akan melihat bahwa animasinya cukup halus dan Anda tidak memerlukan trik khusus saat menggambar bingkai. Satu-satunya kelemahan adalah Anda harus mengalokasikan gambar di luar layar sebesar area gambar. Jika area gambar sangat besar, ini mungkin membutuhkan banyak memori.

Berikut adalah Example6Applet beraksi, diikuti dengan daftar kode.

catatan:

Saat Anda menggunakan buffering ganda, Anda perlu mengganti update()metode ini, karena Anda tidak ingin latar belakang applet dibersihkan sebelum Anda mengecat bingkai. (Anda membersihkan sendiri latar belakang dengan menggambar ke gambar di luar layar.)

Menggunakan gambar

Sekarang kita akan menulis ulang paintFrame()metode tersebut dengan metode yang menganimasikan beberapa gambar. Ini menambah beberapa komplikasi kecil pada masalah tersebut. Gambar agak besar dan dimuat secara bertahap. Diperlukan waktu lama untuk menggambar sepenuhnya, terutama saat Anda memuatnya dengan koneksi lambat. Inilah alasan mengapa drawImage()metode ini mengambil argumen keempat, objek ImageObserver. Pengamat gambar adalah objek yang diberi tahu ketika lebih banyak data gambar telah tiba. Untuk mendapatkan gambar kami menggunakan getImage()metode.

Memindahkan gambar melintasi layar

Applet animasi gambar pertama ini, Example7Applet, menggunakan dua gambar berikut:

world.gif: car.gif:

Gambar dunia digunakan sebagai latar belakang, dan gambar mobil digambar di atasnya dua kali, membuat animasi dua mobil yang berlomba di seluruh dunia.

Berikut adalah Example7Applet beraksi, diikuti dengan daftar kode.

Menampilkan urutan gambar

Example8Applet menunjukkan cara membuat animasi menggunakan gambar terpisah untuk setiap bingkai. Berikut 10 bingkai yang digunakan:

T1.gif: T2.gif: T3.gif: T4.gif: T5.gif:

T6.gif:

T7.gif:

T8.gif:

T9.gif:

T10.gif:

Kami masih menggunakan buffering ganda untuk menghilangkan flashing. Alasannya adalah setiap gambar yang kita render sebagian transparan, dan oleh karena itu kita perlu menghapus setiap frame sebelum menggambar berikutnya. Ini akan menyebabkan flashing tanpa buffering ganda.

Berikut adalah Example8Applet beraksi, diikuti dengan daftar kode.

catatan:

Saat menampilkan urutan gambar, Anda harus berhati-hati saat menyelaraskan gambar dengan benar. Cara termudah adalah dengan memastikan bahwa semua gambar berukuran sama dan dapat digambar pada posisi yang sama. Jika bukan itu masalahnya, applet Anda harus menggambar setiap bingkai pada offset yang berbeda.

Menggunakan MediaTracker untuk menghindari tampilan tambahan

Ketika program Java memuat gambar, itu dapat menampilkan gambar sebelum gambar dimuat sepenuhnya. Pengguna melihat gambar pertama kali dirender secara tidak lengkap, lalu secara bertahap semakin lengkap saat gambar dimuat. Tampilan inkremental ini memberikan umpan balik kepada pengguna (meningkatkan kinerja yang dirasakan) dan memungkinkan program dengan mudah melakukan tugas lain saat gambar sedang dimuat.

Dalam hal animasi, tampilan gambar inkremental bisa berguna untuk gambar latar belakang, tetapi bisa sangat mengganggu saat digunakan untuk gambar animasi. Oleh karena itu terkadang Anda perlu menunggu sampai seluruh animasi dimuat sebelum menampilkannya.

Anda dapat menggunakan MediaTrackerkelas Jim Graham untuk melacak pengunduhan gambar, menunda tampilan animasi hingga seluruh rangkaian gambar diunduh sepenuhnya. Example9Applet menunjukkan bagaimana menggunakan MediaTrackerkelas untuk mengunduh gambar untuk animasi Duke yang melambai.

Berikut adalah Example9Applet beraksi, diikuti dengan daftar kode.

Menambahkan suara

Sangat mudah untuk menambahkan suara ke animasi. Anda dapat menggunakan getAudioClip()metode ini untuk mendapatkan objek AudioClip. Nanti, Anda dapat memutar klip sebagai loop berkelanjutan atau sebagai suara tunggal. Contoh 10Applet menunjukkan cara memutar suara latar belakang terus menerus serta suara berulang selama animasi.

Berikut adalah Example10Applet beraksi, diikuti dengan daftar kode.

catatan:

Saat memainkan suara terus menerus, Anda harus ingat untuk menghentikannya saat pengguna meninggalkan halaman (yaitu, lakukan dengan stop()metode applet Anda ).

Catatan lain:

Audio terus menerus bisa sangat mengganggu. Sebaiknya berikan cara kepada pengguna untuk mematikan audio tanpa meninggalkan halaman. Anda dapat memberikan tombol, atau cukup mematikan audio saat pengguna mengklik applet.

Tips untuk memuat gambar lebih cepat

Animasi yang menggunakan banyak gambar akan membutuhkan waktu lama untuk diunduh. Hal ini terutama disebabkan oleh fakta bahwa koneksi HTTP baru dibuat untuk setiap file gambar, dan membuat koneksi dapat memakan waktu beberapa detik bahkan ketika ada banyak bandwidth.

Di bagian ini, kami akan memberi tahu Anda tentang dua format gambar yang dapat digunakan applet Anda untuk mempercepat pengunduhan gambar.

Menggunakan strip gambar

Anda dapat meningkatkan kinerja pengunduhan dengan menggunakan satu gambar yang berisi beberapa bingkai animasi. Anda dapat membuat satu bingkai dari gambar dengan menggunakan clipRect()operator. Di bawah ini adalah contoh strip gambar yang digunakan di applet UnderConstruction.

Applet menciptakan efek pengeboran dengan tidak menghapus bingkai sebelumnya. Latar belakang hanya dibersihkan sesekali.

Berikut ini UnderConstruction sedang beraksi, dengan tautan ke kode sumbernya.

Kompresi antar frame menggunakan Flic

Jika Anda benar-benar ingin meningkatkan kinerja pengunduhan animasi yang terdiri dari banyak bingkai, Anda harus menggunakan beberapa bentuk kompresi antar-bingkai.

Alat animasi

Saat ini (Januari 1996), beberapa alat tersedia untuk membantu Anda membuat animasi yang didukung Java. Alat terbaik yang dapat saya temukan adalah The Easy Animator (TEA) DimensionX (sebelumnya dikenal sebagai JAM). Ini memungkinkan Anda membuat animasi secara interaktif. Kami ingin mendorong pengembang untuk menulis lebih banyak alat untuk membuat animasi di Java.

Jika Anda memiliki beberapa gambar siap pakai untuk ditampilkan, Anda dapat menggunakan applet Animator. Animator memiliki banyak parameter yang memungkinkan Anda menentukan suara kontinu, suara khusus bingkai, waktu dan posisi bingkai individu, gambar permulaan, urutan bingkai, dan sebagainya.

Anda juga harus memeriksa halaman Animasi Gamelan untuk menemukan banyak applet yang menggunakan animasi.

Kesimpulan

Saya harap artikel ini akan membantu pengembang applet menulis applet animasi yang lebih banyak dan lebih baik. Saya juga berharap alat yang lebih baik akan segera tersedia.

Arthur van Hoff, hingga saat ini, adalah staf insinyur senior di Sun Microsystems dan telah terlibat dalam pengembangan bahasa Java sejak 1993. Dia adalah penulis kompiler Java pertama yang seluruhnya ditulis di Java. Dia baru-baru ini meninggalkan Sun untuk membentuk perusahaan baru bersama dengan Sami Shaio, Kim Polese, dan Jonathan Payne. Perusahaan baru ini akan fokus membangun aplikasi Java. Kathy Walrath adalah penulis teknis di Sun Microsystems. Dia telah menjadi bagian dari tim Java sejak 1993. Saat ini, dia bekerja dengan Mary Campione di The Java Tutorial: Object-Oriented Programming for the Internet, tutorial yang disempurnakan dengan applet untuk mempelajari bahasa Java, pemrograman applet, dan pemrograman Java GUI. . Selain tersedia secara online, Tutorial Java juga akan diterbitkan musim panas ini sebagai bagian dari Seri Java Addison-Wesley.

Kisah ini, "Animasi dalam applet Java" awalnya diterbitkan oleh JavaWorld.