Apa metode paling sederhana untuk menghasilkan medan yang halus untuk game 2d?

23

Apa metode paling sederhana untuk menghasilkan medan yang halus untuk game 2d seperti "Moon Buggy" atau "Route 960"?

Saya mendapat jawaban di stackoverflow.com tentang menghasilkan berbagai ketinggian acak dan mengaburkannya nanti. Ya, tidak apa-apa. Tetapi akan lebih baik untuk memberikan beberapa poin, dan mendapatkan kurva yang halus.

astropanik
sumber

Jawaban:

13

Salah satu cara Anda dapat mencapai ini sebagai berikut:

  • Buat titik di tengah layar, dengan ketinggian acak; Anda sekarang memiliki dua bagian, satu di setiap sisi dari titik ini
  • Untuk setiap bagian, bagilah menjadi dua dengan menempatkan satu titik di tengah bagian ini, dengan ketinggian (berkisar) acak antara kedua tetangganya.
  • Ulangi sebanyak n kali.

Yang terjadi adalah detail dalam pemandangan menjadi lebih baik dengan setiap iterasi.

Bagaimana Anda menangani kasus batas terserah Anda: Anda dapat mengasumsikan titik di (0, tinggi / 2) dan (lebar, tinggi / 2) misalnya.

Semoga ini membantu!

EDIT: Ini adalah gambar yang saya buat untuk ilustrasi:

terraingen

Ini ide yang sama!

Tim Kelsall
sumber
12

Dengan asumsi bahwa Anda menginginkan medan yang benar-benar mulus, saya sarankan untuk mundur dari jawaban berbasis kebisingan dan memahami dari mana mereka berasal. Sinyal 'noise' pada dasarnya adalah jumlah sinusoid yang sangat banyak dari amplitudo acak, dengan amplitudo 'rata-rata' pada frekuensi yang diberikan oleh fungsi frekuensi f . Anda bisa mendapatkan sebagian besar definisi 'kebisingan' umum dengan cara ini. Misalnya, gerakan Brown memiliki 1 / f ^ 2respons frekuensi (yaitu, amplitudo rata-rata pada frekuensi yang diberikan berbanding terbalik dengan kuadrat frekuensi): ini berarti bahwa titik-titik terdekat memiliki sedikit korelasi satu sama lain, karena komponen frekuensi tinggi dari sinyal sangat teredam. Sebaliknya, noise fraktal klasik (perpindahan titik tengah, noise Perlin, dll.) Memiliki respons frekuensi 1 / f ; ada lebih banyak perbedaan antara titik-titik terdekat, tetapi masih ada sedikit korelasi. Melangkah lebih jauh, white noise memiliki respons frekuensi konstan - tidak ada korelasi sama sekali antara titik mana pun.

Apa gunanya ini bagi Anda? Nah, Anda bisa mendapatkan sinyal halus yang masih memiliki sedikit tampilan berisik dengan hanya menjumlahkan beberapa sinusoid tetapi memastikan bahwa mereka memiliki amplitudo yang sesuai pada frekuensi tertentu. Anda ingin frekuensinya 'acak' sehingga tidak ada dua dari mereka yang memiliki kelipatan bersama (jika tidak, Anda akan mendapatkan komponen periodik untuk bentuk keseluruhan bukit Anda), jadi saya akan menyarankan sesuatu seperti prosedur berikut (lengkap dengan contoh kerja):

  1. Pilih 4 angka (nyata) secara acak dalam kisaran [1..10] - ini akan menjadi frekuensi gelombang sinus Anda. Saya 'melempar dadu' di random.org dan mendapatkan: f 0 = 1.75, f 1 = 2.96, f 2 = 6.23, dan f 3 = 8.07. Tidak ada yang ajaib tentang angka 4 (Anda dapat menggunakan lebih banyak, tetapi menggunakan lebih sedikit akan mulai membuat gelombang sinus individu lebih jelas) atau kisaran 1 hingga 10 di sini (itu hanya cara untuk memastikan bahwa Anda tertinggi dan terendah frekuensi tidak terlalu berjauhan). Mungkin masuk akal untuk memilih satu frekuensi dalam rentang [1..2] dan sisanya dalam rentang [2..10] hanya agar Anda memiliki sinusoid 'dominan' yang diketahui.
  2. Untuk masing-masing empat (atau namun banyak) frekuensi tersebut f i , memilih amplitudo sebuah i di suatu tempat di kisaran antara -C / f i dan C / f i untuk beberapa konstan C . Nilai yang Anda pilih di sini mengontrol amplitudo keseluruhan gelombang Anda - demi kenyamanan, saya memilih C = 1. Lalu saya membutuhkan angka acak dalam kisaran [-1 / 1.75 (= -0.571) .. 1 / 1.75 (= 0.571) ], dan juga dalam rentang [-0.338 .. 0,338], [-0,161 .. 0,161], dan [-0,124 .. 0,124]. Bergulir dadu empat kali lagi, saya mendapat sebuah 0 = -0,143, sebuah 1 = -0,180, sebuah 2 = -0,012, dana 3 = 0,088. (Perhatikan bahwa ini mungkin bukan cara terbaik untuk melakukan langkah ini - karena nilai maksimum yang mungkin dari fungsi adalah jumlah amplitudo abs ( a 0 ) + abs ( a 1 ) + abs ( a 2 ) + abs ( a 3 ), mungkin lebih masuk akal untuk membagi masing-masing empat Anda seorang i nilai dengan jumlah ini setelah Anda dihasilkan mereka, dan kemudian kalikan masing-masing dengan C sehingga Anda dapat yakin maksimum yang tepat fungsi dapat mencapai adalah C .)
  3. Pilih empat 'offsets' o i , masing-masing dalam kisaran [0..2 (] (0..6.28) - ini akan mengubah titik awal gelombang Anda sehingga semuanya tidak dimulai pada 0. Saya mendapat o 0 = 1,73, o 1 = 4,98, o 2 = 3,17, dan o 3 = 4,63.
  4. 'Plot' fungsi f (x) = a 0 sin ( f 0 (kx + o 0 ) ) + a 1 sin ( f 0 (kx + o 1 ) ) + a 2 sin ( f 0 (kx + o 0 ) ) + a 3 sin ( f 0 (kx + o 0 ) ) - di sini k adalah konstanta lain, konstanta yang mengontrol 'bentangan' horizontal fungsi Anda. Anda harus mencari tahu apa ini untuk aplikasi Anda sendiri; untuk kenyamanan saya baru saja mengambil k= 1, dan fungsi keseluruhan saya adalah f (x) = -0.143 dosa (1,75 ( x + 1,73)) - 0,180 dosa (2,96 ( x +4,98)) - 0,012 dosa (6,23 ( x +3,17)) + 0,088 dosa (8.07 ( x +4.63)).

Berikut ini adalah hasil dari menjalankan contoh saya, seperti diplot di Wolfram Alpha - perhatikan bahwa itu memperbaiki ukuran grafiknya untuk keperluan tampilan, tetapi Anda harus memiliki banyak kendali atas bentangan horizontal dan vertikal dari hasilnya melalui konstanta yang saya sebutkan di atas. :

Sinusoid acak sederhana

Steven Stadnicki
sumber
10

The algoritma perpindahan titik tengah dapat menghasilkan medan 2d indah.

contoh medan

Ada perbedaan tipis antara perpindahan titik tengah dan apa yang disarankan @tykel. Algoritma Tykel membagi lagi horizon dan mengambil ketinggian baru. Ini menciptakan medan di mana puncaknya ditempatkan secara seragam. Manusia hebat dalam memilih keteraturan, sehingga medan yang dihasilkan akan tampak dihasilkan, bukan alami.

Kekuatan Midpoint berasal dari memetik titik tengah kemudian berpindah sepanjang garis normal dari garis itu. Hal ini menyebabkan puncak bervariasi dari atas ke bawah serta sisi ke sisi. Medan yang dihasilkan adalah fraktal, dan manusia menganggap fraktal sebagai alami.

Perpindahan ketinggian acak dapat menghasilkan medan keturunan jika Anda menambahkan beberapa parameter lagi (perpindahan horizontal, kemiringan maksimum, dll). Ini menyoroti kekuatan GKG lainnya; sangat mudah untuk disetel. Dua parameter, kekentalan dan tingkat detail.

deft_code
sumber
7

Anda dapat menggunakan fungsi noise untuk menghasilkan ketinggian acak. Yang paling sederhana adalah nilai noise, yang bekerja persis seperti deskripsi Anda: Anda menghasilkan beberapa ketinggian integer acak, dan kemudian menyisipkan ketinggian di antara mereka. Metode interpolasi yang paling sering digunakan adalah pemetaan kurva S-cubic:

Misalkan Anda memiliki tinggi h0pada titik x0dan tinggi h1pada titik x1. Kemudian untuk mendapatkan ketinggian di titik mana pun x( x0<=x<=x1), Anda gunakan

t = (x-x0)/(x1-x0); // map to [0,1] range
t = t*t*(3 - 2*t); // map to cubic S-shaped curve
h = h0+t*h1;

Ketinggian yang diperoleh dengan cara ini akan mulus, acak, tetapi tidak terlalu menarik. Untuk membuat medan Anda lebih baik, Anda dapat menggunakan fraktal noise . Ini berfungsi seperti ini: misalkan Anda telah menghasilkan fungsi h(x)yang mengembalikan ketinggian pada koordinat yang diberikan (menggunakan metode di atas). Fungsi ini memiliki frekuensi, ditentukan oleh frekuensi ketinggian interger asli. Untuk membuat fraktal darinya, Anda menggabungkan fungsi bersama dengan beberapa frekuensi:

fbm(x)=h(x) + 0.5*h(2*x) + 0.25*h(4*x) + 0.125*h(8*x);

Dalam contoh ini, saya menggabungkan empat frekuensi - asli, ganda, 4 kali dan 8 kali asli, dengan frekuensi yang lebih tinggi dengan bobot yang lebih sedikit. Secara teoritis, fraktal berjalan hingga tak terhingga, tetapi dalam praktiknya hanya diperlukan beberapa istilah. The fbmdalam rumus singkatan gerak Brown pecahan - ini adalah nama fungsi ini.

Ini adalah teknik yang kuat. Anda dapat bermain dengan pengganda frekuensi, dengan bobot frekuensi yang berbeda, atau menambahkan beberapa fungsi untuk mendistorsi kebisingan. Misalnya, untuk mendapatkan lebih banyak nuansa "bergerigi", h(x)dapat diubah menjadi 1-abs(h(x))(dengan asumsi -1<=h(x)<=1)

Namun, walaupun semua ini bagus, teknik ini memiliki batasan serius. Dengan pendekatan berbasis "ketinggian", Anda tidak akan pernah bisa memiliki "overhang" medan. Dan saya membayangkan mereka menjadi fitur yang sangat bagus untuk dimainkan di game "Moon Buggy".

Menambahkan overhang yang bagus adalah tugas yang sulit. Satu hal yang bisa saya pikirkan - Anda bisa mulai dengan "ketinggian" fraktal, dan "tessellate" menjadi serangkaian splines atau kurva bezier. Maka garis medan akan ditentukan oleh beberapa "titik kunci". Berikan sedikit jitter pada titik-titik utama ini - ini akan menghasilkan deformasi acak pada medan, mungkin membentuk beberapa bentuk yang menarik. Namun, persimpangan-sendiri medan mungkin menjadi masalah dengan pendekatan ini, terutama dengan jumlah jitter yang tinggi.

Sudahlah
sumber
4

Ada dua metode populer untuk menghasilkan peta ketinggian medan.

Beberapa jawaban yang diberikan di sini sudah didasarkan pada algoritma Diamond-square, tetapi mengetahui namanya membuatnya lebih mudah untuk mencari informasi lebih lanjut. Perlin noise juga memiliki kegunaan lain, jadi ada baiknya untuk memeriksanya.

msell
sumber
OP berbicara tentang lanskap 2D bergaya mario, tetapi ini masih merupakan tautan yang bagus.
tenpn
1

Gagasan saya adalah membuat fungsi noise yang dihaluskan. Pertama dengan metode intNoise (int) yang mengembalikan int "acak", tetapi yang tergantung pada input. Jika Anda menggunakan input yang sama dua kali, hasilnya akan sama.

Kemudian gunakan metode smoothing untuk membuat floatNoise (float) yang menggunakan dua bilangan bulat di sekitar input untuk membangun nilai acak.

Kemudian gunakan posisi X sebagai input dan Y sebagai output. Hasilnya akan menjadi kurva yang dihaluskan tetapi dengan ketinggian acak.

XGouchet
sumber