Bingkai Gerakan Independen


11

Saya telah membaca dua utas lainnya di sini tentang gerakan: Gerakan berbasis waktu Vs Gerakan berbasis frame rate? , dan Kapan saya harus menggunakan langkah waktu tetap atau variabel?

tapi saya pikir saya kurang memiliki pemahaman dasar tentang gerakan frame independent karena saya tidak mengerti apa yang dibicarakan oleh salah satu dari kedua thread tersebut.

Saya mengikuti bersama dengan tutorial SDL lazyfoo dan sampai pada pelajaran frame independen. http://lazyfoo.net/SDL_tutorials/lesson32/index.php

Saya tidak yakin apa yang ingin dikatakan oleh bagian gerakan dari kode ini, tetapi saya pikir ini adalah ini (tolong perbaiki saya jika saya salah): Untuk memiliki frame independent, kita perlu mengetahui seberapa jauh suatu objek ( mis. sprite) bergerak dalam jangka waktu tertentu, misalnya 1 detik. Jika titik bergerak pada 200 piksel per detik, maka saya perlu menghitung berapa banyak bergerak dalam detik itu dengan mengalikan 200 pps dengan 1/1000 detik.

Apakah itu benar? Pelajaran mengatakan:

"kecepatan dalam piksel per detik * waktu sejak frame terakhir dalam detik. Jadi jika program ini berjalan pada 200 frame per detik: 200 pps * 1/200 detik = 1 piksel"

Tapi ... saya pikir kita mengalikan 200 pps dengan 1/1000 detik. Apa bisnis ini dengan frame per detik?

Saya akan menghargai jika seseorang bisa memberi saya sedikit penjelasan lebih rinci tentang bagaimana bingkai gerakan independen bekerja.

Terima kasih.

TAMBAHAN:

SDL_Rect posRect;
posRect.x = 0;
posRect.y = 0;

float y, yVel;
y = 0;
yVel = 0;

Uint32 startTicks = SDL_GetTicks();

bool quit = false;
SDL_Event gEvent;

while ( quit == false )
{
    while ( SDL_PollEvent( &gEvent ) )
    {
        if ( gEvent.type == SDL_QUIT )
            quit = true;
    }

    if ( y <= 580 )
    {
        yVel += DOT_VEL;
        y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
        posRect.y = (int)y;
    }

    startTicks = SDL_GetTicks();
    SDL_BlitSurface( bg, NULL, screen, NULL );
    SDL_BlitSurface( dot, NULL, screen, &posRect );
    SDL_Flip( screen );
}

Kode itu yang memindahkan satu titik ke bawah layar. Saya pikir saya sudah melakukan semuanya dengan benar sejauh ini. Itu bergerak ke bawah layar tetapi ada sedikit hal aneh yang terjadi yang tidak bisa saya jelaskan. Titik seharusnya tetap pada y = 580 ketika sampai lebih dari nilai-y. Namun, setiap kali saya menjalankan program, titik tersebut akan berakhir di lokasi yang berbeda, yang berarti sedikit lebih banyak dari 580, sehingga titik tersebut setengah atau lebih dari setengah layar (titik adalah 20 piksel, layar dimensi 800x600). Jika saya melakukan sesuatu seperti klik dan tahan bilah judul program, dan kemudian lepaskan, titik menghilang dari layar. Kenapa variabel setiap kali? Adapun masalah bilah judul saya pikir itu karena ketika saya memegang bilah judul, penghitung waktu masih berjalan, dan waktu yang berlalu semakin besar, menghasilkan jarak yang lebih besar titik bergerak di bingkai berikutnya. Apakah itu benar?


Penambahan Anda sebenarnya adalah pertanyaan lain. Anda harus menjadikannya pertanyaan kedua alih-alih menambahkannya ke pertanyaan yang ada. Itu dapat dijawab dengan mudah: Hitung saja gerakan-y, misalnya. yMovement = (yVel * (SDL_GetTicks() - startTicks)/1000.f);lalu lakukan:if(y + yMovement <= 580){ y += yMovement; } else { y = 580; }
bummzack

Jawaban:


10

CATATAN: Semua fraksi dimaksudkan untuk mengapung.

Bingkai gerakan independen bekerja dengan mendasarkan gerakan dari waktu. Anda mendapatkan jumlah waktu yang dihabiskan sejak frame terakhir (jadi jika ada 60 frame dalam satu detik, setiap frame membutuhkan 1,0 / 60,0 detik, jika semua frame mengambil jumlah waktu yang sama) dan cari tahu berapa banyak pergerakan yang dilakukan. diterjemahkan menjadi.

Jika Anda ingin entitas Anda memindahkan jumlah ruang tertentu untuk unit waktu tertentu (kami akan mengatakan 100 piksel untuk setiap detiknya) maka Anda dapat mengetahui berapa piksel yang harus Anda pindahkan per frame dengan mengalikan jumlah gerakan per detik (100 piksel) dengan jumlah waktu yang dilewati dalam detik (1.0 / 60.0) untuk mengetahui berapa banyak gerakan yang harus terjadi dalam bingkai saat ini.

Ini bekerja dengan mencari tahu berapa banyak gerakan yang harus Anda lakukan per frame dengan menggunakan jumlah waktu yang berlalu dan kecepatan yang ditentukan dengan beberapa unit waktu (detik atau milidetik lebih disukai). Jadi perhitungan Anda mungkin terlihat seperti:movementPerSecond * (timeElapsedInMilliseconds / 1000.0)

Saya harap itu masuk akal bagi Anda.

Saya ingin menggerakkan pria saya 200 piksel ke kanan setiap detik. Jika frame saat ini dijalankan 50 milidetik setelah frame sebelumnya, maka saya harus menggerakkan pria saya sepersekian dari kecepatan yang ditentukan sebelumnya (yang 200 piksel). Saya harus memindahkannya 50/1000 dari jarak karena hanya 1/20 (50/1000 = 1/20) waktu telah berlalu. Oleh karena itu masuk akal untuk hanya memindahkannya 10 piksel (jika 19 frame lebih terjadi, 50 milidetik terpisah satu sama lain, maka jumlah total gerakan dalam detik itu adalah 200 piksel, jumlah yang kita inginkan).

Cara kerja frame independen bekerja adalah frame biasanya muncul pada langkah waktu variabel (ada jumlah waktu berbeda yang terjadi antara frame berikutnya). Jika kita terus-menerus memindahkan suatu entitas dengan jarak konstan setiap frame, maka pergerakannya didasarkan pada frame rate. Jika ada banyak waktu di antara frame, game akan tampak bergerak terlalu lambat dan jika tidak ada banyak waktu di antara frame, game akan tampaknya akan cepat. (terlalu sedikit waktu antar frame = banyak frame = lebih banyak pergerakan) Untuk mengatasinya, kami menggunakan kecepatan dalam hal waktu dan melacak waktu antara frame. Dengan begitu kita tahu sudah berapa lama sejak kita terakhir memperbarui posisi dan seberapa jauh kita harus memindahkan entitas.

Frame per detik: Ini adalah jumlah frame yang terjadi per detik. Biasanya frame rate adalah berapa kali gim ditarik / diberikan sedetik atau berapa kali perputaran gim diselesaikan satu detik.

Fixed Varie Variable Time Step: Ini mengacu pada jumlah waktu antar frame. Biasanya, waktu antar frame tidak akan konstan. Sistem / inti tertentu seperti fisika akan membutuhkan beberapa satuan waktu untuk mensimulasikan / menjalankan sesuatu. Biasanya, sistem fisika lebih stabil / scalable jika langkah waktu diperbaiki. Perbedaan antara langkah waktu tetap / variabel ada dalam nama. Langkah waktu tetap adalah seperti apa itu: langkah waktu yang terjadi pada tingkat waktu yang tetap. Langkah waktu variabel adalah langkah waktu yang terjadi pada tingkat waktu yang berbeda / berbeda.


Dalam contoh yang Anda berikan, 50 milidetik adalah waktu untuk setiap frame, benar? Dan itu dihitung dengan 1000 / FPS? Jadi gerakan yang Anda butuhkan untuk membuat setiap frame adalah piksel per detik * 50/1000?
ShrimpCrackers

hm, saya menyadari bahwa milidetik untuk setiap kerangka waktu mungkin akan bervariasi, bukan? Sesuatu seperti getTicks () - startTicks akan selalu berbeda dan tidak konstan.
ShrimpCrackers

@Omnion: Jika Anda menentukan jarak dalam "piksel per detik" Anda tidak dapat menggunakan milidetik ... itu harus 1,0 / 60,0 bukan 1000/60 yang akan menghasilkan sesuatu yang sama sekali berbeda.
bummzack

@ ShrimpCrackers ya, waktu yang telah berlalu berubah. Bayangkan PC yang lebih tua yang tidak mampu menghasilkan 60 fps. Anda masih ingin gim berjalan pada kecepatan yang sama (tetapi bukan fps yang sama) pada mesin seperti itu.
bummzack

jadi, lalu di tutorial lazyfoo, apa arti 1000 dalam deltaticks / 1000.f? FPS? 1000 milidetik? Saya agak bingung sekarang. Tampaknya FPS diperlukan dalam menentukan waktu yang diperlukan untuk setiap frame, tetapi itu sebenarnya tidak menghitung ke dalam gerakan.
ShrimpCrackers

7

Dalam dinamika bingkai kode Anda untuk (misalnya) memindahkan suatu entitas akan terlihat seperti ini:

x = x + speedPerFrame

Jika Anda ingin menjadi frame-independent, bisa terlihat seperti ini:

x = x + speedPerSecond * secondsElapsedSinceLastFrame

terima kasih, itu masuk akal. Saya punya pertanyaan lain di atas.
ShrimpCrackers

1

Mengenai pertanyaan tambahan.

Titik Anda berhenti di lokasi yang berbeda setiap kali karena Anda tidak memeriksa batas (y> 580) ketika Anda memindahkannya. Anda hanya berhenti memperbarui lebih jauh setelah 580 masa lalu.

Pada frame terakhir sebelum Anda menyeberang 580 Anda bisa mulai dari 579 atau Anda bisa di 570 atau Anda bisa di 100. Anda juga bisa melangkah 1 pixel maju atau 1000, tergantung pada berapa lama frame terakhir waktu untuk mengeksekusi.

Ubah saja kondisi IF Anda menjadi seperti ini dan Anda akan baik-baik saja.

if ( y <= 580 )
{
    yVel += DOT_VEL;
    y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
    if( y > 580 )
    {
        y = 580;
    }
    posRect.y = (int)y;
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.