Indonesian (Bahasa Indonesia) translation by ⚡ Rova Rindrata (you can also view the original English article)
Dalam tutorial ini, saya akan mengikuti pendekatan yang disarankan oleh Richard Davey (Terima kasih, Richard!), dan digunakan olehnya dan orang lain, dalam mendeteksi tabrakan antara bitmap dengan modifikasi yang halus. Saya juga akan membandingkan kinerja antara berbagai pendekatan deteksi tabrakan bitmap menggunakan PerformanceTest dari Grant Skinner.
Catatan: Selain menjadi bagian dari Sesi Shoot-'Em-Up, artikel ini juga merupakan bagian dari Deteksi dan Reaksi Tabrakan.
Langkah 1: Ikhtisar
Saya menjelaskan pendekatan alternatif ini secara singkat di sini.
- Periksa apakah ada tumpang tindih antara dua bitmap.
- Jika ada, lanjutkan ke #3. Jika tidak, keluar.
- Periksa apakah area tumpang tindih memiliki piksel buram yang tumpang tindih.
- Jika demikian, bitmap akan tumpang tindih. Jika tidak, keluar.
Langkah 2: Kotak Pembatas
Pertama, kita periksa apakah kotak pembatas bitmap tumpang tindih menggunakan Rectangle. Skripnya seperti di bawah ini. Pertama, variabelnya.
private var enemy1:Bitmap, myShip:Bitmap; private var myShipSp:Sprite; private var rec_e:Rectangle, rec_m:Rectangle; private var intersec:Rectangle;
enemy1 = new E1 as Bitmap; addChild(enemy1); myShip = new My as Bitmap; myShipSp = new Sprite; addChild(myShipSp); myShipSp.addChild(myShip); enemy1.x = stage.stageWidth >> 1; myShipSp.x = stage.stageWidth >> 1; enemy1.y = stage.stageHeight * 0.2; myShipSp.y = stage.stageHeight * 0.8; //drawing boxes around the sprite draw(enemy1.getBounds(stage), this, 0); draw(myShipSp.getBounds(stage), this, 0);
Di sini kita memeriksa area yang tumpang tindih di antara kotak-kotak itu. Lihat DetectVisible.as
dalam unduhan sumber untuk skrip lengkapnya
private function refresh(e:Event):void { //determining the bounding box of intersection area rec_e = enemy1.getBounds(stage); rec_m = myShipSp.getBounds(stage); intersec = rec_e.intersection(rec_m); //redraw the bounding box of both sprites this.graphics.clear(); draw(enemy1.getBounds(stage), this, 0); draw(myShipSp.getBounds(stage), this, 0); //only draw bounding box of intersection area if there's one if (!intersec.isEmpty()){ lines.graphics.clear(); draw(intersec, lines); t.text ="Intersection area by red rectangle." } else { t.text ="No intersection area." } }
Ini demonya. Seret pesawat luar angkasa yang lebih kecil di sekitar.
(Jangan khawatir tentang kotak merah yang "tertinggal" ketika pesawat diseret keluar dari kotak pembatas yang lain.)
Langkah 3: Menggambar ke Area Persimpangan
Jadi jika ada area berpotongan, kita melanjutkan untuk memeriksa apakah ada piksel yang tumpang tindih di area tersebut. Namun, pertama mari kita coba menggambar bitmap ke area persimpangan ini. Skrip lengkap ada di DetectVisible2.as
private function refresh(e:Event):void { //determining the bounding box of intersection area rec_e = enemy1.getBounds(stage); rec_m = myShipSp.getBounds(stage); intersec = rec_e.intersection(rec_m); //redraw the bounding box of both sprites this.graphics.clear(); draw(enemy1.getBounds(stage), this, 0); draw(myShipSp.getBounds(stage), this, 0); //only draw bounding box of intersection area if there's one if (!intersec.isEmpty()){ lines.graphics.clear(); draw(intersec, lines); //to draw the intersection area and checking for overlapping of colored area var eM:Matrix = enemy1.transform.matrix; var myM:Matrix = myShipSp.transform.matrix; bdt_intersec = new BitmapData(intersec.width, intersec.height, false, 0) eM.tx -= intersec.x; eM.ty -= intersec.y myM.tx -= intersec.x; myM.ty -= intersec.y bdt_intersec.draw(enemy1, eM); bdt_intersec.draw(myShip, myM); bm_intersec.bitmapData = bdt_intersec; bm_intersec.x = 10 bm_intersec.y = stage.stageHeight * 0.8 - bm_intersec.height; t.text = "Intersection area by red rectangle.\n" } else { t.text ="No intersection area." } }
Perhatikan bahwa karena kita menggambar area dengan menggunakan matriks, setiap skala, skewing dan transformasi lainnya pada kedua bitmap akan diperhitungkan. Ini demonya; lihat kotak di sudut kiri bawah.
Langkah 4: Memeriksa Warna di Area Persimpangan
Jadi bagaimana cara memeriksa piksel yang tepat? Pertama-tama, kita memberikan warna kotak persimpangan ini warna hitam (Red = 0, Green = 0, Blue = 0). Kemudian, bayangan pesawat ruang angkasa yang lebih kecil akan dicat ke dalam kotak gelap ini sebagai hijau, dengan mode campuran ADD. Demikian pula, bayangan pesawat ruang angkasa alien yang stasioner yang lebih besar akan dicat merah.
Jadi sekarang, akan ada area merah dan hijau untuk pesawat ruang angkasa, dan hitam jika tidak ada area yang tumpang tindih. Namun, jika ada piksel dari dua bitmap ini yang tumpang tindih, ini akan digambar dengan warna kuning (Red = 255, Green = 255, Blue = 0). Kita menggunakan metode Bitmapdata.getColorBoundsRect
untuk memeriksa keberadaan area ini.
Ini cuplikan di Main.as
//to draw the intersection area and checking for overlapping of colored area var eM:Matrix = enemy1.transform.matrix; var myM:Matrix = myShipSp.transform.matrix; bdt_intersec = new BitmapData(intersec.width, intersec.height, false, 0) eM.tx -= intersec.x; eM.ty -= intersec.y myM.tx -= intersec.x; myM.ty -= intersec.y //tweak color bdt_intersec.draw(enemy1, eM, new ColorTransform(1,1,1,1,255,-255,-255), BlendMode.ADD); bdt_intersec.draw(myShip, myM, new ColorTransform(1,1,1,1,-255,255,-255), BlendMode.ADD); bm_intersec.bitmapData = bdt_intersec; bm_intersec.x = 10 bm_intersec.y = stage.stageHeight * 0.8 - bm_intersec.height; t.text = "Intersection area by red rectangle.\n" //check for the existance of the right color intersec_color = bdt_intersec.getColorBoundsRect(0xffffff, 0xffff00); if (!intersec_color.isEmpty()) t.appendText("And there are interesecting pixels in the area.");
Perhatikan bahwa kita menekan komponen Red dan Blue pada baris 113 untuk memaksimalkan Green untuk pesawat ruang angkasa kecil. Pada baris 112 kita melakukan hal yang sama dengan pesawat luar angkasa alien dengan komponen Blue dan Green.
Membandingkan Pendekatan
Jadi setelah menerima komentar tentang masalah kinerja mengenai deteksi tabrakan, saya memutuskan untuk melakukan beberapa pengujian cepat dan kotor pada pendekatan ini. Saya membuat 20 pesawat ruang angkasa musuh dan satu pesawat ruang angkasa pemain dan memeriksa tabrakan antara kapal satu pemain tersebut dengan yang 20 lainnya. Sprite ini dikemas ke dalam lingkungan yang sama untuk memaksa deteksi tabrakan untuk semua pendekatan agar memiliki perjalanan yang lengkap.
Pendekatan pertama adalah yang paling sederhana. BitmapData
ditangkap saat inisiasi dan untuk setiap frame, deteksi tabrakan diperiksa menggunakan BitmapData.hitTest()
. Untuk pendekatan kedua, BitmapData
diperbarui setiap frame dan deteksi tabrakan dilakukan berdasarkan pada BitmapData
yang diambil. Yang ketiga mengacu pada pendekatan yang disarankan oleh tutorial ini.
Jadi hasil untuk salah satu pengujian yang saya lakukan adalah sebagai berikut.
–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– bitmapdata fixed (1000 iterations) Player version: WIN 11,1,102,55 (debug) –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms bitmapdata fixed 168 0.17 –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– bitmapdata updates (1000 iterations) Player version: WIN 11,1,102,55 (debug) –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms bitmapdata updates 5003 5.00 –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– custom method (1000 iterations) Player version: WIN 11,1,102,55 (debug) –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms custom method 4408 4.41 ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
PerformanceTest
memberikan hasil yang berbeda setiap kali saya menjalankan pengujian. Jadi saya menjalankannya beberapa kali dan memperoleh waktu rata-rata. Kesimpulan: metode tercepat adalah yang pertama, diikuti oleh pendekatan ketiga dan kemudian yang kedua.
Jadi menyimpan BitmapData
untuk bitmap ketika mereka pertama kali diperkenalkan ke panggung dan memeriksa hitTest
setiap frame setelahnya adalah benar-benar efisien, asalkan sprite ini tidak melakukan transformasi selain translation (seperti rotasi, skewing dan penskalaan) sepanjang waktu. Jika tidak, Anda akan dipaksa untuk mengadopsi pendekatan kedua atau ketiga, dan yang ketiga lebih efisien seperti yang ditunjukkan oleh gambar di atas.
Anda dapat melihat Collisions.as
dan Results.as
untuk skrip lengkapnya.
Mencari Metode yang Mahal
Saya memulai setelahnya untuk mencari baris kode tertentu yang menghabiskan lebih banyak waktu komputasi. Pendekatan kedua dan ketiga membutuhkan lebih banyak waktu, jadi saya memperoleh beberapa fungsi dari mereka, masing-masing rusak pada titik yang berbeda. Lihat salah satu hasil di bawah ini.
–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– default hitTest (1000 iterations) Player version: WIN 11,1,102,55 (debug) include bounds –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms default hitTest 189 0.19 –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– default hitTest (1000 iterations) Player version: WIN 11,1,102,55 (debug) include transform –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms default hitTest 357 0.36 –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– default hitTest (1000 iterations) Player version: WIN 11,1,102,55 (debug) include hittest –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms default hitTest 4427 4.43 –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– custom method (1000 iterations) Player version: WIN 11,1,102,55 (debug) inlcude bounds and transform –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms custom method 411 0.41 –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– custom method (1000 iterations) Player version: WIN 11,1,102,55 (debug) include draw and bounds –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––– method...................................................ttl ms...avg ms custom method 3320 3.32 ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
Yang pertama, kedua, dan ketiga mengacu pada pendekatan kedua pada breakpoint yang berbeda, dan yang keempat dan kelima mengacu pada pendekatan ketiga. Melihat hasil ketiga dan kelima kalinya, BitmapData.draw
tampaknya membutuhkan banyak waktu komputasi. Dan waktu yang diambil untuk menggambar dengan pendekatan kedua tampaknya lebih mahal dalam waktu komputasi, yang membuat saya berpikir bahwa ukuran untuk BitmapData.draw
agar beroperasi memanglah penting. Anda dapat memeriksa Collisions2.as
dan Results2.as
untuk skrip lengkapnya.
Satu hal yang saya rasa sedikit mengganggu adalah ketidakkonsistenan pengujian-pengujian ini - saya selalu tidak mendapatkan hasil waktu yang sama, meskipun mereka hampir mengikuti peringkat yang sama setiap saat. Jadi, cukup baik untuk melakukan perbandingan sederhana antar fungsi-fungsi.
Kesimpulan
Nah, terima kasih atas waktu Anda membaca tip kecil ini. Semoga ini bermanfaat. Tinggalkan komentar jika Anda tidak setuju dengan apa pun dalam tutorial ini. Saya ingin menanggapi umpan baliknya!
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post