Bagaimana cara membuat objek bergerak berhenti dengan lancar di ujung jalan?

8

Ada selusin cara saya bisa menjawab pertanyaan ini, tetapi untuk menjaga pikiran saya sejalan, saya mengutarakannya sesuai dengan masalah saya.

Jadi saya membuat platform mengambang yang saya ingin dapat melakukan perjalanan dari satu titik yang ditunjuk ke yang lain, dan kemudian kembali ke yang pertama, dan hanya melewati antara keduanya dalam garis lurus. Namun, hanya untuk membuatnya sedikit lebih menarik, saya ingin menambahkan beberapa aturan ke platform.

  1. Saya mengkodekannya untuk melakukan perjalanan kelipatan nilai ubin seluruh data dunia. Jadi jika platform tidak stasioner, maka ia akan melakukan perjalanan setidaknya satu lebar ubin penuh atau tinggi ubin.
  2. Dalam satu panjang ubin, saya ingin mempercepat dari berhenti ke kecepatan maksimal yang diberikan.
  3. Setelah mencapai jarak satu ubin panjang, saya ingin memperlambat berhenti di koordinat ubin yang diberikan dan kemudian ulangi proses secara terbalik.

masukkan deskripsi gambar di sini

Dua bagian pertama tidak terlalu sulit, pada dasarnya saya mengalami masalah dengan bagian ketiga. Saya ingin platform berhenti tepat pada koordinat ubin, tetapi karena saya bekerja dengan akselerasi, sepertinya mudah untuk mulai menerapkan akselerasi dalam arah yang berlawanan dengan nilai yang menyimpan kecepatan platform saat ini setelah mencapai panjang satu ubin. jarak (dengan asumsi bahwa genteng bepergian lebih dari satu panjang genteng, tetapi untuk menjaga hal-hal sederhana, mari kita asumsikan itu) - tetapi kemudian pertanyaannya adalah apa nilai yang benar untuk akselerasi ke peningkatan untuk menghasilkan efek ini? Bagaimana saya menemukan nilai itu?

TheBroodian
sumber
1
Saya tidak punya waktu untuk jawaban penuh saat ini, tetapi lihat ini: red3d.com/cwr/steer/gdc99 , khususnya bagian "Kedatangan". Meniru perilaku itu untuk memperlambat berhenti dan membalikkannya untuk mempercepat dari berhenti.
MichaelHouse
Ditandai. Itu adalah banyak informasi berharga yang baru saja Anda ketahui tentang saya, Pak.
TheBroodian
Ini "diinginkan_velocity = (clipped_speed / jarak) * target_offset" semacam masuk akal, tetapi tidak persis. Setelah saya menemukan diinginkan_velocity, apakah saya mengurangi dari kecepatan objek saat ini?
TheBroodian
Saya menggunakannya untuk memperbarui nilai akselerasi: acceleration = desired_velocity - currentVelocityKemudian terapkan akselerasi itu seperti biasanya. Saya akan membuat jawaban sedikit lebih jauh menunjukkan apa yang saya lakukan.
MichaelHouse

Jawaban:

5

Menggunakan perilaku kemudi ini sebagai panduan. Melihat perilaku tiba:

masukkan deskripsi gambar di sini

Perilaku kedatangan identik dengan mencari sementara karakter jauh dari target. Tetapi alih-alih bergerak melalui target dengan kecepatan penuh, perilaku ini menyebabkan karakter melambat saat mendekati target, akhirnya melambat hingga berhenti bersamaan dengan target.

Kita dapat membuat fungsi "tiba di" seperti sesuatu yang mirip dengan ini:

arriveAtPoint(Vector2f position, Vector2f target) {
    float slowing_distance = 1;
    Vector2f target_offset = target - position;
    float distance = target_offset.length();
    float ramped_speed = currentVelocity * (distance / slowing_distance);
    float clipped_speed = Math.min(ramped_speed, currentVelocity);
    targetLinearVelocity = target_offset.scale(clipped_speed / distance);
    acceleration = targetLinearVelocity -linearVelocity;
}

Ini akan memperbarui akselerasi yang perlu kita gunakan untuk menerapkan pada objek yang bergerak.

MichaelHouse
sumber
Dan hanya untuk klarifikasi, linearVelocity akan menjadi kecepatan di mana objek kita akan bepergian setelah pembaruan sebelumnya?
TheBroodian
Ungkapan Anda sangat aneh. Tapi, linearVelocity == currentVelocity.
MichaelHouse
3
Saya tidak setuju dengan pendekatan ini karena terlalu rumit. Mungkin untuk melakukan ini dengan tween sederhana menggunakan persamaan gerak ( rumus SUVAT ). Aljabar kecil dan Anda dapat menghitung input yang dibutuhkan untuk mencapai target yang diinginkan dengan tepat.
Andrew Russell
1
Akan sangat membantu jika Anda bisa menguraikannya dengan jawaban?
TheBroodian
@AndrewRussell Saya ingin melihat jawaban itu juga.
MichaelHouse
5

Lihatlah halaman ini: http://sol.gfxile.net/interpolation/index.html

Tampaknya Anda menginginkan efek seperti smoothstep:

grafik smoothstep

Jika Anda memiliki titik paling kiri, titik paling kanan yang harus dicapai platform, dan waktu yang digunakan untuk membuat urutan penuh, sesuatu seperti ini mungkin ok:

bingkai foreach:

float smoothstep(float t, int level = 1)
{
    float ret = t;
    for(int i = 0; i < level; ++i)
    {
        ret = pow(ret, 2) * (3 - 2 * ret);
    }
    return ret;
}

currentTime += deltaTime;
if(currentTime > fullTime) currentTime -= fullTime;
float halfTime = fullTime / 2.0;
float t = abs(currentTime - halfTime) / halfTime;
t = smoothstep(t, 1);
platformPosition = rightPoint * t + leftPoint * (1 - t);

jika Anda menggunakan mesin fisika, Anda dapat membuatnya dengan impuls, seharusnya tidak terlalu sulit untuk diterjemahkan. Jika Anda menginginkan proses yang lebih mulus, Anda dapat meningkatkan level smoothstep. Multiple smoothstep

Gustavo Maciel
sumber
3

Anda dapat menggunakan XnaTweener yang menyediakan fungsi pelonggaran yang menginterpolasi nilai dari satu titik ke titik lainnya dengan cara yang mudah ...

Berikut ini adalah balasan dengan beberapa kode yang berbasis di proyek Xna Tweener dan video yang menunjukkan kinerjanya ...

https://gamedev.stackexchange.com/a/26872/8390

[EDIT]

Anda harus memiliki urutan tombol yang menentukan pergerakan platform, seperti ini:

public class MovementKey
{
    public float Time = 0;
    public float Duration;
    public Vector2 Traslation;            // Traslation is relative to previous key
    public TweeningFunction Function;

    internal float GetRatio( float Elapsed )   
    {
        // Always return a value in [0..1] range
        //    0 .. Start position relative to accumulated traslations of previous keys
        //    1 .. Target relative position reached.. then should go to next key if avalaible
        return Function( Elapsed, 0, 1, Duration ); 
    }
}

Dan kemudian Anda bisa menangani gerakan dengan cara ini:

public class Movement {

    List<MovementKey> Keys;

    public void Update( float Seconds)
    {

        float ratio;
        if (Playing) Elapsed += Seconds;

        while ( index!= Keys.Count - 1 && Elapsed > Keys[iKey + 1].Time )
        {
            Traslation += Keys[iKey].Traslation;  // Relative
            index++;
        }

       if ( index == Keys.Count - 1 && Elapsed > Keys[iKey].Time + Keys[iKey].Duration )
       {
          ratio = 1;
          if ( DoLoop )
          {
              Elapsed -= (Keys[index].Time + Keys[iKey].Duration);
              Index = 0;
              Traslation = Vector2.zero;
          }
       }
       else {                    
           ratio = Keys[index].GetRatio( Elapsed - Keys[index].Time );
       }

       Position = DefaultPosition + Traslation + ratio * Keys[index].Traslation;        
   }

"DefaultPosition" adalah posisi awal, "Traslation" mengakumulasi pergerakan beberapa kunci, dan setiap traslation kunci relatif terhadap kunci sebelumnya, jadi ketika Anda melipatgandakannya dengan faktor rasio [0..1] ia mengembalikan traslasi relatif yang diinterpolasi berjalan untuk mencapai kunci itu dari kunci sebelumnya ...

Di sini Anda memiliki video lain yang menunjukkan gerakan platform didefinisikan seperti dijelaskan di sini ...

http://www.youtube.com/watch?v=ZPHjpB-ErnM&feature=player_detailpage#t=104s

Saya telah mengulangi kode ini mencoba membuatnya mudah dimengerti ... mungkin ia memiliki beberapa bug ... kode asli menangani beberapa contoh dari gerakan yang sama tetapi dengan beberapa penundaan di antara setiap contoh ... Saya yakin kode ini dapat didesain ulang agar lebih mudah ...

Blau
sumber
Terima kasih, ini sangat membantu, walaupun sedang digunakan dalam konteks animasi, saya mencoba menerjemahkannya di kepala saya ke apa yang akan lebih kontekstual dengan situasi saya saat ini.
TheBroodian
Saya tersesat. Saya tidak tahu bagaimana menghubungkan ini dengan situasi saya saat ini sama sekali. oo ;;
TheBroodian
Anda memiliki animasi ... Anda mencoba menghidupkan dalam istilah posisi ...
Blau
Maafkan saya, alasan mengapa saya mengalami kesulitan, adalah karena saya mencoba untuk mem-bootstrap ide ini dan menerjemahkannya ke dalam sistem yang bekerja pada sistem kecepatan = kecepatan * waktu, sedangkan sistem ini hanya menyenggol lokasi objek secara prosedural. (tidak ada yang salah dengan itu, hanya sulit untuk menemukan cara yang tepat untuk menghubungkan keduanya).
TheBroodian