Tip Singkat: Trigonometri untuk Pengembang Permainan Flash
() translation by (you can also view the original English article)
Dalam Menerapkan Tank di Zona Perang Isometrik, Anda belajar bagaimana membuat obyek berputar untuk menghadap pointer dan bergerak menuju lokasi pada klik. Di Tip Cepat ini, kita akan melihat secara umum matematika di belakangnya: trigonometri.
Pratinjau Hasil Akhir
Ini adalah hasil akhir dari tutorial saya sebelumnya. Itu menggunakan prinsip trigonometri yang akan kita bahas dalam Tip Singkat ini:
Gerakkan mouse untuk membuat turret mengarahkannya ke sana, dan klik di mana saja untuk mendorong tank ke titik tersebut.
Setiap programmer, terutama programmer permainan, menghadapi kebutuhan untuk memindahkan obyek di layar cepat atau lambat. Ini adalah tugas yang sederhana jika Anda perlu memindahkan obyek ke satu arah, misalnya sepanjang sumbu x atau y. Tetapi misalkan Anda ingin membuat obyek mengikuti penunjuk mouse Anda di mana pun Anda memindahkannya, atau membuat permainan balap di mana Anda mengontrol percepatan mobil dengan menekan tombol panah ke atas dan menggunakan panah kiri dan kanan untuk mengarahkan.
Katakanlah Anda menekan tombol panah kanan sekali dan itu menambahkan 10 derajat ke properti rotasi mobil Anda tetapi Anda masih ingin mobil bergerak maju (yaitu mempercepat) ketika Anda menekan tombol panah ke atas, bahkan jika mobil diarahkan ke bagian bawah layar atau sisi kiri atau kanan dll. dan Anda tidak ingin terlihat seperti meluncur ke samping. Jadi, bagaimana Anda melakukannya? Di situlah sedikit trigonometri membantu!
Bagi mereka, yang pandai matematika itu tidak akan menjadi masalah, tetapi ada banyak orang yang tidak mengerti sama sekali, atau bahkan takut akan hal itu. Saya akan mencoba memecahnya sejelas mungkin di Tip Singkat ini.
Langkah 1: Sistem Koordinat Flash
Pada awalnya, mari kita ingat sistem koordinat Cartesian. Terdengar rumit? Jika ya, lihat saja gambar di bawah dan saya yakin itu akan menjadi hal yang biasa:

Ia memiliki sumbu X dan Y; Anda dapat dengan jelas melihat di mana X dan Y positif dan negatif. Ketika datang ke koordinat di Flash, situasinya sedikit berbeda. Flash juga memiliki sistem koordinat tetapi sepertinya sistem Cartesian yang terbalik:
Ia juga memiliki sumbu X dan Y dan Titik Asal, satu-satunya perbedaan adalah bahwa sumbu Y positif di bawah sumbu X.
Simbol apa pun yang dibuat di Flash memiliki sistem koordinat bawaannya sendiri. Jika Anda membuat simbol baru, apakah itu movie clip atau tombol, Anda mungkin melihat properti "registration point" dalam kotak dialog pembuatan simbol. Apa itu? Registration point adalah titik asal suatu simbol. Intinya bahwa obyek akan berputar jika Anda mengubah properti rotasinya.
Catatan: titik asal dari instance panggung adalah di sudut kiri atas. Ini berarti bahwa semua titik di atas panggung memiliki koordinat X dan Y yang positif.
Dalam Tip Cepat ini kita akan melihat tiga fungsi trigonometri yang paling umum digunakan dalam Flash; Sinus, Cosinus dan Atan2. Beberapa orang mungkin bertanya, bagaimana kita bisa menggunakan fungsi-fungsi ini dalam Flash? Baiklah, mari kita lihat beberapa contoh praktis, dan memahami mengapa kita membutuhkannya dan bagaimana mereka dapat membuat hidup kita sedikit lebih mudah.
Langkah 2: Menghitung Sudut
Mari menghitung sudut antara dua titik. Buat File Flash baru (ActionScript 3.0). Pilih frame pertama dari timeline dan tekan F9 untuk membuka Panel Actions.
Pada titik ini mari kita buat sesuatu yang sederhana. Cukup ketikkan ini ke dalam Panel Actions:
1 |
stage.addEventListener(MouseEvent.CLICK, calculateAngle) |
2 |
|
3 |
function calculateAngle(e:MouseEvent):void |
4 |
{
|
5 |
trace("stage X " + e.stageX); |
6 |
trace("stage Y " + e.stageY) |
7 |
}
|
Ini akan memberi kita posisi pointer mouse setiap kali kita mengklik panggung. Tidak terlalu menarik, kan?
Ok, sekarang anggap Anda ingin "memberi tahu" beberapa obyek koordinat pointer mouse Anda relatif terhadap obyek ini, kemudian menunjukkan arah untuk melakukan perjalanan untuk mencapai posisi pointer.
Tutup Panel Actions dan buka Insert > New Symbol atau tekan saja Ctrl + F8.

Berikan nama apa saja (atau tinggalkan nama default) dan tekan OK. Crosshair kecil di tengah layar adalah registration point simbol atau titik asalnya. Ini akan menjadi posisi X dan Y obyek. Sekarang ambil alat Oval (tombol O) dan gambar lingkaran (dengan tombol Shift ditekan) di mana saja pada layar.

Klik lingkaran untuk memilihnya dan buka panel Properties > Position and size. Untuk W (lebar) ketik 20, sama untuk H (tinggi) dan untuk jenis posisi X dan Y (-10). Ini akan membuat lingkaran 20x20 px dan tepat memusatkannya ke registration point. Sekarang keluar dari mode pengeditan simbol (Klik Scene 1 di atas), ambil simbol ini di perpustakaan Anda dan seret ke panggung (di mana saja, kita akan mendapatkan posisinya secara dinamis nanti). Setelah obyek Anda di atas panggung, berikan nama instance mCircle
.

Sekarang kita ingin menghitung arah dari posisi Y dan X lingkaran kita ke posisi Y dan X pointer mouse. Garis merah pada gambar di bawah adalah arah yang perlu kita ketahui. Ini dapat ditemukan dengan menggunakan fungsi Math.atan2()
standar.

Mari kita lakukan sekarang. Hapus pernyataan "trace" dari kode dan membuat variabel baru sebagai gantinya. Kemudian lacak variabel ini untuk melihat apa yang Anda dapatkan:
1 |
stage.addEventListener(MouseEvent.CLICK, calculateAngle); |
2 |
|
3 |
var myAtan2:Number; |
4 |
|
5 |
function calculateAngle(e:MouseEvent):void |
6 |
{
|
7 |
myAtan2 = Math.atan2(e.stageY - mCircle.y, e.stageX - mCircle.x); |
8 |
trace(myAtan2); |
9 |
}
|
Perhatikan bahwa e.stageY - mCircle.y
adalah jarak vertikal dari mouse ke lingkaran, dan e.stageX - mCircle.x
adalah jarak horizontal.
Anda akan mendapatkan jenis angka ini di panel output:
1 |
-2.419017353128333
|
2 |
3.0118660246925346
|
3 |
2.5704959452340326
|
4 |
1.6726588917423932
|
5 |
1.0238847495551058
|
6 |
0.21368467849101092
|
Ini adalah sudut relatif (antara garis sumbu X dan garis merah) dalam radian. Kenapa bukan derajat? Nah, Flash menggunakan radian untuk menghitung sinus dan kosinus, tetapi jika Anda ingin tahu apa sudut-sudut ini dalam derajat Anda dapat selalu mengalikan "myAtan2" dengan 180 dan membaginya dengan Math.PI
. Seperti ini:
1 |
trace(myAtan2 * 180 / Math.PI) // gives you the angle in degrees; |
Editor: Sebagai sumber tambahan, inilah satu set fungsi yang bagus untuk konversi derajat/radian. Ini disimpan sebagai snipet di snipplr.com, anggota terbaru dari jaringan Envato!
Langkah 3: Memahami Sinus dan Cosinus
Setelah kita mengetahui sudut antara dua titik, kita sekarang dapat menghitung berapa banyak piksel yang kita harus tambahkan ke properti X dan Y lingkaran setiap frame sampai mencapai titik klik. Mari kita periksa apa yang perlu kita ketahui di sini:

Garis biru adalah Cosinus dari sudut, dan oranye adalah Sinus dari sudut. Dengan kata lain,
- Sine(angle) == e.stageY - mCircle.y
- Cosine(angle) == e.stageX - mCircle.x
Daripada menjelaskan bagaimana kerja sinus dan kosinus, saya akan mendemonstrasikan bagaimana menggunakannya dengan beberapa contoh praktis. Secara blak-blakan, sinus dan cosinus adalah hubungan antara Y dan X di sudut kita.
Bayangkan sudut antara dua benda adalah 45 derajat. Dalam hal ini hubungan antara sinus dan kosinus adalah 1:1 (lihat gambar di bawah), yang berarti kita harus menambahkan properti X dan Y dari lingkaran kita dengan jumlah yang sama setiap frame untuk mencapai tujuannya. Misalnya Anda harus menambahkan 5 piksel ke X dan 5 piksel ke Y setiap frame.

Dalam diagram ini, sudut telah berubah dan hubungan antara sinus dan kosinus telah berubah juga. Sekarang sekitar 1:2.

Dalam hal ini kita harus menambahkan dua kali lebih banyak piksel ke properti X lingkaran kita daripada ke Y. Mis. X += 10, Y += 5;
Langkah 4: Contoh Praktis
Anda mungkin akan bertanya mengapa kita perlu sinus dan kosinus jika kita sudah tahu koordinat titik klik - kita dapat memindahkan mCircle
kita ke sana segera? Nah, Anda bisa melakukannya dengan cara ini jika Anda ingin lingkaran Anda (atau obyek lain) untuk "teleport" pada koordinat titik klik segera setelah klik terjadi. Tetapi bagaimana jika Anda ingin bergerak secara bertahap ke arah klik? Untuk melakukan ini, Anda perlu menambahkan sejumlah piksel ke properti X dan Y, misalnya, setiap frame atau setiap detik.
Sekarang mari kita menghitung berapa banyak piksel yang harus kita tambahkan untuk properti X dan Y berdasarkan sinus dan cosinus dari sudut antara obyek kita dan titik klik. Ingat, Flash mengetahui sudut antara mereka dari operasi ini:
1 |
myAtan2 = Math.atan2(e.stageY - mCircle.y, e.stageX - mCircle.x); |
Untuk tujuan ini, kita harus memperbarui kode kita sedikit.
1 |
stage.addEventListener(MouseEvent.CLICK, calculateAngle); |
2 |
|
3 |
// 2 is the maximum amount of pixels to add to the objects X and Y properties every frame
|
4 |
// you can use any number you like
|
5 |
var moveAmount:Number = 2; |
6 |
var myAtan2:Number; |
7 |
var mouseClickX:Number; |
8 |
var mouseClickY:Number; |
9 |
|
10 |
function calculateAngle(e:MouseEvent):void |
11 |
{
|
12 |
mouseClickX = e.stageX; |
13 |
mouseClickY = e.stageY; |
14 |
|
15 |
myAtan2 = Math.atan2(mouseClickY - mCircle.y, mouseClickX - mCircle.x); |
16 |
|
17 |
addEventListener(Event.ENTER_FRAME, moveTheCircle); |
18 |
}
|
19 |
|
20 |
function moveTheCircle(e:Event):void |
21 |
{
|
22 |
mCircle.x += Math.cos(myAtan2) * moveAmount; |
23 |
mCircle.y += Math.sin(myAtan2) * moveAmount; |
24 |
}
|
Perhatikan apa yang telah saya lakukan di sini: Saya mempromosikan semua variabel saya di luar fungsi apa pun, karena sekarang saya memiliki lebih dari satu fungsi dan saya ingin variabel-variabel ini dapat diakses dari setiap fungsi.
1 |
var moveAmount:Number = 2; |
2 |
var myAtan2:Number; |
3 |
var mouseClickX:Number; |
4 |
var mouseClickY:Number; |
Panggung memiliki event listener untuk klik mouse, jadi ketika klik terjadi, metode calculateAngle()
dipanggil dan variabel berikutnya digunakan:
1 |
mouseClickX = e.stageX; |
2 |
mouseClickY = e.stageY; |
3 |
myAtan2 = Math.atan2(mouseClickY - mCircle.y, mouseClickX - mCircle.x); |
Fungsi ini juga menambahkan event listener untuk memasukkan frame ke panggung, yang memanggil metode moveTheCircle()
setiap frame.
1 |
addEventListener(Event.ENTER_FRAME, moveTheCircle); |
Langkah 5: Menghitung Piksel
Sekarang, mari kita merinci metode moveTheCircle()
itu sendiri. Untuk saat ini hanya ada dua hal:
1 |
mCircle.x += Math.cos(myAtan2) * moveAmount; |
2 |
mCircle.y += Math.sin(myAtan2) * moveAmount; |
Seperti yang Anda lihat, baris pertama menghitung berapa banyak piksel yang harus ditambahkan ke properti X dan yang kedua berhubungan dengan Y. Mari saya jelaskan. Math.cos menemukan cosinus (properti x) dari sudut "myAtan2", Math.sin melakukan hal yang sama dengan sinusnya (properti y). Jika sudut myAtan2 kita sama dengan sekitar 0,785 radian (45 derajat) cosinus dan sinus keduanya akan sama dengan sekitar 0,707... Anda dapat menggunakan kalkulator untuk memeriksanya.
Perhitungan sederhana akan menunjukkan berapa banyak piksel dari kode di atas akan menambah properti X dan Y dari obyek kita jika sudutnya 45 derajat.
1 |
Cosine(45 degrees) = 0.707 * 2 = 1.414; |
2 |
Sine(45 degrees) = 0.707 * 2 = 1.414; |
3 |
|
4 |
so the code will work out these results: |
5 |
mCircle.x += 1.414 pixels; |
6 |
mCircle.y += 1.414 pixels; |
Jika sudutnya misalnya. 60 derajat maka hasilnya akan seperti ini:
1 |
Cosine(60 degrees) = 0.5 * 2 = 1; |
2 |
Sine(60 degrees) = 0.866 * 2 = 1.732; |
3 |
|
4 |
And the code would work out this way: |
5 |
mCircle.x += 1 pixel; |
6 |
mCircle.y += 1.732 pixels; |
Langkah 6: Memperbaiki Masalah dengan Kode
Yah, kita hampir selesai. Namun masih ada sedikit masalah dengan kode kita. Anda mungkin telah memperhatikan bahwa obyek kita tidak pernah berhenti, bahkan jika mencapai titik klik itu masih terus bergerak. Kita dapat memperbaiki masalah ini dengan sangat mudah. Ketika obyek kita bergerak ke arah titik klik, jarak antara mereka lebih pendek sehingga nilai mutlak dari jaraknya berkurang juga. Kita dapat melacaknya seperti ini:
1 |
trace(Math.abs(mCircle.x - mouseClickX) ); |
2 |
trace(Math.abs(mCircle.y - mouseClickY) ); |
(Math.abs()
mengubah angka negatif menjadi angka positif dengan hanya mengalikannya dengan -1. Itu tidak berpengaruh pada angka yang sudah positif.)
Anda tidak perlu menambahkan pernyataan trace ini ke kode Anda, saya taruh di sini hanya untuk menunjukkan cara Anda dapat melihat nilai mutlak. Dalam hal ini kedua nilai mutlak adalah kurang dari 3 saat obyek mencapai titik klik. Jadi yang kita butuhkan sekarang adalah menambahkan satu pernyataan if
di dalam fungsi moveTheCircle()
kita.
1 |
function moveTheCircle(e:Event):void |
2 |
{
|
3 |
mCircle.x += Math.cos(myAtan2) * moveAmount; |
4 |
mCircle.y += Math.sin(myAtan2) * moveAmount; |
5 |
|
6 |
//Check if the horizontal and vertical distances from the circle to the mouse point are very close
|
7 |
if (Math.abs(mCircle.x - mouseClickX) < 3 && Math.abs(mCircle.y - mouseClickY) < 3) |
8 |
{
|
9 |
removeEventListener(Event.ENTER_FRAME, moveTheCircle); |
10 |
}
|
11 |
}
|
Ketika nilai mutlak mendapat di bawah 3, listener enter frame dihapus. Kita harus memeriksa nilai mutlak X dan Y karena salah satunya mungkin mencapai 3 bahkan ketika yang kedua belum. Ini berarti obyek mungkin berhenti seperti ini:



Gambar di atas menunjukkan versi di mana hanya nilai mutlak X yang diperiksa. Nilai mutlak jarak X sudah kurang dari 3 sehingga berhenti memperhatikan nilai Y.
Kesimpulan
Yah, itu saja! Saya harap Tip Singkat ini akan membantu Anda memahami beberapa trigonometri yang digunakan dalam pengembangan Flash :)