Saya bertanya-tanya tentang bagaimana mekanisme manipulasi waktu dalam game biasanya dirancang. Saya sangat tertarik pada pembalikan waktu (semacam seperti di BES atau Prince of Persia terbaru).
Gim ini adalah penembak top down 2D.
Mekanisme yang saya coba desain / implementasikan memiliki persyaratan sebagai berikut:
1) Tindakan entitas selain karakter pemain sepenuhnya deterministik.
- Tindakan yang dilakukan suatu entitas didasarkan pada frame yang dikembangkan sejak level awal dan / atau posisi pemain di layar
- Entitas dilahirkan pada waktu yang ditentukan selama level.
2) Pembalikan waktu berfungsi dengan membalikkan kembali secara realtime.
- Tindakan pemain juga terbalik, ia memutar balik apa yang dilakukan pemain. Pemain tidak memiliki kontrol selama waktu mundur.
- Tidak ada batasan pada waktu yang dihabiskan untuk membalikkan, kita dapat membalikkan semua jalan ke awal level jika diinginkan.
Sebagai contoh:
Frame 0-50: Pemain bergerak foward 20 unit selama waktu ini Musuh 1 memunculkan di frame 20 Musuh 1 bergerak ke kiri 10 unit selama bingkai 30-40 Pemain menembakkan peluru di bingkai 45 Peluru bergerak 5 foward (45-50) dan membunuh Musuh 1 di bingkai 50
Membalik ini akan diputar ulang secara realtime: Pemain bergerak mundur 20 unit selama waktu ini Musuh 1 bangkit kembali pada frame 50 Bullet muncul kembali pada frame 50 Bullet bergerak mundur 5 dan menghilang (50-45) Musuh bergerak ke kiri 10 (40-30) Musuh dihilangkan pada bingkai 20.
Hanya dengan melihat gerakan, saya punya beberapa ide tentang bagaimana mencapai ini, saya berpikir untuk memiliki antarmuka yang mengubah perilaku ketika waktu bergerak maju atau mundur. Alih-alih melakukan sesuatu seperti ini:
void update()
{
movement += new Vector(0,5);
}
Saya akan melakukan sesuatu seperti ini:
public interface movement()
{
public void move(Vector v, Entity e);
}
public class advance() implements movement
{
public void move(Vector v, Entity e)
{
e.location += v;
}
}
public class reverse() implements movement
{
public void move(Vector v, Entity e)
{
e.location -= v;
}
}
public void update()
{
moveLogic.move(new vector(5,0));
}
Namun saya menyadari ini bukan kinerja yang optimal dan akan cepat menjadi rumit untuk tindakan lebih lanjut (seperti gerakan halus di sepanjang jalur lengkung dll).
Jawaban:
Anda mungkin ingin melihat pola Command .
Pada dasarnya setiap tindakan reversibel yang dilakukan entitas Anda diimplementasikan sebagai objek perintah. Semua objek tersebut menerapkan setidaknya 2 metode: Jalankan () dan Batalkan (), ditambah apa pun yang Anda butuhkan, seperti properti cap waktu untuk waktu yang tepat.
Setiap kali entitas Anda melakukan tindakan yang dapat dibalik, Anda membuat objek perintah yang sesuai terlebih dahulu. Anda menyimpannya di tumpukan Undo, kemudian memberi makan ke mesin permainan Anda dan jalankan. Saat Anda ingin membalikkan waktu, Anda memunculkan tindakan dari atas tumpukan dan memanggil metode Undo () mereka, yang melakukan kebalikan dari metode Execute (). Misalnya, dalam hal lompatan dari titik A ke titik B, Anda melakukan lompatan dari B ke A.
Setelah Anda melakukan suatu tindakan, simpan di tumpukan Redo jika Anda ingin maju dan mundur sesuka hati, seperti halnya fungsi undo / redo dalam editor teks atau program cat. Tentu saja, animasi Anda juga harus mendukung mode "mundur" untuk memainkannya mundur.
Untuk shenanigans desain game lainnya, biarkan setiap entitas menyimpan aksinya pada tumpukannya sendiri, sehingga Anda dapat membatalkan / mengulanginya secara terpisah satu sama lain.
Pola perintah memiliki kelebihan lain: Misalnya, cukup sepele untuk membuat perekam replay, karena Anda hanya perlu menyimpan semua objek di tumpukan ke file, dan pada waktu replay, cukup masukkan ke mesin game satu per satu. satu.
sumber
Anda bisa melihat Pola Memento; niat utamanya adalah untuk mengimplementasikan operasi undo / redo dengan memutar kembali keadaan objek, tetapi untuk jenis permainan tertentu itu sudah cukup.
Untuk gim dalam perulangan waktu nyata, Anda dapat mempertimbangkan setiap kerangka operasi Anda sebagai perubahan kondisi dan menyimpannya. Ini adalah pendekatan sederhana untuk diterapkan. Alternatifnya adalah menjebak ketika keadaan objek berubah. Misalnya, mendeteksi kapan gaya yang bekerja pada benda tegar diubah. Jika Anda menggunakan properti untuk mendapatkan dan menetapkan variabel, ini juga bisa menjadi implementasi yang relatif lurus ke depan, bagian yang sulit adalah mengidentifikasi kapan mengembalikan keadaan, karena ini bukan waktu yang sama untuk setiap objek (Anda bisa menyimpan waktu rollback sebagai jumlah frame dari awal sistem).
sumber
Dalam kasus khusus Anda yang menangani rollback dengan memutar kembali gerakannya akan bekerja dengan baik. Jika Anda menggunakan segala bentuk pathfinding dengan unit AI, pastikan untuk menghitung ulang setelah rollback untuk menghindari unit yang tumpang tindih.
Masalahnya adalah cara Anda menangani gerakan itu sendiri: mesin fisika yang layak (penembak top down 2D akan baik-baik saja dengan yang sangat sederhana) yang melacak info langkah terakhir (termasuk posisi, gaya total, dll) akan memberikan dasar yang kuat. Kemudian, memutuskan rollback maksimum dan rincian untuk rollback-langkah Anda harus mendapatkan hasil yang Anda inginkan.
sumber
Padahal ini adalah ide yang menarik. Saya akan menyarankan untuk tidak melakukannya.
Memutar ulang game ke depan berfungsi dengan baik, karena operasi akan selalu memiliki efek yang sama pada kondisi game. Ini tidak menyiratkan bahwa operasi terbalik memberi Anda keadaan semula. Misalnya, evaluasi ungkapan berikut dalam bahasa pemrograman apa pun (matikan optimisasi)
Setidaknya dalam C dan C ++, ia mengembalikan false. Meskipun perbedaannya kecil, bayangkan berapa banyak kesalahan yang dapat menumpuk pada 60fps dalam 10 detik detik. Akan ada kasus di mana pemain hanya melewatkan sesuatu, tetapi memukulnya saat permainan diputar ulang ke belakang.
Saya akan merekomendasikan menyimpan keyframe setiap setengah detik. Ini tidak akan menghabiskan terlalu banyak memori. Anda kemudian dapat menginterpolasi antarframe key, atau bahkan lebih baik, mensimulasikan waktu antara duaframe key, dan kemudian memutar ulang mundur.
Jika gim Anda tidak terlalu rumit, simpan saja kerangka kunci keadaan permainan 30 kali per detik dan mainkan mundur. Jika Anda memiliki 15 objek masing-masing dengan posisi 2D, dibutuhkan 1,5 menit untuk mendapatkan MB, tanpa kompresi. Komputer memiliki memori gigabytes.
Jadi jangan terlalu rumit, itu tidak akan mudah untuk memutar ulang permainan mundur, dan itu akan menyebabkan banyak kesalahan.
sumber