З того, що я можу сказати *, L-Systems - це набір граматичних правил заміни, які ви можете застосовувати рекурсивно, щоб отримати цікаві, "органічні" результати.
Заводи часто використовують L-системи, оскільки вони демонструють багато рекурсивного зростання (тобто гілка розпадається на більше гілок). Для простого прикладу я покажу дерево "льодяник", сформоване за допомогою системи L:
variables : | o (these are the things that will grow)
start : o
| (this is what we start with)
rules : (o → o o) (these are the substitution rules that we apply
\ / one step at a time)
Отже, у поколінні 1 ми тільки починаємо:
o
|
У другому поколінні ми дотримуємось кожного з правил і підміняємо існуючі частини відповідно до правил. Заміняємо "кульки" на "дві палички і кульки":
o o
\ /
|
Покоління 3:
o o o o
\| |/
\ /
|
Незабаром у нас буде гарне (хитре) велике дерево!
Для цього в коді ви можете робити це рекурсивно (тобто DFS), постійно застосовуючи правила до одних і тих же частин, поки не досягнете якогось довільного кінця, або ви можете це робити ітеративно (тобто BFS), як ми це робили в цьому прикладі , виконуючи одне правило «пройти» на всі елементи і повторити ряд кроків. Це є:
Рекурсивно:
tree = start
grow(tree, start)
func grow(tree, part)
if this part of the tree is big enough
stop
if part is 'o'
replace part with 'o\/o'
grow(tree, the left 'o')
grow(tree, the right 'o')
Ітеративно:
tree = start
for a number of iterations
for each part in tree
if part is 'o':
replace with 'o\/o'
Багато використання L-систем виконують крок "зростання", використовуючи підрозділ - тобто деталі зменшуються, оскільки вони "вирощуються", більші частини просто поділяються. Інакше ваша зростаюча система може почати перекриватися поверх себе. Ви побачите на прикладі мого льодяника, я магічно переконався, що дві гілки не перетинаються посередині, змінюючи форму нових гілок. Зробимо приклад міста за допомогою підрозділу:
variables: block_vertical block_horizontal road_vertical road_horizontal
start: block_vertical
rules: (block_vertical → block_horizontal road_vertical block_horizontal)
(block_horizontal → block_vertical road_horizontal block_vertical)
Це матиме сенс через хвилину.
Покоління 1:
+--------------------+
| |
| |
| |
| V |
| |
| |
| |
+--------------------+
Єдиний, нудний вертикальний блок. (V означає вертикаль.)
Покоління 2: вертикальний блок замінюємо горизонтальними блоками вертикальною дорогою посередині
+--------------------+
| r |
| r |
| r |
| H r H |
| r |
| r |
| r |
+--------------------+
R означає дорогу! Я випадковим чином розподілив розкол, ми не хочемо нудних регулярних деталей в PCG.
Покоління 3: горизонтальні блоки замінюємо вертикальними блоками, розділеними на горизонтальні дороги. Залишилися існуючі дороги; для них немає правил.
+--------------------+
| V r |
| r |
|rrrrrrrr |
| r V |
| V r |
| rrrrrrrrrrrrr|
| r V |
+--------------------+
Зауважте, як дороги з'єднуються між собою, що приємно. Повторіть це достатньо разів, і у вас вийде щось подібне (нахабно зірвавши відповідну відповідь ):
Зауважте, що є багато деталей, які я не висвітлював, і що цей результат виглядає "очевидно" породженим - реальні міста виглядають дещо інакше. Ось що робить PCG весело / важко. Є нескінченні речі, які ви можете зробити для налаштування та покращення своїх результатів, але будучи не пов'язаними з L-Systems, я залишу цю відповідь тут; сподіваюся, що це допоможе вам почати роботу.
* - Я формально не вивчав L-системи, хоча зіткнувся з конкретними типами, такими як граматика та PCG-рослинність; будь ласка, виправте мене, якщо я визнаю неправильні визначення чи поняття