OK, saya sudah memposting ini di math.stackechange.com tetapi tidak mendapatkan jawaban :(
Pertama di sini adalah gambar masalah saya, uraian berikut setelahnya:
Jadi saya mengatur semua poin dan nilai.
Kapal mulai bergerak di sekitar planet kiri P1
dengan S=0.27 Degrees
per gametick, ketika mencapai Point A
itu mulai mengikuti kurva bezier sampai mencapai Point D
, kemudian bergerak di sekitar planet kanan P2
dengan S=0.42 Degrees
per centang game. Perbedaannya S
adalah agar perjalanan dengan kecepatan gerakan yang sama di sekitar planet.
Sejauh ini bagus, saya bisa menjalankannya, sekarang masalah saya.
Kapan S P1
dan sangat S P2
berbeda, kapal melompat di antara dua kecepatan ketika mencapai tujuan itu, yang terlihat sangat buruk. Jadi saya perlu mempercepat kapal antara Point A
dan Point D
dari S P1
ke S P2
.
Hal yang saya lewatkan berwarna ungu, yaitu:
Cara untuk menghitung kutu diperlukan kapal untuk bergerak di sepanjang bezier dengan mempertimbangkan akselerasi.
Dan cara untuk menemukan posisi pada kurva bezier berdasarkan T, sekali lagi mempertimbangkan akselerasi.
ATM Saya menghitung panjang bezier dengan menghitung jarak antara N
titik-titiknya. Jadi apa yang saya pikir saya butuhkan, adalah cara untuk skala T
saya perlu dimasukkan ke dalam perhitungan bezier saya sesuai dengan percepatan
sumber
Jawaban:
OK, saya punya semuanya berfungsi, butuh selamanya, jadi saya akan memposting solusi rinci saya di sini.
Catatan: Semua sampel kode dalam JavaScript.
Jadi mari kita uraikan masalahnya menjadi beberapa bagian dasar:
Anda harus menghitung panjangnya, serta titik-titik di antara
0..1
kurva bezierAnda sekarang perlu menyesuaikan skala Anda
T
untuk mempercepat kapal dari satu kecepatan ke kecepatan lainMemperbaiki Bezier dengan benar
Menemukan beberapa kode untuk menggambar kurva Bezier itu mudah, ada beberapa pendekatan yang berbeda, salah satunya adalah Algoritma DeCasteljau , tetapi Anda juga bisa menggunakan persamaan untuk kurva Bézier kubik:
Dengan ini, satu sekarang dapat menggambar kurva bezier dengan menelepon
x
dany
dengant
yang berkisar dari0 to 1
, mari kita lihat:Eh ... itu bukan benar-benar distribusi poin, kan?
Karena sifat kurva Bézier, titik-titik pada
0...1
memiliki perbedaanarc lenghts
, sehingga segmen di dekat awal dan akhir, lebih panjang daripada yang dekat dengan tengah kurva.Memetakan T secara merata pada kurva parameterisasi panjang busur AKA
Jadi apa yang harus dilakukan? Nah secara sederhana kita membutuhkan fungsi untuk memetakan kita
T
ket
kurva, sehinggaT 0.25
hasilt
kita berada25%
pada panjang kurva.Bagaimana kita melakukannya? Baiklah, kami Google ... tetapi ternyata istilah itu tidak dapat diunduh dari Google , dan pada titik tertentu Anda akan menemukan PDF ini . Yang pasti adalah bacaan yang bagus, tetapi jika Anda sudah lupa semua hal matematika yang Anda pelajari di sekolah (atau Anda tidak suka simbol-simbol matematika) itu sangat tidak berguna.
Apa sekarang? Baiklah dan Google lagi (baca: 6 jam), dan Anda akhirnya menemukan artikel yang bagus tentang topik tersebut (termasuk gambar yang bagus! ^ _ ^ "):
Http://www.planetclegg.com/projects/WarpingTextToSplines.html
Melakukan kode yang sebenarnya
Jika Anda tidak bisa menolak mengunduh PDF itu meskipun Anda sudah kehilangan pengetahuan matematis Anda sejak dulu, dan Anda berhasil melewati tautan artikel yang hebat , Anda mungkin sekarang berpikir: "Ya Tuhan, ini akan membutuhkan ratusan baris kode dan berton-ton CPU "
Tidak, tidak akan. Karena kami melakukan apa yang semua programmer lakukan, ketika sampai pada soal matematika:
Kami hanya curang.
Parameterisasi panjang busur, cara malas
Mari kita hadapi itu, kita tidak perlu ketelitian tanpa akhir dalam permainan kita, bukan? Jadi kecuali Anda bekerja di NASA dan berencana mengirim orang-orang Mars, Anda tidak akan membutuhkan
0.000001 pixel
solusi yang sempurna.Jadi bagaimana kita memetakan
T
ket
? Ini sederhana dan hanya terdiri dari 3 langkah:Hitung
N
titik pada kurva menggunakant
dan menyimpanarc-length
(alias panjang kurva) pada posisi itu ke dalam arrayUntuk memetakan
T
ket
, yang pertama kaliT
dengan total panjang kurva untuk mendapatkanu
dan kemudian mencari array panjang untuk indeks dari nilai terbesar yang lebih kecil dariu
Jika kami memiliki hit yang tepat, kembalikan nilai array pada indeks itu dibagi dengan
N
, jika tidak menginterpolasi sedikit antara titik yang kami temukan dan yang berikutnya, bagi hal itu sekali lagi denganN
dan kembali.Itu saja! Jadi sekarang mari kita lihat kode lengkapnya:
Ini menginisialisasi kurva baru kami dan menghitung
arg-lenghts
, itu juga menyimpan yang terakhir dari panjang sebagaitotal length
kurva, faktor kunci di sini adalahthis.len
yang kamiN
. Semakin tinggi, semakin akurat pemetaannya, karena kurva ukuran pada gambar di atas100 points
tampaknya sudah cukup, jika Anda hanya perlu perkiraan panjang yang baik, sesuatu seperti25
sudah akan melakukan pekerjaan dengan hanya memiliki 1 pixel di contoh, tetapi kemudian Anda akan memiliki pemetaan yang kurang tepat yang akan menghasilkan distribusi tidak merataT
saat dipetakan ket
.Kode pemetaan yang sebenarnya, pertama-tama kita lakukan sederhana
binary search
pada panjang yang disimpan untuk menemukan panjang terbesar yang lebih keciltargetLength
, lalu kita kembali atau melakukan interpolasi dan kembali.Sekali lagi ini menghitung
t
pada kurva.Waktunya untuk hasil
Dengan sekarang menggunakan
mx
danmy
Anda mendapatkan merataT
pada kurva :)Bukankah itu sulit, bukan? Sekali lagi, ternyata solusi sederhana (walaupun bukan solusi sempurna) akan cukup untuk sebuah gim.
Jika Anda ingin melihat kode lengkap, ada inti yang tersedia:
https://gist.github.com/670236
Akhirnya, mempercepat kapal
Jadi yang tersisa sekarang adalah mempercepat kapal di sepanjang jalurnya, dengan memetakan posisi
T
yang akan kita gunakan untuk menemukant
kurva kita.Pertama kita perlu dua persamaan gerak , yaitu
ut + 1/2at²
dan(v - u) / t
Dalam kode aktual yang akan terlihat seperti ini:
Kemudian kami menurunkannya
0...1
dengan melakukan:Dan begitulah, kapal sekarang bergerak dengan lancar di sepanjang jalan.
Jika tidak berfungsi ...
Ketika Anda membaca ini, semuanya bekerja dengan baik dan keren, tetapi saya awalnya memiliki beberapa masalah dengan bagian akselerasi, ketika menjelaskan masalah tersebut kepada seseorang di ruang obrolan gamedev, saya menemukan kesalahan terakhir dalam pemikiran saya.
Jika Anda belum lupa tentang gambar dalam pertanyaan asli, saya sebutkan di
s
sana, ternyata itus
adalah kecepatan dalam derajat , tetapi kapal-kapal bergerak di sepanjang jalan dalam piksel dan saya lupa tentang fakta itu. Jadi yang perlu saya lakukan dalam hal ini adalah mengubah perpindahan dalam derajat menjadi perpindahan dalam piksel, ternyata ini lebih mudah:Jadi itu saja! Terima kasih sudah membaca ;)
sumber
Masalahnya adalah bahwa kapal tidak akan mengambil lintasan itu secara alami. Jadi, meskipun bekerja dengan sempurna, tetap saja tidak akan terlihat benar.
Jika Anda ingin mensimulasikan transisi yang mulus antar planet, saya akan menyarankan untuk memodelkannya. Persamaannya sangat sederhana karena Anda hanya memiliki dua kekuatan signifikan: gravitasi, dan daya dorong.
Anda hanya perlu mengatur konstanta Anda: Massa P1, P2, kirim
Dengan setiap centang game (waktu: t) Anda melakukan 3 hal
Hitung gravitasi p1 di kapal dan p2 di kapal, tambahkan vektor yang dihasilkan ke vektor dorong.
Hitung kecepatan baru Anda berdasarkan akselerasi baru Anda dari langkah 1
Pindahkan kapal sesuai dengan kecepatan baru Anda
Mungkin tampak seperti banyak pekerjaan tetapi dapat dilakukan dalam selusin baris kode dan akan terlihat sangat alami.
Jika Anda perlu bantuan dengan fisika, beri tahu saya.
sumber
t
:)Saya menemukan artikel yang bagus menjelaskan kemungkinan solusi untuk masalah ini dengan contoh kode yang ditulis dalam javascript. Ini bekerja dengan "mendorong nilai t" ke arah yang benar.
Pertanyaan ini sudah memiliki banyak jawaban keren, tetapi saya menemukan solusi ini layak diperhatikan.
sumber
Terima kasih atas halaman hebat Anda yang menjelaskan bagaimana Anda memecahkan masalah ini. Saya melakukan sesuatu yang agak berbeda dari Anda dalam satu detail, karena saya sangat terkandung dalam memori: Saya tidak membangun sebuah array, atau harus mencarinya untuk 'segmen' yang tepat dengan pencarian biner. Ini karena saya selalu tahu saya bergerak dari satu ujung kurva Bezier saya ke yang lain: Oleh karena itu, saya hanya mengingat segmen 'saat ini', dan jika saya melihat bahwa saya akan keluar dari batas-batas segmen tersebut untuk menghitung berikutnya posisi, saya menghitung segmen berikutnya (atau sebelumnya) (berdasarkan arah perjalanan.) Ini berfungsi dengan baik untuk aplikasi saya. Satu-satunya kesalahan yang harus saya selesaikan adalah, dalam beberapa kurva, ukuran segmennya sangat kecil sehingga plot berikutnya yang saya tunjukkan adalah - pada waktu yang jarang - lebih dari satu segmen di depan yang sekarang, jadi alih-alih hanya pergi ke '
Tidak tahu apakah ini cukup masuk akal, tetapi ini tentu membantu saya.
sumber
Pemodelan semacam itu aneh, dan dapat menghasilkan hasil yang tidak masuk akal aneh. Apalagi jika kecepatan planet mulai benar-benar lambat.
Model kapal dengan daya dorong.
Ketika kapal berada di orbit terakhir mereka di planet awal, berakselerasi dengan penuh.
Ketika kapal berada dalam jarak tertentu, gunakan dorongan terbalik untuk memperlambat kapal ke kecepatan orbit planet target.
Sunting: Lakukan seluruh simulasi sekaligus ketika sebuah simpul hendak meninggalkan orbit. baik mengirim semua data, atau mengirim hanya beberapa vektor gerakan pada interval, dan interpolasi di antara mereka.
sumber
Jika saya memahaminya dengan benar, masalah Anda terlalu dibatasi.
Saya percaya bahwa Anda ingin pesawat ruang angkasa untuk melakukan perjalanan di sepanjang jalur yang ditentukan antara orbit dalam beberapa waktu t , dan Anda juga ingin itu mempercepat dari kecepatan s1 ke kecepatan s2 dalam waktu yang sama t . Sayangnya, Anda tidak dapat (secara umum) menemukan akselerasi yang memenuhi kedua kendala ini secara bersamaan.
Anda harus sedikit merilekskan masalah Anda untuk menyelesaikannya.
sumber
Saya menemukan jawaban ini karena saya mencari untuk mendistribusikan poin secara merata di sepanjang jalur svg yang menggunakan kurva bezier.
Meskipun MDN mengatakan itu sudah usang, Anda dapat menggunakan
path.getPointAtLength
untuk mendapatkan hasil yang benar. https://developer.mozilla.org/en-US/docs/Web/API/SVGPathElement/getPointAtLengthSaat ini berfungsi di Chrome / Safari / Firefox, dan seharusnya bekerja di IE / Edge juga, tetapi saya tidak memverifikasi mereka 2.
sumber
Masalah dengan solusi yang diterima
Karena Bezier merupakan fungsi eksponensial , kami mengharapkan tingkat kemajuan yang berbeda di berbagai area kurva.
Karena solusi Ivo secara linear menginterpolasi antara sampel eksponensial awal ini , ketidakakuratan akan sangat bias terhadap ujung / tengah kurva (biasanya kubik) di mana delta-delta itu terbesar; jadi kecuali laju sampel
N
meningkat sangat seperti yang disarankannya, kesalahan tampak jelas, dan pada tingkat zoom tertentu, akan selalu terlihat jelas untuk yang diberikanN
, yaitu bias bersifat intrinsik untuk algoritma itu. Tidak bagus untuk misalnya grafik berbasis vektor di mana zoom mungkin tidak terbatas.Melawan bias melalui sampling terpandu
Sebuah solusi alternatif adalah untuk remap linear
distance
untukt
setelah melawan bias alam yang fungsi Bezier menghasilkan.Dengan asumsi inilah yang kami inginkan:
tapi inilah yang kami dapatkan dari fungsi posisi Bezier:
Dengan melihat
N
sampel yang diambil, kita dapat melihat di mana jarak delta terbesar, dan resample ("split") di tengah-tengah antara dua jarak yang berdekatan, meningkatN
sebesar 1. Misalnya, membelah padat=0.9
(yang merupakan tengah di delta terbesar), kita mungkin mendapatkan:Kami mengulangi proses ini untuk interval jarak terbesar berikutnya sampai delta maksimum antara dua jarak di seluruh rangkaian berada di bawah beberapa
minDistanceDelta
, dan lebih khusus, kurangepsilon
dari jarak tertentu yang ingin kami petakan ke langkah-langkaht
; kita kemudian dapat memetakant
langkah-langkah yang diinginkan secara linear kedistance
s yang sesuai . Ini menghasilkan hashtable / peta yang bisa Anda akses dengan murah dan yang nilainya Anda dapat lerp di antara, saat runtime, tanpa bias.Ketika set tumbuh
N
, biaya untuk mengulangi ini meningkat, jadi idealnya lakukan ini sebagai pra-proses. Setiap kaliN
meningkat, tambahkan dua interval resultan baru keintervals
koleksi sambil menghapus lama, interval tunggal yang mereka ganti. Ini adalah struktur tempat Anda bekerja untuk menemukan interval terbesar berikutnya untuk dipecah menjadi dua. Menyortirintervals
berdasarkan jarak membuat segalanya mudah, karena Anda bisa menghapus item pekerjaan berikutnya dari ujung, dan membagi dll.Kita berakhir dengan sesuatu seperti yang kita inginkan:
Karena kami mengambil tebakan pada setiap langkah, kami tidak akan mendapatkan tepat jarak yang tepat
2
,4
dll. Yang kami inginkan, tetapi melalui pengulangan berulang-ulang ini cukup dekat dengan nilai jarak yang diinginkan sehingga Anda dapat memetakan ket
langkah Anda dengan akurasi yang adil, menghilangkan bias akibat untuk pengambilan sampel yang hampir setara.Anda kemudian dapat mengambil mis
t=0.5
, seperti yang dilakukan Ivo dalam jawabannya, yaitu dengan menyisipkan antara dua nilai terdekat di atas (3.9998132
dan6.00703
).Kesimpulan
Untuk sebagian besar kasus, solusi Ivo akan bekerja dengan baik, tetapi untuk kasus-kasus di mana bias harus dihindari dengan cara apa pun, pastikan bahwa Anda
distance
tersebar sebanyak mungkin, dan kemudian dipetakan secara lineart
.Perhatikan bahwa pemisahan dapat dilakukan secara stokastik daripada pemisahan di tengah setiap kali, misalnya kita mungkin telah membagi interval contoh pertama di
t=0.827
daripada dit=0.9
.sumber