Bagaimana cara membuat sesuatu terjadi setiap N detik dalam game?

8

Saya ingin sesuatu terjadi setiap N detik, bagaimana saya melakukannya? Mungkin menggunakan timer tapi bagaimana caranya?

pengguna2957632
sumber
Saya membuat pertanyaan Anda lebih umum karena saya pikir ini lebih bermanfaat untuk lebih banyak orang dengan cara ini.
MichaelHouse
Berdasarkan komentar pada salah satu jawaban, saya tidak percaya poster mencari bit timer, tetapi bagaimana mengubah frame sprite. Itu lebih tergantung pada platform apa yang kita bicarakan. Apapun, sekarang pertanyaannya telah diedit, itu tidak mewakili apa yang sebenarnya dia tanyakan. Java 2D penting untuk pertanyaan yang ingin ia tanyakan.
prototipe
Mengubah sprite dan mewujudkannya setiap 5 detik tidak berhubungan dan harus ditanyakan sebagai pertanyaan yang berbeda. Silakan ajukan pertanyaan baru tentang mengubah sprite. Pastikan untuk memasukkan apa yang telah Anda coba dan bagaimana dengan itu tidak berfungsi.
MichaelHouse

Jawaban:

14

Pendekatan umum untuk ini adalah dengan menggunakan loop pembaruan dan waktu delta.

float timerCurrent = 0f;
float timerTotal = 5f;


Update() {
    timerCurrent += deltaTime;
    if(timerCurrent >= timerTotal) {
        //do timer action
        timerCurrent -= timerTotal;
    }
}

Ini mengandaikan bahwa Anda memiliki akses ke deltaTimevariabel. Waktu Delta hanyalah waktu yang telah berlalu sejak frame terakhir. Banyak mesin akan menyediakan ini untuk Anda, atau Anda dapat mempelajari lebih lanjut tentang pengaturan sendiri di sini .

MichaelHouse
sumber
Apakah ini dalam arti teknis lebih baik daripada memulai penghitung waktu eksplisit seperti dalam jawaban @ Josh?
Jack M
@ JackM Itu akan tergantung pada implementasi timer. Alasan saya menjawab seperti ini adalah karena agnostik bahasa dan sangat sederhana untuk diterapkan.
MichaelHouse
1
@ JackM: Ini juga lebih baik jika Anda pernah menjalankan di bawah debugger. Waktu permainan yang terakumulasi dapat berhenti ketika Anda mencapai breakpoint alih-alih setiap timer kedaluwarsa dan langsung menyala terus.
Ben Jackson
Kita harus hati-hati, karena permainan bisa membeku misalnya dan kutu bisa hilang. Oleh karena itu kita harus memanggil aksi timer untuk setiap tick dengan delta yang ditentukan yang telah berlalu dan tidak hanya sekali dll.
Christian Ivicevic
Metode ini tidak mengandalkan menghitung kutu, itu bergantung pada waktu delta. Jika ada kerangka ekstra panjang, waktu delta juga ekstra panjang. Namun, dalam banyak kasus itu lebih baik untuk membatasi waktu delta, bingkai ekstra panjang dapat menyebabkan masalah dengan fisika dan semacamnya. Metode ini lebih unggul daripada hanya menggunakan waktu saat ini dikurangi waktu mulai karena akan lebih baik disinkronkan dengan perhitungan lain dalam permainan saat membatasi rentang waktu delta.
MichaelHouse
3

Di sebagian besar bahasa, Anda harus memulai jam dengan semacam pemanggilan fungsi di sepanjang baris clock.startTimer()sebelum Anda memasuki loop utama. Kemudian, Anda harus menyimpan nilai waktu jam sebelum Anda memasukkan loop utama ke dalam variabel dengan fungsi seperti time = clock.getTime(). Simpan waktu langkah Anda ke dalam variabel n.

Di loop utama Anda, centang yang ingin Anda buat adalah sesuatu di sepanjang baris

if(time + n <= clock.getTime())
     //do stuff
     time = clock.getTime() //important to assign new time value here

Catatan: Saya tidak yakin bahasa / perpustakaan apa yang Anda lihat jadi ini hanya algoritma generik yang saya pikirkan. Ini mungkin tidak sesuai dengan kebutuhan Anda. Beberapa bahasa / pustaka mengharuskan Anda membuat objek jam, sementara yang lain Anda bisa langsung membuat panggilan fungsi.

Sesuai komentar di bawah ini, Anda harus berhati-hati dengan masalah threading tergantung pada bahasa yang Anda gunakan. Anda juga harus menggunakan pelampung ganda untuk menyimpan time.

Josh
sumber
1
Jawaban yang bagus. Ini bisa memiliki masalah threading dalam beberapa bahasa (mis. .NET) di mana timer diterapkan di utas terpisah dari loop game Anda.
ashes999
1
Juga penting untuk dicatat di sini bahwa jika timeakan menyimpan waktu permainan yang telah berlalu, itu harus menggunakan format floating point presisi ganda.
kevintodisco
Ini adalah poin yang bagus, saya akan menambahkannya ke jawabannya.
Josh
2

Seperti yang sudah ditunjukkan oleh jawaban lain, menerapkan timer dapat dilakukan dengan menambah nilai yang disimpan oleh masing-masing frame deltaTime, dan membandingkannya dengan durasi yang diharapkan. Untuk kelengkapan, saya akan memasukkan kode yang sangat mirip dengan jawaban lain:

float elapsed = 0.0f;
float duration = 4.0f;

void update(float deltaTime) {
    elapsed += deltaTime;
    if (elapsed <= duration) {
        // Run code.
        elapsed = 0.0f;
        // Maybe remove from update loop?
    }
}

Bagaimana Anda ingin menangani // Run code.porsinya terserah Anda. Mungkin Anda memiliki Timerkelas, sebuah instance yang mengambil delegate(C #) atau callback(C ++) dan menyebutnya ketika penghitung waktu berakhir. Juga, menjeda penghitung waktu adalah masalah menghapusnya dari loop pembaruan.

Pendekatan alternatif adalah dengan menandai waktu mulai dari penghitung waktu, dan sebagai gantinya melakukan perhitungan berdasarkan permintaan waktu yang telah berlalu:

double startTime = 0.0; // This is a double for a reason, I'll explain below.
bool running = false;

void start() {
    startTime = getTime(); // This is whatever system time call you want to use.
    running = true;
}

double getElapsed() {
    double elapsed = getTime() - startTime;
    return elapsed;
}

Gaya ini memberi sedikit lebih banyak kontrol kepada pengguna timer. Struktur itu sendiri tidak peduli dengan apa yang harus dilakukan ketika waktu yang telah berlalu mencapai titik tertentu; bahkan tidak memperbarui. Pengguna dapat meminta waktu yang telah berlalu saat dibutuhkan. Pola ini memiliki efek samping yang disayangkan karena tidak ramah terhadap debugger. Waktu sistem berlanjut ketika program Anda dihentikan pada debugger, jadi timer seperti ini akan berperilaku berbeda ketika melangkah melalui program. Solusi potensial untuk itu adalah mempertahankan nilai waktu berlalu khusus-program yang diperbarui setiap frame menggunakan delta waktu sistem.

Saya pikir yang paling penting adalah dua kebiasaan mengatur waktu pada komputer, terutama dalam hal pengembangan game. Yang pertama adalah presisi floating point dan yang kedua adalah resolusi timer asli.

Anda akan perhatikan bahwa pada contoh kedua, saya menggunakan a double jenis alih-alih float, seperti pada contoh pertama (jenis nama tentu saja tergantung pada bahasa yang Anda gunakan). Alasan untuk ini adalah contoh kedua adalah menyimpan total waktu permainan yang telah berlalu . Jika permainan dibiarkan berjalan untuk waktu yang sangat lama, nilai format floating point presisi tunggal akan memiliki presisi yang tidak cukup untuk secara akurat mengukur waktu yang telah berlalu , yang mengarah ke masalah stabilitas. Contoh pertama baik-baik saja menggunakan floattipe selama durasi besar tidak diharapkan.

Di ujung lain spektrum, jika waktu pembaruan yang Anda harapkan cukup kecil, Anda mungkin sebenarnya tidak dapat mencapainya pada awalnya, tergantung pada bagaimana Anda mendapatkan waktu sistem. Pengatur waktu akan sering bergantung pada resolusi pengatur waktu dari OS yang Anda jalankan. Misalnya, resolusi penghitung waktu default Windows 7 dan di bawahnya adalah 15,6 ms . Ini berarti bahwa ketepatan waktu terendah yang dapat Anda capai menggunakan fungsi sepertitimeGetTime atau GetTickCount, adalah 15,6 ms, kecuali jika Anda mengubah resolusi pengatur waktu (ada juga bahaya yang terkait dengannya).

Ya, itu agak lama, tetapi ini adalah hal-hal penting yang harus diperhatikan ketika mengimplementasikan timer.

kevintodisco
sumber
kamu berterima kasih tetapi saya sekarang bagaimana melakukan itu sedikit tetapi bagaimana saya akan mengubah sprite kembali dan froward
user2957632
@ user2957632 Bukan itu pertanyaan Anda saat ini. Tolong buat lebih jelas.
kevintodisco