Kelola sejumlah besar aktor independen secara real-time

8

Saya sedang mengerjakan game strategi real-time skala besar - idealnya dengan ribuan unit aktif sekaligus - tetapi saya mengalami kesulitan mengelola semua unit sekaligus tanpa menjadi lambat secara mengejutkan. Masalahnya adalah bahwa perlu beberapa saat untuk memperbarui posisi dan status segala sesuatu setiap langkah waktu. Apakah Anda tahu ada pola desain / metodologi / kiat untuk mengurangi ini?

Slubb
sumber
1
Meskipun pertanyaan Anda mungkin tampak jauh berbeda, Anda dapat menggunakan algoritma yang sama seperti yang dijelaskan di sini . tidak perlu menggunakan pemrosesan parralel dalam algoritma itu, hanya dengan satu saja Anda akan mendapatkan peningkatan kinerja tinggi.
Ali1S232
Menyejajarkan pembaruan tidak akan membantu jika, katakanlah, Anda memiliki dua core dan memperbarui setengahnya sudah terlalu lama, tetapi jika Anda memiliki beberapa core yang tersedia dan belum menggunakannya, itu akan membantu. Idealnya Anda menginginkan solusi yang tidak mengharuskan Anda memperbarui setiap unit setiap langkah waktu, atau cara untuk menyederhanakan pembaruan sehingga Anda bisa. Seberapa besar langkah waktu ini? Ini independen dari draw frames, kan?
Blecki
4
Hal pertama yang dapat Anda lakukan adalah mengenali bahwa kecepatan Anda tidak ada hubungannya dengan jumlah aktor independen. Ini ada hubungannya dengan apa yang dilakukan aktor-aktor itu . Saya dapat memiliki seratus ribu pembaruan aktor independen> 60fps jika semua yang mereka lakukan adalah if not dead position += 1atau satu pembaruan aktor <1fps jika masuk ke loop tak terbatas. Beberapa algoritma Anda - beberapa bagian dari apa yang unit ini lakukan - terlalu mahal seperti yang Anda lakukan dan itu saja. Mungkin ada banyak kemungkinan penyebab yang berbeda, dan banyak strategi yang berbeda untuk masing-masing.
doppelgreener

Jawaban:

4

Ada dua hal berbeda yang perlu dipertimbangkan ketika mengukur dan mengoptimalkan kinerja sistem entitas berskala besar.

Pada level rendah, Anda memiliki representasi fisik dari entitas Anda yang cenderung mulai menggunakan tata letak penyimpanan yang efisien seperti SoA (struct of arrays) untuk mengurangi biaya pengulangan dan memperbarui semua entitas yang aktif.

Di level yang lebih tinggi, Anda memiliki logika pengambilan keputusan, logika game umum, AI, dan pencarian jalur. Ini semua adalah tugas yang memiliki kesamaan yang tidak harus dijalankan pada kecepatan pembaruan yang sama seperti rendering Anda.

Karena Anda akan mendapatkan waktu bingkai yang tidak rata jika Anda mengambil pendekatan naif dengan hanya melakukan tugas-tugas itu setiap N bingkai, cenderung bermanfaat untuk mengamortisasi biaya melalui beberapa bingkai.

Jika tugas bersifat incremental, Anda dapat menjalankan sebagian dari algoritma setiap frame dan menggunakan hasil parsial dalam pembaruan Anda.

Jika tugas sebagian besar monolitik tetapi dapat dipisahkan per entitas, Anda bisa melakukan tugas itu untuk subset entitas game Anda per frame, berputar di antara mereka dalam mode round-robin. Ini memiliki manfaat mengurangi kompleksitas hal-hal seperti merintis jalan dan AI, karena Anda tidak memiliki semua orang yang mencoba untuk bertindak sekaligus.

Dalam RTS taktis skala besar yang saya kerjakan, kami fokus pada memiliki struktur data yang kuat untuk menanyakan representasi tingkat rendah dalam algoritme tingkat tinggi, untuk menemukan tetangga entitas game. Proses pembaruan tingkat rendah bertindak berdasarkan niat yang disediakan oleh simulasi tingkat tinggi yang memperbarui lambat, dan pada akhirnya bermuara pada simulasi partikel murah, meningkatkan hingga ribuan.

Lars Viklund
sumber
+1. Pikiran saya persis, terutama mengurangi logika ke grup yang dikelola yang hanya diproses setiap beberapa siklus, dengan semua kelompok tersebut berpotensi terhuyung untuk diproses bahkan.
Insinyur
1

sejauh yang saya ingat Anda akan selalu memiliki kurang dari 10.000 unit permainan. tidak ada permainan yang dapat saya ingat dengan lebih dari angka itu, meskipun kerajaan bumi bisa mencapai 14.000 melalui peretasan tetapi tidak ada yang akan pernah sampai ke titik itu. jadi hanya memiliki array statis 10.000 objek tampaknya lebih dari yang dibutuhkan.

seperti yang Anda ketahui, mengulangi lebih dari 10.000 objek bukan masalah besar, tetapi mungkin menghabiskan banyak waktu jika algoritme Anda berjalan lebih lambat daripada O (n). misalnya jika Anda mencoba memeriksa setiap dua objek untuk deteksi tabrakan akan membutuhkan waktu O (n ^ 2) yang berarti banyak waktu. jadi Anda harus memecah algoritma Anda entah bagaimana. mari kita tinjau algoritma contoh untuk setiap hal yang dapat saya pikirkan saat ini:

  1. deteksi tabrakan: untuk setiap algoritma deteksi tabrakan Anda harus memeriksa setiap dua objek tetapi Anda dapat menghilangkan beberapa pengecekan memulai loop. seperti yang saya sarankan di komentar Anda dapat menggunakan algoritma yang sama yang diberikan untuk pertanyaan ini . tidak perlu menggunakan banyak utas atau apa pun, bahkan dengan satu utas dan 4 wilayah Anda akan mengurangi pemeriksaan Anda dari n * (n-1) menjadi 4 * (n / 4) ((n-1) / 4), dan dengan mengoptimalkan jumlah wilayah Anda bisa mendapatkan hasil yang lebih baik. Saya pikir dengan menggunakan daerah nomor terbaik Anda bahkan dapat mencapai O (n log (n)).

  2. Anda harus membuat jalur untuk setiap objek yang bergerak. sistem yang biasa saya lihat sejauh ini adalah hal yang sangat sederhana: setiap kali pemain memerintahkan unit untuk pindah ke suatu tempat komputer menghitung lintasannya, setelah itu dalam setiap siklus jika objek dapat memindahkannya bergerak jika tidak dapat dilewati siklus itu. tidak ada yang istimewa. meskipun Anda juga dapat mengubah algoritme yang diberikan di sini untuk mengurangi panggilan pencarian jalur Anda dan memiliki pencarian jalur waktu nyata untuk setiap kelompok unit, tetapi itu sebenarnya tidak diperlukan.

  3. Anda harus memeriksa apakah ada peluru atau bom atau benda serupa yang mengenai salah satu unit: Anda dapat menggunakan wilayah yang sama yang Anda buat untuk deteksi tabrakan di sini.

  4. untuk memilih unit Anda juga dapat menggunakan wilayah yang sama.

secara umum saya akan menyarankan menggunakan array statis (atau array dinamis dengan ukuran yang disediakan) paling banyak 10.000 atau 20.000. kemudian gunakan sesuatu sekitar 10 atau 15 loop masing-masing iterasi di semua unit. itu adalah susunan besar nyata yang berisi semua unit dari semua pemain. jadi setiap indeks memiliki data tentang pemilik unit dan tipe unit. Anda juga dapat membuat beberapa array lain untuk setiap pemain. di setiap indeks array sekunder ini, Anda hanya perlu menyimpan pointer ke objek di array utama.

jika Anda memiliki pertanyaan lain beri komentar untuk menambahkannya ke jawaban saya.

Ali1S232
sumber
Saya ingat memiliki lebih dari 40.000 di Empires Dawn of the Modern :) :). Malu renderer hanya bisa menyimpan sekitar 1000 di layar meskipun sebelum mereka mulai menghilang, tetapi sisa permainan berfungsi dengan baik :).
deceleratedcaviar
@aniel: itu bukan masalah besar, jenderal tidak memiliki batasan jumlah unit. Saya hanya memberikan beberapa ukuran unit yang baik untuk mendasarkan perhitungan matematika saya. 40000 dan 10000 tidak jauh berbeda satu sama lain.
Ali1S232