Mekanisme pembalikan waktu dalam game

10

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).

Jkh2
sumber
1
Saya belum menonton semua ini (YouTube gemetar cam, 1,5 jam) , tapi mungkin ada beberapa ide dari Jonathan Blow yang mengerjakan ini dalam permainannya Braid.
MichaelHouse
Kemungkinan duplikat dari gamedev.stackexchange.com/questions/15251/…
Hackworth

Jawaban:

9

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.

Hackworth
sumber
2
Perhatikan bahwa reversibilitas tindakan dalam permainan bisa menjadi hal yang sangat sensitif, karena masalah presisi titik mengambang, tanda waktu variabel, dll; jauh lebih aman untuk menyelamatkan keadaan itu daripada membangunnya kembali di sebagian besar situasi.
Steven Stadnicki
@StevenStadnicki Mungkin, tapi itu pasti mungkin. Dari atas kepala saya, Jenderal C&C melakukannya dengan cara ini. Permainan ini memiliki replay selama berjam-jam hingga 8 pemain, dengan berat paling sedikit beberapa ratus kB, dan begitulah yang saya kira sebagian besar jika tidak semua game RTS melakukan multipemain mereka: Anda tidak dapat mentransmisikan kondisi permainan penuh dengan potensi ratusan unit setiap frame, Anda harus membiarkan mesin melakukan pembaruan. Jadi ya, itu pasti layak.
Hackworth
3
Putar ulang adalah hal yang sangat berbeda dari mundur, karena operasi yang secara konsisten dapat direproduksi ke depan (misalnya, menemukan posisi pada frame n, x_n, dengan memulai dengan x_0 = 0 dan menambahkan deltas v_n untuk setiap langkah) tidak harus direproduksi mundur ; (x + v_n) -v_n tidak secara konsisten sama dengan x dalam matematika floating-point. Dan mudah untuk mengatakan 'atasi', tetapi Anda sedang berbicara tentang kemungkinan perombakan total, termasuk tidak dapat menggunakan banyak perpustakaan eksternal.
Steven Stadnicki
1
Untuk beberapa game pendekatan Anda mungkin layak, tapi AFAIK kebanyakan game yang menggunakan waktu-pembalikan sebagai mekanik menggunakan sesuatu yang lebih dekat ke pendekatan Memento OriginalDaemon di mana negara yang relevan adalah disimpan untuk setiap frame.
Steven Stadnicki
2
Bagaimana dengan memutar ulang dengan menghitung ulang langkah-langkahnya, tetapi menyimpan bingkai kunci setiap beberapa detik? Kesalahan floating point tidak akan membuat perbedaan yang signifikan hanya dalam beberapa detik (tentu saja tergantung pada kerumitannya). Ini juga terbukti bekerja dalam kompresi video: P
Tharwen
1

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).

OriginalDaemon
sumber
0

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.

Darkwings
sumber
0

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)

(1.1 + 3 - 3) == 1.1

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.

Hannesh
sumber