Unity - Cara memindahkan kapal secara realistis ke titik dalam permainan top-down 2D

14

Saya mencoba untuk memindahkan kapal layar ke titik di mana saya mengklik dengan mouse. gerakan ini harus realistis (dayung di belakang di mana kapal bergerak) jadi jika klik mouse kiri dan di depan kapal kapal kemudian harus pindah ke sana dengan jalur melengkung untuk memiliki rotasi yang tepat

Saya akan senang jika seseorang dapat membantu saya dengan masalah ini, terima kasih pergerakan kapal

DavidT
sumber
1
Seperti gambar Anda tampaknya menggambarkan layar: Haruskah angin diperhitungkan? Beberapa manuver tidak mungkin dilakukan dengan angin yang salah atau kekurangannya.
Tidak ada yang
Lebih penting lagi, pergerakan kapal layar yang tampak realistis benar - benar membutuhkan pertimbangan angin; mengabaikannya akan hampir seperti mengabaikan gravitasi ketika menerapkan lompatan. Anda tidak perlu membutuhkan model angin yang sangat terperinci, tetapi Anda harus ingat bahwa kapal Anda didorong oleh angin di layar mereka (dan air menempel ke kemudi dan kemudi). Secara khusus, kapal tidak dapat berlayar melawan angin secara langsung; mereka harus mengalahkan jalan mereka di sana sebagai gantinya.
Ilmari Karonen
Biasanya "titik goto" dapat dipecah menjadi fase rotasi dan fase gerakan maju. Ambil pendekatan yang sama tetapi lakukan gerakan maju ke rotasi. Contoh masing-masing x rad rotasi, maju perahu y meter
dnk drone.vs.drones

Jawaban:

7

Lihat halaman ini

Menambahkan Putaran Realistis

Langkah selanjutnya adalah menambahkan belokan realistis untuk unit kami, sehingga mereka tampaknya tidak mengubah arah secara tiba-tiba setiap kali mereka perlu berbelok. Solusi sederhana melibatkan penggunaan spline untuk menghaluskan sudut-sudut yang tiba-tiba menjadi belokan. Sementara ini memecahkan beberapa masalah estetika, masih menghasilkan gerakan fisik yang sangat tidak realistis untuk sebagian besar unit. Misalnya, itu mungkin mengubah tikungan mendadak dari tangki menjadi kurva yang ketat, tetapi belokan yang melengkung masih akan jauh lebih ketat daripada yang bisa dilakukan oleh tangki.

Untuk solusi yang lebih baik, hal pertama yang perlu kita ketahui adalah radius belokan untuk unit kita. Radius putar adalah konsep yang cukup sederhana: jika Anda berada di tempat parkir besar di mobil Anda, dan putar roda ke kiri sejauh mungkin dan lanjutkan mengemudi dalam lingkaran, jari-jari lingkaran itu adalah giliran Anda radius. Jari-jari belok Volkswagen Beetle akan jauh lebih kecil dari pada SUV besar, dan jari-jari belok seseorang akan jauh lebih kecil dari pada beruang besar yang bergerak-gerak.

Katakanlah Anda berada pada suatu titik (asal) dan menunjuk ke arah tertentu, dan Anda perlu menuju ke titik lain (tujuan), seperti yang diilustrasikan dalam Gambar 5. Jalur terpendek ditemukan baik dengan berbelok ke kiri sejauh Anda bisa, berputar-putar sampai Anda langsung menunjuk ke tujuan, dan kemudian melanjutkan ke depan, atau dengan berbelok ke kanan dan melakukan hal yang sama. Gambar 5: Menentukan jalur terpendek dari titik asal ke tujuan.

Pada Gambar 5, rute terpendek jelas merupakan garis hijau di bagian bawah. Jalur ini ternyata cukup mudah untuk dihitung karena beberapa hubungan geometris, diilustrasikan dalam Gambar 6.

Gambar 6: Menghitung panjang jalan.

Pertama-tama kita menghitung lokasi titik P, yang merupakan pusat lingkaran putar kita, dan selalu radius r dari titik awal. Jika kita berbelok ke kanan dari arah awal kita, itu berarti P berada pada sudut (initial_direction - 90) dari titik asal, jadi:

angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)

Sekarang kita tahu lokasi titik pusat P, kita dapat menghitung jarak dari P ke tujuan, ditampilkan sebagai h pada diagram:

dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)

Pada titik ini kami juga ingin memeriksa bahwa tujuan tidak ada di dalam lingkaran, karena jika itu, kami tidak akan pernah bisa mencapainya:

if (h < r)
    return false

Sekarang kita dapat menghitung panjang segmen d, karena kita sudah tahu panjang dua sisi lainnya dari segitiga siku-siku, yaitu h dan r. Kami juga dapat menentukan sudut dari hubungan segitiga-kanan:

d = sqrt(h*h - r*r)
theta = arccos(r / h)

Akhirnya, untuk mengetahui titik Q di mana untuk meninggalkan lingkaran dan mulai pada garis lurus, kita perlu mengetahui sudut total +, dan mudah ditentukan sebagai sudut dari P ke tujuan:

phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)

Perhitungan di atas mewakili jalur belok kanan. Path sebelah kiri dapat dihitung dengan cara yang persis sama, kecuali bahwa kita menambahkan 90 ke initial_direction untuk menghitung angleToP, dan kemudian kita gunakan - alih-alih +. Setelah menghitung keduanya, kita cukup melihat jalur mana yang lebih pendek dan menggunakannya.

Dalam penerapan algoritma ini dan yang mengikuti, kami menggunakan struktur data yang menyimpan hingga empat "segmen garis" yang berbeda, masing-masing lurus atau melengkung. Untuk jalur lengkung yang dijelaskan di sini, hanya ada dua segmen yang digunakan: busur yang diikuti oleh garis lurus. Struktur data berisi anggota yang menentukan apakah segmen itu busur atau garis lurus, panjang segmen, dan posisi awal. Jika segmen adalah garis lurus, struktur data juga menentukan sudutnya; untuk busur, ini menentukan pusat lingkaran, sudut awal pada lingkaran, dan total radian yang tercakup oleh busur.

Setelah kami menghitung jalur lengkung yang diperlukan untuk mencapai antara dua titik, kami dapat dengan mudah menghitung posisi dan arah kami pada waktu tertentu, seperti yang ditunjukkan pada Listing 2.

DAFTAR 2. Menghitung posisi dan orientasi pada waktu tertentu.

distance = unit_speed * elapsed_time
loop i = 0 to 3:
    if (distance < LineSegment[i].length)
        // Unit is somewhere on this line segment
        if LineSegment[i] is an arc
            //determine current angle on arc (theta) by adding or
            //subtracting (distance / r) to the starting angle
            //depending on whether turning to the left or right
            position.x = LineSegment[i].center.x + r*cos(theta)
            position.y = LineSegment[i].center.y + r*sin(theta)
        //determine current direction (direction) by adding or
        //subtracting 90 to theta, depending on left/right
        else
            position.x = LineSegment[i].start.x 
              + distance * cos(LineSegment[i].line_angle)
            position.y = LineSegment[i].start.y
              + distance * sin(LineSegment[i].line_angle)
        direction = theta
        break out of loop
    else
        distance = distance - LineSegment[i].length
Draco tidak lagi percaya pada SE
sumber
4
Jawaban ini tidak benar-benar melihat ke dalam fisika kapal. Saya juga merasa bermasalah bahwa ini pada dasarnya adalah tautan ke dan kutipan panjang dari situs web lain (saya tidak yakin tentang legalitasnya).
Tidak ada yang
Terakhir kali saya memberikan sumber daya yang ada yang merupakan solusi untuk pertanyaan yang diajukan, saya diminta untuk memasukkan konten tautan jika situs target tidak lagi ada. Sekarang saya diminta untuk tidak memasukkan konten. Putuskan pikiran Anda.
Draco18s tidak lagi mempercayai SE
3
@ Draco18s: Apa yang harus Anda lakukan adalah merangkum poin-poin penting dari materi terkait dengan kata-kata Anda sendiri. (Atau, lebih baik lagi, jawab pertanyaan berdasarkan pengalaman Anda sendiri, dan hanya gunakan tautan sebagai bahan pendukung atau untuk bacaan lebih lanjut.) Kutipan pendek umumnya OK, terutama dalam situasi di mana mereka tidak dapat benar-benar dihindari (misalnya mengutip seseorang dengan tepat kata-kata untuk menunjukkan bahwa mereka benar-benar mengatakan sesuatu), tetapi mengutip sebagian besar artikel benar-benar melampaui penggunaan yang adil .
Ilmari Karonen
Jika intinya ada di dalam lingkaran, Anda bisa keluar sedikit dan kembali.
user253751
(. Ps Lihat juga ini dua pertanyaan pada meta.SE.)
Ilmari Karonen
7

Sebagai solusi sederhana, seperti yang sudah saya katakan di komentar, Anda dapat mencoba pendekatan ini:

pertimbangkan fase di mana Anda mengarahkan kapal ke arah target, dalam fase itu Anda menerapkan rotasi ke sip tetapi juga gerakan ke depan. Ketika kapal sudah menghadap target Anda dapat menerapkan kecepatan maju penuh. Saya mengatur tes di love2d, berikut ikuti metode pembaruan kapal.

turnAngSpeed = 0.4 --direction changing speed
ForwordSpeed = 40 -- full forward speed
turnForwordSpeed = ForwordSpeed *0.6 -- forward speed while turning
function ent:update(dt)
            dir = getVec2(self.tx-self.x,self.ty-self.y) -- ship --> target direction (vec2)
            dir = dir.normalize(dir) --normalized                               
            a= dir:angle() - self.forward:angle() --angle between target direction e current forward ship vector
            if (a<0) then
             a=a+math.pi *2 -- some workaround to have all positive values
            end

            if a > 0.05 then -- if angle difference 
                if a < math.pi then
                    --turn right
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),turnAngSpeed * dt)
                else
                    --turn left
                    self.forward = vec2.rotate(self.forward,getVec2(0,0),-turnAngSpeed * dt)
                end             
                --apply turnForwordSpeed
                self.x = self.x+ self.forward.x * turnForwordSpeed * dt
                self.y = self.y+ self.forward.y * turnForwordSpeed * dt
            else 
                --applly ForwordSpeed
                self.x = self.x+ self.forward.x * ForwordSpeed * dt
                self.y = self.y+ self.forward.y * ForwordSpeed * dt
            end
end

masukkan deskripsi gambar di sini

Contoh animasi menunjukkan (putaran terakhir) kasus di mana kapal tidak dapat mencapai target, karena kombinasi kecepatan putar dan maju mendefinisikan radius putar terlalu besar, dalam hal ini dapat berguna mengurangi " turnForwordSpeed" atau lebih baik membuatnya tergantung pada jarak sudut ( a) dan jarak target.

dnk drone.vs.drones
sumber
Ini adalah jawaban yang bagus, tetapi mungkin atau mungkin tidak cukup realistis untuk OP. Tidak seperti, katakanlah, mobil, kapal tidak benar-benar memiliki "radius putar": sebagian besar kapal bertenaga (mesin / manusia) pada dasarnya dapat menyalakan uang receh, sementara kapal layar bergantung pada angin, dan sebenarnya dapat memiliki belokan efektif negatif jari-jari saat memasang, dalam arti bahwa belok kiri ke angin dapat menyebabkan kapal melayang ke kanan. Apa yang dimiliki kapal adalah inersia (dan seret): mereka tidak dapat berbelok atau bergerak secara instan, dan begitu bergerak atau berbelok, luangkan waktu dan kekuatan untuk berhenti. Meski begitu, miliki +1.
Ilmari Karonen
Terimakasih banyak atas jawaban Anda!!! :) Anda adalah pahlawan saya!
DavidT
@ DavidT Kemudian pertimbangkan untuk menandai jawabannya sebagai jawaban yang diterima, jika itu dapat menyelesaikan masalah Anda dengan memuaskan. :)
Mand
-2

Sistem mesh Unity Nav, kemungkinan akan melakukan apa yang Anda inginkan dengan sedikit bermain-main dengan nilai nav agent.

Nav Meshes cukup mudah digunakan. Dan hanya dapat digunakan dalam pengaturan top down (atau setidaknya hanya tersedia untuk gerakan x / z)

Halaman manual Unity tentang pengaturan nav mesh

Pada dasarnya Anda dapat menggunakan mesh bentuk apa saja untuk memanggang area navigasi, dan menambahkan agen nav ke objek Anda dan meminta mereka menemukan jalurnya di sekitar navigasi mesh

ProtoJazz
sumber
Saya menemukan jawaban Draco juga kurang dalam hal itu. Namun, jawaban Anda bukanlah jawaban nyata dan lebih banyak komentar.
Tidak ada yang
2
Ini adalah saran yang bagus tetapi, untuk menjadi jawaban yang baik, diperlukan dukungan dan informasi tentang implementasi. Harap tambahkan beberapa informasi tentang mengkonfigurasi nav mesh untuk menjadikan ini jawaban yang baik. Saya pikir itulah yang coba dikatakan oleh para komentator di atas :)
sirdank