Bagaimana cara menerapkan balok traktor?

8

Saya sedang mengerjakan permainan di mana pemain dapat mengambil benda menggunakan sesuatu seperti sinar traktor, dan membawanya berkeliling.

Menarik benda ke arah tengah balok tidaklah sulit. Tapi begitu objeknya cukup dekat dengan pusat, saya harus menyimpannya di sana saat pemain bergerak, yang merupakan masalah yang saya alami. Saya dapat memikirkan dua cara untuk melakukannya, dan keduanya memiliki masalah:

  1. Perbarui posisi objek setiap kali posisi pemain berubah, pertahankan posisi tetap di tengah balok.

  2. Perbarui kecepatan objek untuk menunjuk langsung ke pusat balok, semakin jauh, semakin banyak kecepatan.

Bergerak dan berputar bekerja dengan baik dengan kedua pendekatan, tetapi fisika salah ketika benda yang dibawa bertabrakan dengan benda lain:

Dengan pendekatan pertama, fisika diabaikan sepenuhnya. Objek yang dibawa hanya mendorong sesuatu keluar dari jalan. Itu karena perubahan posisi hanya seharusnya dilakukan sebagai bagian dari fisika dunia, berdasarkan kecepatan.

Dengan pendekatan kedua, fisika pada dasarnya berperilaku sebagaimana mestinya, tetapi bereaksi berlebihan. Masalahnya adalah: Untuk menjaga benda yang dibawa di tengah-tengah balok bahkan ketika berputar dan bergerak, saya perlu menggunakan nilai kecepatan tinggi. Jadi, begitu benda yang dibawa menyentuh benda lain, ia mendapat kecepatan yang terlalu banyak dari tabrakan.

Bagaimana saya bisa menerapkan ini dengan benar? Tebakan terbaik saya sekarang adalah untuk pergi dengan pendekatan kedua dan menambahkan penanganan khusus untuk benda yang dibawa ke fisika dunia, mengurangi kecepatan ke nilai waras untuk tabrakan atau ketika pemain berhenti membawa mereka. Tapi itu sepertinya solusi yang cukup canggung.

Sunting: Menambahkan beberapa kode pseudo untuk menggambarkan cara kerjanya sekarang (itu akan menjadi pendekatan kedua di atas)

void attract_object(object, ticks) {
    Vector distance = beam_center - object.center;
    // If the object is not close to the beam center, attract it slowly
    if (magnitude(distance) > 10) {
        object.velocity += distance.normalized() * ticks * 0.1;
        return;
    }

    // Here comes the part we're talking about. That magic 0.5 is just high enough
    // that the object isn't lost while moving around. But it's still so high that
    // other objects are repelled with way too much force.
    object.velocity = distance * ticks * 0.5;
}

Dari apa yang saya lihat, ini terjadi ketika objek yang dibawa mendorong objek lain:

  1. Objek yang dibawa bertabrakan dengan objek lain
  2. Kecepatan objek terdistribusi dengan baik, sehingga objek yang dibawa didorong menjauh dari pusat balok dalam proses
  3. Kode di atas menyebabkan objek yang dibawa untuk kembali ke pusat balok, dengan kecepatan sangat banyak sehingga akan kembali ke sana dengan cepat
  4. Ketika benda yang dibawa bergerak kembali ke tengah balok, setengah dari kecepatan tinggi ditransfer ke objek lain, memukulnya kembali dengan keras. Karena kecepatan awal objek yang diangkut nampak waras, saya dapat membayangkan bahwa langkah 2 hingga 4 diulang beberapa kali, membangun kecepatan tinggi.

Itu tampaknya menjadi penyebabnya. Saya tidak bisa memikirkan cara yang bagus untuk memperbaikinya :(

futlib
sumber
1
Selamat datang di kompleksitas reaktor fusi Tokomak. Anda mendapat manfaat hanya dengan membangun model matematika yang berfungsi, bukan botol magnet yang berfungsi, tetapi matematika itu identik dan non-sepele. Apa yang Anda coba adalah bisa dilakukan, tetapi Anda harus memikirkan model matematika Anda dengan cermat sebelum membuat kode.
Pieter Geerkens

Jawaban:

1

Pada dasarnya apa yang Anda cari adalah memiliki objek 'berseri-seri' berperilaku persis seperti jika Anda akan meraihnya dengan tangan Anda.
Salah satu pilihan adalah membuatnya membagi akselerasi kecepatan a / o dari 'tangan' yang menahannya alih-alih mengatur kecepatannya untuk mengisi celah dengan pusat balok.

Katakanlah pusat balok adalah pegangan. jika karakter Anda berputar 90 derajat ke kiri dalam 1 detik, maka kecepatan tangan akan menjadi:

If R = length of the arm: which is the radius of the rotation circle
R^2 *PI /4 would be the distance traveled over a second.
buatlah kali waktu berlalu frame untuk menemukan kecepatan Anda harus berlaku untuk objek Anda. Temukan normal horizontal ke balok untuk menemukan vektor arahnya.

Maksud saya adalah Anda tidak harus menyelesaikan masalah jika Anda mencoba implementasi lain yang tidak akan menyebabkannya sejak awal.

Saya akan bermain dengan senjata gravitasi di HL2 untuk mendapatkan inspirasi tentang masalah ini, tetapi saya punya rencana lain untuk hari ini.

EDIT: im maaf saya pikir itu untuk beamgun 3D, tetapi pada dasarnya hal yang sama dengan 2D kecuali sumbu berbeda (dan tidak ada geometri yang kompleks)

icosamuel
sumber
Setelah mencoba berbagai peretasan, inilah yang membuat saya di jalur, hasilnya terlihat bagus. Kecepatan tabrakan masih agak terlalu tinggi, tapi saya pikir saya bisa mengetahuinya. Mungkin hanya dengan tidak menarik benda apa pun dengan kecepatan tinggi ke arah yang berbeda.
futlib
Mungkin ketika 'tangan' bertabrakan dengan dinding, Anda dapat menghitung posisi masuk akal terdekat (yaitu tidak bertabrakan) untuk tangan dan menggunakan ini sebagai 'tangan sementara' saat tabrakan terjadi. Saya sering suka melibatkan masalah dari perspektif lain. Saya senang saya bisa membantu dengan itu;).
icosamuel
4

Bagaimana dengan menambahkan koneksi pegas, yaitu memaksa benda yang dibawa untuk bergerak kembali ke posisi carry berdasarkan jarak, tetapi masih memungkinkan untuk didorong oleh benda padat (seperti dinding).

Secara konstan sesuaikan kecepatan benda yang dibawa (dengan mengubah akselerasi berdasarkan posisi / jarak) untuk mengarah ke posisi balok traktor (yaitu pendekatan kedua Anda). Jika objek didorong terlalu jauh, jatuhkan koneksi (dan objek).

Saya tidak begitu yakin mengapa Anda membutuhkan kecepatan tinggi. Terutama kasus "pemain melepaskan" akan menunjukkan bahwa kecepatan rotasi Anda mungkin terlalu tinggi atau tidak realistis. Juga jangan lupakan hal-hal seperti hambatan udara dan gravitasi.


Sunting: Mempertimbangkan kode yang diperbarui, masalahnya agak sepele untuk ditemukan:

if (magnitude(distance) > 10) {
    object.velocity += distance.normalized() * ticks * 0.1;
    return;
}

Masalahnya di sini adalah kasus di mana jarak objek ke posisi tujuannya selalu terlalu jauh (yaitu > 10). Selama kondisi ini benar, kecepatannya hanya meningkat berulang kali (yaitu tanpa batas).

Dua kemungkinan solusi untuk ini:

Tentukan kecepatan maksimum:

object.velocity = min(object.velocity + distance.normalized() * ticks * 0.1, max_velocity);

Terapkan kecepatan tetap daripada mempercepat:

object.velocity = distance.normalized() * ticks * magic_factor;

Hanya mempercepat sementara terlalu jauh jelas merupakan pendekatan yang salah di sini. Hal tentang menarik pegas atau karet gelang: Tidak masalah apakah Anda memegangnya selama satu detik atau satu menit. Pada akhirnya itu akan mempercepat dengan cara yang sama (mengingat itu belum bergerak dan tidak ada kekuatan lain yang diterapkan).

Mario
sumber
Itu yang saya jelaskan dalam metode 2, bukan? Itulah fisika pegas dasar AFAIK. Saya akan menambahkan beberapa kode ke pertanyaan di atas untuk menggambarkannya.
futlib
Juga menghapus bagian tentang kecepatan yang salah di atas, itu sebenarnya baik-baik saja, hanya mengujinya. Jadi hanya tabrakan dengan benda lain yang berantakan.
futlib
Ya itu pada dasarnya pendekatan kedua Anda. Memperbarui jawaban saya.
Mario
Mencoba kedua pendekatan, tetapi tidak membantu. Sepertinya magnitudo (jarak)> 10 kasing bukanlah penyebabnya di sini. Saya mencoba membatasi kecepatan untuk kasus <=, tetapi ini adalah masalah biasa: Kecepatannya sangat rendah sehingga objek dijatuhkan, atau begitu tinggi sehingga mengusir orang lain dengan keras.
futlib
"begitu tinggi sehingga mengusir orang lain dengan kasar": Anda harus memindahkan objek lain berdasarkan kecepatan efektif, bukan kecepatan di belakang layar (yaitu, atur ulang kecepatan karena tabrakan).
Mario