Saya mulai belajar bagaimana fisika DIY, dan saya punya pertanyaan tentang menerapkan integrasi pada tingkat paling dasar (yaitu ini bukan pertanyaan Euler vs RK4).
Hampir setiap contoh yang saya temui memiliki beberapa integrate()
fungsi yang mendapat catatan waktu sejak pembaruan terakhir, dan memperbarui percepatan (dan / atau kecepatan dan / atau posisi) sejak pembaruan terakhir.
Dalam bentuk yang paling sederhana: position += velocity * deltaTime
Namun, saya tidak mengerti mengapa itu terakumulasi seperti ini ketika bisa dengan mudah didapat dengan mengubah suatu fungsi . Misalnya: getPosition = makeNewFunction()
yang dapat mengembalikan sesuatu yang memiliki tanda tangan Time -> Position
, dan cara kerja fungsi tersebut dihasilkan melalui rumus matematika yang sesuai.
Dengan begitu, tidak ada akumulasi ... kapan pun posisi perlu didapatkan, ia memanggil fungsi itu dengan waktu saat ini.
Pemahaman pemula saya adalah bahwa ini juga akan menghindari kesalahan yang berasal dari akumulasi ... jadi mengapa ini tidak berhasil, apa yang saya lewatkan?
(Fwiw saya memang mengumpulkan bukti dasar konsep ide ini - meskipun itu juga menguji beberapa hal lain pada saat yang sama sehingga itu bukan contoh terbersih: https://github.com/dakom/ball-bounce-frp )
EDIT 1: seperti yang disebutkan dalam komentar, mungkin penting untuk menunjukkan bahwa saya belum belajar tentang mengubah akselerasi, atau berurusan dengan brengsek dan hal-hal lain yang memerlukan integrasi tingkat tinggi daripada akselerasi konstan.
EDIT 2: di sini adalah beberapa contoh kode dasar ide, dan pseudo javascript sintaks - catatan yang getKinematicPosition
adalah sebagian diterapkan sehingga mengembalikan fungsi baru saja Waktu -> Posisi:
Saya berpegang teguh pada posisi di sini tetapi itu bisa menjadi sesuatu yang lain, seperti getVelocity
, saya kira ...
getKinematicPosition = initialVelocity => acceleration => time =>
((.5 *acceleration) * (time * time)) + (initialVelocity * time);
getPosition = getKinematicPosition ([0,0,0]) (GRAVITY);
onTick = totalTime => {
position = getPosition (totalTime);
onCollision = () => {
getPosition = changeTheFunction(totalTime);
//changeTheFunction uses totalTime to base updates from 0
//it could use getKinematicPosition or something else entirely
}
}
sumber
Jawaban:
Ini akan bekerja untuk kelas masalah tertentu, dan frasa kunci untuk mencari adalah solusi bentuk-tertutup . Misalnya, dalam Program Luar Angkasa Kerbal, gerakan pesawat ruang angkasa di orbit dihitung dengan cara ini. Sayangnya, sebagian besar masalah non-sepele (misalnya masuknya kembali atmosfer dari pesawat ruang angkasa tersebut) tidak memiliki solusi bentuk tertutup yang diketahui. Dengan demikian kebutuhan akan pendekatan numerik yang lebih sederhana secara matematis (yaitu
integrate()
seiring waktu).sumber
Masalah dengan pendekatan Anda adalah, bahwa Anda tidak memiliki riwayat objek Anda. Anda dapat menghitung posisi jika Anda bergerak ke suatu arah, tetapi apa yang terjadi jika Anda menekan sesuatu dan bangkit kembali?
Jika Anda terakumulasi dari posisi terakhir yang diketahui, Anda dapat menangani dampaknya dan melanjutkan dari sana. Jika Anda mencoba menghitungnya dari awal, Anda harus menghitung ulang dampaknya setiap waktu, atau menetapkannya sebagai posisi awal yang baru.
Teladan Anda mengingatkan saya pada sebuah game balapan. (Saya tidak tahu apakah posisi akan dikontrol oleh mesin fisika, tetapi saya pikir itu bekerja dengan baik untuk menjelaskan)
Jika Anda mengemudi dengan mobil Anda, Anda dapat mempercepat dan memperlambat. Anda tidak dapat menghitung posisi Anda tanpa mengetahui bagaimana profil kecepatan mobil Anda terlihat dari awal hingga sekarang. Akumulasi jaraknya jauh lebih mudah daripada menyimpan kecepatan yang Anda miliki di setiap frame dari awal hingga sekarang.
Penafian: Saya belum menulis fisika permainan saat ini, begitulah cara saya melihat masalahnya.
Sunting:
Di diagram ini Anda dapat melihat bagaimana nilai berubah seiring waktu.
merah = akselerasi (dari mulai akselerasi ke sloving down)
hijau = kecepatan (dari mulai berhenti)
biru = cara Anda pergi.
Kecepatan total adalah bagian integral dari akselerasi dari titik awal Anda ke log aktual Anda. (Area antara garis dan sumbu)
Jalan adalah integral dari kecepatan Anda.
Jika Anda tahu nilai untuk akselerasi Anda, Anda bisa menghitung nilai lainnya. Tetapi jika saya tidak salah apakah integral juga dihitung dengan akumulasi pada PC. Dan itu jauh lebih mahal untuk menyimpan semua nilai percepatan.
Plus itu mungkin terlalu banyak untuk dihitung setiap frame.
Saya tahu, keterampilan melukis saya luar biasa. ;)
Sunting 2:
Contoh ini untuk gerakan linier. Arah canging membuat ini semakin sulit.
sumber
Kamu bisa!
Ini disebut menggunakan solusi bentuk analitis atau tertutup . Ini memiliki manfaat yang lebih akurat, karena kesalahan pembulatan yang menumpuk dari waktu ke waktu tidak ada.
Namun, ini berfungsi jika dan hanya jika Anda tahu formulir tertutup sebelumnya. Untuk permainan, ini cukup sering tidak terjadi.
Gerakan pemain tidak menentu dan tidak bisa dimasukkan ke dalam beberapa fungsi yang sudah dihitung sebelumnya. Pemain dapat dan akan mengubah kecepatan dan orientasinya dengan cukup sering.
NPC berpotensi memanfaatkan solusi bentuk tertutup, dan pada kenyataannya kadang-kadang mereka melakukannya. Namun ini memiliki beberapa kelemahan lainnya. Pikirkan tentang game balap sederhana. Setiap kali kendaraan Anda bertabrakan dengan kendaraan lain, Anda harus mengubah fungsi Anda. Mungkin mobil bergerak lebih cepat tergantung dari bawah tanah. Maka menemukan solusi bentuk tertutup seperti itu akan sangat sulit. Bahkan, ada kemungkinan lebih banyak kasus di mana menemukan bentuk tertutup seperti itu tidak mungkin atau sangat rumit sehingga sama sekali tidak layak.
Contoh yang bagus untuk menggunakan solusi bentuk tertutup adalah Program Luar Angkasa Kerbal. Begitu roket Anda berada di orbit dan tidak didorong, KSP dapat meletakkannya "di atas rel". Orbits sudah ditentukan sebelumnya dalam sistem dua tubuh, dan bersifat periodik. Selama roket tidak lagi menggunakan gaya dorong, Anda sudah tahu di mana roket akan berada, dan Anda bisa memanggilnya
getPositionAtTime(t)
(tidak disebutkan persis seperti itu, tetapi Anda mendapatkan ide).Namun dalam praktiknya, hanya menggunakan integrasi langkah demi langkah seringkali jauh lebih praktis. Tetapi ketika Anda melihat situasi di mana solusi bentuk tertutup ada dan mudah untuk dihitung, lakukan! Tidak ada alasan untuk tidak menggunakannya.
Misalnya, jika karakter Anda mengarahkan meriam, Anda dapat dengan mudah menunjukkan titik tumbukan bola meriam yang diprediksi menggunakan solusi bentuk-tertutup. Dan, jika gim Anda tidak memungkinkan untuk mengubah arah bola meriam (tidak ada angin misalnya), Anda bahkan dapat menggunakannya untuk memindahkan bola meriam. Perhatikan bahwa Anda perlu berhati-hati terhadap rintangan yang bergerak ke jalur bola meriam Anda.
Ada banyak situasi serupa. Jika Anda membuat game berbasis bulat, maka ada kemungkinan akan ada solusi bentuk tertutup yang jauh lebih banyak daripada saat membangun game RTS, karena Anda tahu semua parameter sebelumnya dan dapat mengatakan dengan pasti bahwa itu tidak berubah (tidak ada yang bergerak tiba-tiba ke jalan itu, misalnya).
Perhatikan bahwa ada teknik untuk memerangi ketidakakuratan numerik dari integrasi bertahap. Misalnya, Anda dapat melacak akumulasi kesalahan dan menerapkan istilah korektif untuk menjaga kesalahan dalam pemeriksaan, misalnya Penjumlahan Kahan
sumber
Dalam kasus bola memantul sederhana, datang dengan solusi bentuk tertutup mudah. Namun, sistem yang lebih kompleks cenderung membutuhkan penyelesaian Persamaan Diferensial Biasa (ODE). Pemecah angka diperlukan untuk menangani semua kasus kecuali yang paling sederhana.
Memang ada dua kelas pemecah ODE numerik: eksplisit dan implisit. Pemecah eksplisit memberikan perkiraan bentuk tertutup untuk keadaan Anda berikutnya, sementara pemecah implisit membutuhkan penyelesaian persamaan untuk melakukannya. Apa yang Anda gambarkan untuk bola memantul Anda sebenarnya adalah pemecah ODE implisit, terlepas Anda mengetahuinya atau tidak!
Pemecah implisit memiliki keuntungan karena dapat menggunakan langkah waktu yang jauh lebih besar. Untuk algoritme bola pantul Anda, tanda waktu Anda dapat setidaknya sebesar durasi hingga tabrakan berikutnya (yang akan mengubah fungsi Anda). Ini dapat membuat program Anda berjalan lebih cepat. Namun, secara umum, kami tidak selalu dapat menemukan solusi implisit yang baik untuk ODE yang kami minati. Ketika kami tidak bisa, kami kembali ke integrasi eksplisit.
Keuntungan besar yang saya lihat dengan integrasi eksplisit adalah bahwa gotcha sudah terkenal. Anda dapat membuka buku teks apa pun dari tahun 60-an dan membaca semua yang perlu Anda ketahui tentang keanehan kecil yang muncul dengan teknik integrasi tertentu. Dengan demikian, pengembang mempelajari keterampilan ini sekali, dan mereka tidak perlu mempelajarinya lagi. Jika Anda melakukan integrasi implisit, setiap use case sedikit berbeda, dengan gotcha yang sedikit berbeda. Agak sulit untuk menerapkan apa yang Anda pelajari dari satu tugas ke yang berikutnya.
sumber
pos (t) = v (t) * t
hanya berfungsi jika pos (0) = 0 dan v (t) = k
Anda tidak dapat menghubungkan posisi ke waktu tanpa mengetahui kondisi awal dan seluruh fungsi kecepatan, sehingga persamaannya adalah sebagai perkiraan dari integral
pos (t) = integral dari v (t) dt dari 0 hingga t
EDIT _________
Inilah sedikit bukti per komentar (dengan asumsi pos (0) = 0)
biarkan v (t) = 4
eqn 1: pos (t) = 4 * t (benar)
eqn 2: pos (t) = c + 4 * t dari 0 hingga t = 4 * t (benar)
biarkan v (t) = 2 * t
eqn 1: pos (t) = 2 * t ^ 2 (salah)
eqn 2: pos (t) = c + t ^ 2 dari 0 hingga t = t ^ 2 (benar)
Saya harus menambahkan bahwa persamaan Anda sudah menjadi faktor dalam percepatan konstan (yaitu persamaan Anda adalah eqn 2 di mana v (t) = v0 + a * t dan batas integrasi adalah t0 dan t), sehingga persamaan Anda harus berfungsi selama Anda memperbarui posisi awal, kecepatan awal, dan akselerasi tetap konstan.
EDIT2 ________
Saya juga harus menambahkan bahwa Anda juga dapat menghitung posisi dengan posisi awal, kecepatan awal, percepatan awal, dan sentakan konstan. Dengan kata lain, Anda dapat membuat fungsi berdasarkan persamaan 2 yang mewakili posisi vs waktu dengan memisahkannya menjadi turunannya yaitu kecepatan, brengsek, apa pun yang terjadi selanjutnya, dll, dll, dll, tetapi Anda hanya akan akurat dalam persamaan Anda jika v (t) dapat dimodelkan seperti itu. Jika v (t) tidak dapat dimodelkan hanya dengan kecepatan, akselerasi, brengsek konstan, dll, maka Anda perlu kembali ke perkiraan eqn 2, yang cenderung terjadi ketika Anda memiliki sesuatu yang memantul, hambatan udara, angin, dll. .
sumber