Saya mencoba untuk membuat sambungan memutar dengan lancar di sekitar tengah kanvas, ke arah penunjuk mouse. Apa yang saya punya bekerja, tapi saya ingin menghidupkan jarak sesingkat mungkin ke sudut mouse. Masalah terjadi ketika nilai loop di sekitar garis horizontal ( 3.14
dan -3.14
). Arahkan mouse ke area itu untuk melihat bagaimana arah berubah dan dibutuhkan waktu yang lama untuk kembali.
Kode yang relevan
// ease the current angle to the target angle
joint.angle += ( joint.targetAngle - joint.angle ) * 0.1;
// get angle from joint to mouse
var dx = e.clientX - joint.x,
dy = e.clientY - joint.y;
joint.targetAngle = Math.atan2( dy, dx );
Bagaimana saya bisa membuatnya memutar jarak terpendek, bahkan "melintasi celah"?
mathematics
javascript
animation
lerp
easing
jackrugile
sumber
sumber
Jawaban:
Ini tidak selalu merupakan metode terbaik, dan itu bisa lebih mahal secara komputasi (meskipun ini pada akhirnya tergantung pada bagaimana Anda menyimpan data Anda), tetapi saya akan membuat argumen bahwa nilai-nilai lerping 2D bekerja cukup baik di sebagian besar kasus. Alih-alih sudut sudut yang diinginkan, Anda dapat lerp vektor arah dinormalisasi yang diinginkan .
Salah satu keuntungan dari metode ini daripada metode “pilih rute terpendek ke sudut” adalah bahwa metode ini berfungsi ketika Anda perlu menyisipkan di antara lebih dari dua nilai.
Saat menyaring nilai rona, Anda bisa menggantinya
hue
dengan[cos(hue), sin(hue)]
vektor.Dalam kasus Anda, lerping arah sendi yang dinormalisasi:
Kode bisa lebih pendek jika Anda dapat menggunakan kelas vektor 2D. Contohnya:
sumber
dx /= len
...len ? len : 1.0
hanya menghindari pembagian dengan nol, dalam kasus yang jarang bahwa mouse ditempatkan tepat pada posisi bersama. Ini bisa saja ditulis:if (len != 0) dx /= len;
.0°
dan180°
? Dalam bentuk vektor:[1, 0]
dan[-1, 0]
. Interpolasi vektor akan memberikan Anda baik0°
,180°
, atau bagi dengan 0 error, dalam kasust=0.5
.Kuncinya adalah untuk mengingat bahwa sudut (setidaknya dalam ruang Euclidean) adalah periodik dengan 2 * pi. Jika perbedaan antara sudut saat ini dan sudut target terlalu besar (mis. Kursor telah melewati batas), sesuaikan sudut arus dengan menambahkan atau mengurangi 2 * pi.
Dalam hal ini, Anda dapat mencoba yang berikut ini: (Saya belum pernah memprogram dalam Javascript sebelumnya, jadi maafkan gaya koding saya.)
EDIT : Dalam implementasi ini, memindahkan kursor terlalu cepat di sekitar pusat sambungan menyebabkannya menyentak. Ini adalah perilaku yang dimaksudkan, karena kecepatan sudut sendi selalu sebanding dengan
dtheta
. Jika perilaku ini tidak diinginkan, masalah dapat dengan mudah diperbaiki dengan menempatkan tutup pada percepatan sudut sambungan.Untuk melakukan ini, kita harus melacak kecepatan sambungan dan memaksakan akselerasi maksimum:
Kemudian, untuk kenyamanan kami, kami akan memperkenalkan fungsi kliping:
Sekarang, kode gerakan kami terlihat seperti ini. Pertama, kami menghitung
dtheta
seperti sebelumnya, menyesuaikanjoint.angle
seperlunya:Kemudian, alih-alih menggerakkan sambungan segera, kami menghitung kecepatan target dan menggunakannya
clip
untuk memaksanya dalam rentang yang dapat kami terima.Ini menghasilkan gerakan yang halus, bahkan saat berganti arah, saat melakukan perhitungan hanya dalam satu dimensi. Selain itu, memungkinkan kecepatan dan percepatan sambungan disesuaikan secara independen. Lihat demo di sini: http://codepen.io/anon/pen/HGnDF/
sumber
dtheta
. Apakah Anda berniat untuk bersama memiliki momentum?Saya suka jawaban lain yang diberikan. Sangat teknis!
Jika Anda mau, saya punya metode yang sangat sederhana untuk mencapai ini. Kami akan mengasumsikan sudut untuk contoh-contoh ini. Konsep ini dapat diekstrapolasi ke tipe nilai lainnya, seperti warna.
Saya baru saja membuat ini di browser dan belum pernah diuji. Saya harap saya mendapatkan logika yang benar pada percobaan pertama.
[Sunting] 2017/06/02 - Jelaskan sedikit logika.
Mulai dengan menghitung distanceForward dan distanceBackwards, dan biarkan hasilnya melampaui batas (0-360).
Sudut normalisasi mengembalikan nilai-nilai tersebut ke kisaran (0-360). Untuk melakukan ini, Anda menambahkan 360 hingga nilainya di atas nol, dan kurangi 360 sementara nilainya di atas 360. Sudut awal / akhir yang dihasilkan akan menjadi setara (-285 sama dengan 75).
Anda selanjutnya menemukan sudut Normalisasi terkecil dari distanceForward atau distanceBackward. distanceForward dalam contoh menjadi 75, yang lebih kecil dari nilai normal distanceBackward (300).
Jika distanceForward adalah yang terkecil DAN endAngle <startAngle, perpanjang endAngle di luar 360 dengan menambahkan 360. (menjadi 375 dalam contoh).
Jika distanceBackward adalah yang terkecil DAN endAngle> startAngle, perpanjang endAngle ke bawah 0 dengan mengurangi 360.
Anda sekarang akan beralih dari startAngle (300) ke endAngle baru (375). Mesin harus secara otomatis menyesuaikan nilai di atas 360 dengan mengurangi 360 untuk Anda. Kalau tidak, Anda harus lerp dari 300 ke 360, MAKA lerp dari 0 hingga 15 jika mesin tidak menormalkan nilai untuk Anda.
sumber
atan2
ide dasarnya sederhana, yang ini bisa menghemat ruang dan sedikit kinerja (tidak perlu menyimpan x dan y, juga untuk menghitung dosa, cos dan atan2 terlalu sering). Saya pikir perlu sedikit diperluas tentang mengapa solusi ini benar (yaitu memilih jalur terpendek pada lingkaran atau bola, seperti halnya SLERP untuk quaterions). Pertanyaan dan jawaban ini harus dimasukkan dalam komunitas wiki karena ini adalah masalah yang sangat umum dihadapi kebanyakan programmer gameplay.