Animasi dalam applet Java

Artikel ini menerangkan cara menerapkan animasi menggunakan Java applet API. Ia menerangkan teknik yang biasa digunakan dan memberikan contoh mudah untuk menggambarkan setiap teknik.

Teknik animasi asas

Terdapat banyak bentuk animasi di Jawa. Kesamaan dari mereka semua ialah mereka membuat semacam gerakan di layar dengan melukis bingkai berturut-turut pada kelajuan yang agak tinggi (biasanya sekitar 10-20 kali sesaat).

Kita akan mulakan dengan membuat applet templat ringkas untuk melakukan animasi dan menghuraikannya perlahan-lahan sehingga kita sampai di applet yang cukup lengkap.

Menggunakan utas

Untuk mengemas kini skrin beberapa kali per saat, anda perlu membuat utas Java baru yang mengandungi gelung animasi. Gelung animasi bertanggungjawab untuk mengawasi bingkai semasa dan meminta kemas kini skrin secara berkala. Untuk melaksanakan utas, anda mesti membuat subkelas Threadatau mematuhi Runnableantara muka.

Kesalahan biasa adalah meletakkan gelung animasi dalam paint()kaedah applet. Melakukannya akan memberi kesan sampingan yang pelik kerana ia memegang utas AWT utama, yang bertanggung jawab atas semua lukisan dan pengendalian acara.

Sebagai contoh saya telah menulis applet templat kecil, yang disebut Contoh1Applet, yang menggambarkan garis besar umum applet animasi. Contoh1Applet menunjukkan cara membuat utas dan memanggil repaint()kaedah pada selang masa yang tetap. Bilangan bingkai sesaat ditentukan dengan meneruskan parameter applet. Berikut adalah contoh perkara yang anda masukkan dalam dokumen HTML anda:


  

Inilah Contoh1Applet.

Catatan:

Applet ini sebenarnya belum menarik apa-apa di skrin. Lukisan ke skrin dijelaskan kemudian. Perhatikan juga bahawa applet merosakkan utas animasinya setiap kali pengguna meninggalkan halaman (yang mengakibatkan stop()kaedah applet dipanggil). Ini memastikan bahawa applet tidak akan membuang masa CPU semasa halamannya tidak kelihatan.

Mengekalkan kadar bingkai tetap

Dalam contoh di atas, applet hanya tidur untuk jangka masa yang tetap di antara bingkai. Ini mempunyai kekurangan yang kadang-kadang anda tunggu terlalu lama. Untuk mendapatkan 10 bingkai sesaat, anda tidak boleh menunggu 100 milisaat antara bingkai, kerana anda kehilangan sedikit masa hanya menjalankan utas.

Applet berikut, Contoh2Applet, menunjukkan cara mengekalkan masa yang lebih baik. Ini hanya menghitung kelewatan yang betul antara bingkai dengan mengawasi waktu permulaan. Ia mengira anggaran kelewatan yang diperlukan antara bingkai berdasarkan masa semasa.

Inilah Contoh2Applet.

Mengecat setiap bingkai

Yang tinggal adalah melukis setiap bingkai. Dalam contoh sebelumnya, kami memanggil repaint()setiap bingkai, yang menyebabkan kaedah applet paint()dipanggil. Contoh3Applet mempunyai paint()kaedah yang menarik bilangan bingkai semasa ke skrin.

Berikut adalah Contoh3Applet dalam tindakan, diikuti dengan senarai kod.

Catatan:

Sekiranya anda menentukan kadar bingkai sangat tinggi (katakan 100 bingkai sesaat), run()kaedah akan memanggil repaint()100 kali sesaat. Namun, ini tidak akan selalu menghasilkan 100 panggilan ke paint()sesaat kerana ketika anda mengeluarkan permintaan mengecat ulang terlalu cepat, mereka akan dilipat menjadi satu kemas kini layar tunggal. Inilah sebabnya mengapa kita mengawasi nombor bingkai semasa dalam run()kaedah dan bukan paint()kaedahnya.

Menjana grafik

Sekarang mari kita menghidupkan sesuatu yang agak sukar untuk dilukis. Contoh4Applet melukis gabungan gelombang sinus. Untuk setiap koordinat x, ia melukis garis menegak pendek. Semua garis ini bersama-sama membentuk grafik sederhana yang berubah untuk setiap bingkai. Malangnya, anda akan mendapati bahawa pendekatan ini menyebabkan banyak kilat. Kami akan menerangkan punca kilat dan beberapa kaedah pemulihan di bahagian seterusnya.

Inilah Contoh4Applet dalam tindakan, diikuti dengan senarai kod.

Mengelakkan kilat berlebihan

Kilatan yang anda lihat dalam Contoh4Applet mempunyai dua sebab: melukis setiap bingkai terlalu lama (kerana jumlah pengiraan yang diperlukan semasa pengecatan semula) dan seluruh latar belakang dihapus sebelum paint()dipanggil. Sementara pengiraan bingkai berikutnya sedang berlangsung, pengguna melihat latar belakang animasi.

Masa yang singkat antara pembukaan latar belakang dan lukisan gelombang sinus dilihat sebagai kilat. Pada beberapa platform seperti PC, kelipan lebih jelas berbanding pada X Windows. Sebabnya ialah grafik X Windows disangga, yang menjadikan lampu kilat sedikit lebih pendek.

Anda boleh mengurangkan kilat dengan menggunakan dua helah mudah: melaksanakan update()kaedah dan menggunakan penyangga berganda (kadang-kadang dikenali sebagai menggunakan backbuffer ).

Mengatasi kaedah kemas kini ()

Apabila AWT menerima permintaan mengecat semula applet, ia memanggil kaedah applet update(). Secara lalai, update()kaedah ini membersihkan latar belakang applet dan kemudian memanggil paint()kaedah tersebut. Dengan mengesampingkan update()kaedah untuk memasukkan kod gambar yang sebelumnya ada dalam paint()metode ini, kami mengelakkan seluruh kawasan applet dibersihkan dengan setiap pengecatan semula.

Sekarang latar belakang tidak lagi dikosongkan secara automatik, kita perlu melakukannya sendiri dalam update()kaedah ini. Kita sekarang dapat menghapus setiap garis tegak grafik secara berasingan sebelum melukis garis baru, menghilangkan kilatan sepenuhnya. Kesan ini ditunjukkan dalam Contoh5Applet.

Berikut adalah Contoh5Applet dalam tindakan, diikuti dengan senarai kod.

Catatan:

Setiap kali anda menolak update()kaedah ini, anda masih perlu melaksanakannya paint(). Ini kerana paint()kaedah ini dipanggil secara langsung oleh sistem lukisan AWT setiap kali "kerosakan" berlaku pada kawasan lukisan applet - misalnya, apabila tetingkap yang menutupi bahagian lukisan applet dikeluarkan dari skrin. paint()Pelaksanaan anda hanya boleh memanggil update().

Penyangga berganda

Cara lain untuk mengurangkan berkelip antara bingkai adalah dengan menggunakan penyangga berganda. Teknik ini digunakan dalam banyak applet animasi.

Prinsip umum ialah anda membuat gambar di luar skrin, anda memasukkan bingkai ke dalam gambar, dan kemudian anda menampar keseluruhan gambar ke layar dengan satu panggilan ke drawImage(). Kelebihannya ialah sebahagian besar lukisan dilakukan di luar skrin. Lukisan akhir gambar luar skrin ke layar biasanya jauh lebih efisien daripada melukis bingkai secara langsung ke skrin.

Applet gelombang sinus dengan penyangga berganda ditunjukkan dalam Contoh6Applet. Anda akan melihat bahawa animasinya cukup lancar dan anda tidak memerlukan muslihat khas semasa melukis bingkai. Satu-satunya kelemahan ialah anda harus memperuntukkan gambar luar skrin yang sama besarnya dengan kawasan lukisan. Sekiranya kawasan lukisan sangat besar, ini mungkin memerlukan banyak memori.

Berikut adalah Contoh6Applet dalam tindakan, diikuti dengan senarai kod.

Catatan:

Apabila anda menggunakan buffering berganda, anda perlu mengganti update()kaedahnya, kerana anda tidak mahu latar belakang applet dibersihkan sebelum anda melukis bingkai. (Anda membersihkan latar belakang dengan menarik gambar luar skrin.)

Menggunakan gambar

Sekarang kita akan menulis semula paintFrame()kaedah dengan kaedah yang menganimasikan beberapa gambar. Ini menambahkan beberapa komplikasi kecil pada masalah tersebut. Gambar agak besar dan dimuat secara bertahap. Memerlukan masa yang lama untuk gambar digambar sepenuhnya, terutamanya semasa anda memuatkannya melalui sambungan yang perlahan. Inilah sebab mengapa drawImage()kaedah ini mengambil argumen keempat, objek ImageObserver. Pemerhati gambar adalah objek yang diberitahu ketika lebih banyak data gambar telah tiba. Untuk mendapatkan gambar kami menggunakan getImage()kaedah.

Menggerakkan gambar ke seluruh skrin

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

world.gif: car.gif:

Gambar dunia digunakan sebagai latar belakang, dan gambar kereta dilukis di atasnya dua kali, membuat animasi dua kereta berlumba di seluruh dunia.

Berikut adalah Contoh7Applet dalam tindakan, diikuti dengan senarai kod.

Memaparkan urutan gambar

Contoh8Applet menunjukkan cara membuat animasi menggunakan gambar berasingan untuk setiap bingkai. Berikut adalah 10 bingkai yang sedang 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 berganda untuk menghilangkan kilatan. Sebabnya ialah setiap gambar yang kita hasilkan sebahagiannya telus, dan oleh itu kita perlu menghapus setiap bingkai sebelum melukis yang berikutnya. Ini akan menyebabkan flashing tanpa buffering berganda.

Berikut adalah Contoh8Applet dalam tindakan, diikuti dengan senarai kod.

Catatan:

Semasa memaparkan urutan gambar, anda harus berhati-hati untuk menyelaraskan gambar dengan betul. Cara termudah adalah dengan memastikan bahawa semua gambar adalah ukuran yang sama dan dapat dilukis pada kedudukan yang sama. Sekiranya itu tidak berlaku, applet anda perlu menggambar setiap bingkai pada ofset yang berbeza.

Menggunakan MediaTracker untuk mengelakkan paparan tambahan

Ketika program Java memuat gambar, ia dapat menampilkan gambar sebelum gambar dimuat sepenuhnya. Pengguna melihat gambar yang diberikan pertama kali tidak lengkap, dan kemudian secara bertahap semakin lengkap semasa gambar dimuat. Paparan tambahan ini memberikan maklum balas pengguna (meningkatkan prestasi yang dirasakan) dan memungkinkan program dengan mudah melakukan tugas lain ketika gambar dimuat.

Dalam hal animasi, tampilan gambar tambahan dapat berguna untuk gambar latar belakang, tetapi sangat mengganggu ketika digunakan untuk gambar animasi. Oleh itu, kadang-kadang diinginkan untuk menunggu sehingga keseluruhan animasi dimuat sebelum memaparkannya.

Anda boleh menggunakan MediaTrackerkelas Jim Graham untuk mengesan muat turun gambar, menunda paparan animasi sehingga keseluruhan gambar dimuat turun sepenuhnya. Contoh9Applet menunjukkan cara menggunakan MediaTrackerkelas untuk memuat turun gambar untuk animasi Duke yang melambai.

Berikut adalah Contoh9Applet dalam tindakan, diikuti dengan senarai kod.

Menambah suara

Mudah menambahkan suara pada animasi. Anda boleh menggunakan getAudioClip()kaedah untuk mendapatkan objek AudioClip. Kemudian, anda boleh memainkan klip sama ada sebagai gelung berterusan atau sebagai satu suara. Contoh10Applet menunjukkan cara memainkan suara latar berterusan dan juga bunyi berulang semasa animasi.

Berikut adalah Contoh10Applet dalam tindakan, diikuti dengan senarai kod.

Catatan:

Semasa memainkan bunyi berterusan, anda mesti ingat untuk menghentikannya semasa pengguna meninggalkan halaman (iaitu, lakukan dengan stop()kaedah applet anda ).

Nota lain:

Audio berterusan boleh menjengkelkan. Adalah idea yang baik untuk memberi pengguna cara mematikan audio tanpa meninggalkan halaman. Anda boleh memberikan butang, atau cukup mematikan audio ketika pengguna mengklik applet.

Petua untuk memuatkan gambar dengan lebih pantas

Animasi yang menggunakan banyak gambar memerlukan masa yang lama untuk memuat turun. Ini terutama disebabkan oleh kenyataan bahawa sambungan HTTP baru dibuat untuk setiap fail gambar, dan membuat sambungan memerlukan beberapa saat walaupun terdapat banyak lebar jalur.

Di bahagian ini, kami akan memberitahu anda mengenai dua format gambar yang boleh digunakan oleh applet anda untuk mempercepat memuat turun gambar.

Menggunakan jalur gambar

Anda boleh meningkatkan prestasi memuat turun dengan menggunakan satu gambar yang mengandungi beberapa bingkai animasi. Anda boleh membuat satu bingkai dari gambar dengan menggunakan clipRect()operator. Di bawah ini adalah contoh jalur gambar yang digunakan dalam applet UnderConstruction.

Applet mencipta kesan penggerudian dengan tidak memadamkan bingkai sebelumnya. Latar belakang hanya dibersihkan begitu sahaja.

Inilah UnderConstruction dalam tindakan, dengan pautan ke kod sumbernya.

Pemampatan antara bingkai menggunakan Flic

Sekiranya anda benar-benar ingin meningkatkan prestasi memuat turun animasi yang terdiri daripada pelbagai bingkai, maka anda harus menggunakan beberapa bentuk pemampatan antara bingkai.

Alat animasi

Pada masa ini (Januari 1996), beberapa alat tersedia untuk membantu anda membuat animasi bertenaga Java. Alat terbaik yang dapat saya dapati ialah DimensionX's The Easy Animator (TEA) (sebelumnya dikenali sebagai JAM). Ini membolehkan anda membuat animasi secara interaktif. Kami ingin mendorong pemaju untuk menulis lebih banyak alat untuk membuat animasi di Java.

Sekiranya anda mempunyai beberapa gambar siap untuk dipaparkan, anda boleh menggunakan applet Animator. Animator mempunyai banyak parameter yang membolehkan anda menentukan bunyi berterusan, bunyi khusus bingkai, masa dan kedudukan bingkai individu, gambar permulaan, susunan bingkai, dan sebagainya.

Anda juga harus melihat halaman Animasi Gamelan untuk mencari banyak applet yang menggunakan animasi.

Kesimpulannya

Saya harap artikel ini dapat membantu pembangun applet menulis applet animasi yang lebih banyak dan lebih baik. Saya juga berharap bahawa alat yang lebih baik akan tersedia tidak lama lagi.

Arthur van Hoff, hingga baru-baru ini, seorang jurutera kakitangan kanan di Sun Microsystems dan telah terlibat dalam pengembangan bahasa Java sejak tahun 1993. Dia adalah pengarang penyusun Java pertama yang ditulis sepenuhnya di Jawa. Dia baru-baru ini meninggalkan Sun untuk membentuk syarikat baru bersama Sami Shaio, Kim Polese, dan Jonathan Payne. Syarikat baru akan memberi tumpuan untuk membangun aplikasi Java. Kathy Walrath adalah penulis teknikal di Sun Microsystems. Dia telah menjadi bagian dari tim Java sejak tahun 1993. Saat ini, dia bekerja dengan Mary Campione di The Java Tutorial: Object-Oriented Programming for Internet, tutorial yang disempurnakan applet untuk belajar bahasa Java, pengaturcaraan applet, dan pengaturcaraan Java GUI . Selain tersedia dalam talian, The Java Tutorial juga akan diterbitkan pada musim panas ini sebagai bagian dari Addison-Wesley Java Series.

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