Чисте функціональне програмування та ігровий стан


12

Чи існує загальна методика обробки стану (загалом) у функціональній мові програмування? Існують рішення в кожній (функціональній) мові програмування для управління глобальним станом, але я хочу уникати цього, наскільки я міг.

Всі стану в чисто функціональному порядку є функціональними параметрами. Тому мені потрібно поставити весь ігровий стан (гігантську хешмап зі світом, гравцями, позиціями, рахунком, активами, ворогами, ...) як параметр для всіх функцій, які хочуть маніпулювати світом за певним входом або тригером . Сама функція вибирає відповідну інформацію з ігрового блоку, робить щось з нею, маніпулює ігратом і повертає іграт. Але це виглядає як бідне рішення чоловіка для проблеми. Якщо я покладу цілі ігри на всі функції, для мене немає користі на відміну від глобальних змінних чи імперативного підходу.

Я міг би помістити у функції лише відповідну інформацію та повернути дії, які будуть вжиті за даний вхід. І одна єдина функція застосовує всі дії до gametate. Але для більшості функцій потрібно багато "відповідної" інформації. move()потрібні положення об'єкта, швидкість руху, карта для зіткнення, положення всіх клізм, стан здоров'я, ... Тож цей підхід, схоже, не працює.

Отже, моє запитання полягає в тому, як я обробляю величезну кількість стану функціональною мовою програмування - особливо для розробки ігор?

EDIT: Існують деякі ігрові рамки для побудови ігор у Clojure. Підхід до часткового вирішення цієї проблеми полягає в тому, щоб вивести всі об’єкти в грі як "сутності" і покласти їх у величезний мішок. Гігант Основна функція тримає екран і сутності та обробки подій ( :on-key-down, :on-init, ...) для цього осіб і запустити головний цикл відображення. Але це не те чисте рішення, яке я шукаю.


Я деякий час думав про подібні речі; для мене це не є вхідною проблемою, тому що вам все одно доведеться подавати однакові елементи до функцій нефункціонального програмування. Ні, в цьому є проблема виводу (та наступних пов'язаних оновлень). Деякі ваші вхідні параметри слід поєднувати; бо move(), ви, ймовірно, повинні переходити в "поточний" об'єкт (або його ідентифікатор), плюс світ, через який він рухається, і просто отримувати поточну позицію і швидкість ... вихід - це весь світ фізики, або принаймні список змінених об’єктів.
Годинник-Муза

Перевага чистого функціоналу полягає в тому, що прототипи функцій показують всі залежності вашої програми.
tp1

3
IMO, функціональні мови погано підходять для написання ігор. Це одна з багатьох проблем, яку вам потрібно буде вирішити. Ігри вимагають дуже точного контролю продуктивності і рідко мають хорошу конкурентоспроможність через непередбачуваний спосіб природних явищ. (Чисті) функціональні мови відрізняються тривіально паралелізацією та важкими для оптимізації. У гру HARD писати, і я рекомендую робити її типовою мовою, перш ніж братись за щось таке ж складне (функціональне програмування).
Кейсі Кубалл

Відповіді:


7

Побічні ефекти та стан функціональних мов програмування є більш широкою проблемою в інформатиці. Якщо ви не стикалися з ними раніше, можливо, погляньте на монадів . Але будьте попереджені: вони є досить просунутою концепцією, і більшість людей, яких я знаю (включаючи мене), намагаються їх зрозуміти. В Інтернеті є багато, багато навчальних посібників з різними підходами та вимогами до знань. Особисто мені найбільше сподобався Ерік Ліпперт.

Я програміст на C #, не маючи жодного фонового функціонального програмування. Що це за «монада», про яку я постійно чую, і яке це від мене використання?

Ерік Ліпперт про Монади

Однак слід врахувати деякі речі:

  • Ви наполягаєте на використанні суто функціональної мови? Якщо ви кваліфіковані як у функціональному програмуванні, так і в розробці ігор, можливо, ви могли б це зняти. (Навіть хоч хотілося б знати, чи варто користь ваших зусиль.)
  • Чи не було б краще використовувати функціональний підхід лише там, де це необхідно? Якщо ви використовуєте об'єктно-орієнтовану (або, швидше за все, мульти-парадигму) мову, ніщо не заважає вам використовувати функціональний стиль для реалізації розділів, які отримують з неї прибуток. (Щось подібне до MapReduce, можливо?)

Кілька заключних думок:

  • Паралелізм: Хоча ігри і так активно використовують його, AFAIK більшість із них уже відбувається в GPU.
  • Без громадянства: Мутації стану є невід’ємною частиною ігор. Намагання позбутися від них може просто ускладнювати справи без потреби.
  • Можливо, подивіться, як функціональна мова F # грає з об'єктно-орієнтованою екосистемою .NET, якщо вас цікавить.

Загалом, я думаю, навіть якщо це може бути цікаво академічно, я сумніваюся, що такий підхід практичний і вартий зусиль.


Навіщо публікувати коментар до теми, з якою у вас немає досвіду? Думка людей, захоплених однією парадигмою мислення.
Ентоні Раймондо

4

Я написав кілька ігор, використовуючи F # (багатопарадигма, нечистий, функціонально-першої мови), з підходами, починаючи від OOP до FRP . Це питання широке, але я зроблю все можливе.

Чи існує загальна методика обробки стану (загалом) у функціональній мові програмування?

Мій кращий спосіб - мати непорушний тип, який представляє всю гру State. Потім у мене є змінна посилання на струм, Stateякий оновлюється кожною галочкою. Це не суворо чисто, але він зберігає незмінність лише одним місцем.

Якщо я покладу цілі ігри на всі функції, для мене немає користі на відміну від глобальних змінних чи імперативного підходу.

Неправда. Оскільки Stateтип є непорушним, у вас не може бути жодного старого компонента, що мітує світ неправильно визначеними способами. Це вирішує найбільшу проблему GameObjectпідходу (популяризованого Unity): важко контролювати порядок Updateдзвінків.

І на відміну від глобальних, це легко перевіряти і паралелізувати одиниці,

Ви також повинні написати допоміжні функції, які отримують підвластивості стану, щоб розбити проблему.

Наприклад:

let updateSpaceShip ship = 
  {
    ship with 
      Position = ship.Position + ship.Velocity
  }

let update state = 
  { 
    state with 
      SpaceShips = state.SpaceShips |> map updateSpaceShip 
  }

Тут updateдіє на всю державу, але updateSpaceShipдіє лише на окрему людину SpaceShipізольовано.

Я міг би помістити у функції лише відповідну інформацію та повернути дії, які будуть вжиті за даний вхід.

Моєю пропозицією було б створити Inputтип, який містить умови клавіатури, миші, ігрової панелі тощо. Потім ви можете написати функцію, яка приймає Stateта Inputповертає наступне State:

let applyInput input state = 
  // Something

Щоб дати вам уявлення про те, як це поєднується, загальна гра може виглядати приблизно так:

let mutable state = initialState ()

// Game loop
while true do
  // Apply user input to the world
  let input = collectInput ()

  state <- applyInput input state

  // Game logic
  let dt = computeDeltaTime ()

  state <- update dt state

  // Draw
  render state

Отже, моє запитання полягає в тому, як я обробляю величезну кількість стану функціональною мовою програмування - особливо для розробки ігор?

Для простих ігор ви можете використовувати підхід вище (допоміжні функції). Для чогось складнішого ви можете спробувати " лінзи ".

Всупереч деяким коментарям тут, я настійно пропоную писати ігри на (нечистій) функціональній мові програмування або хоча б спробувати! Я виявив, що це робить ітерацію швидшою, бази кодів меншими, а помилки - менш поширеними.

Я також не думаю, що вам не потрібно вчити монадів писати ігри на (нечистій) FP мові. Це тому, що ваш код, швидше за все, буде блокуватися та однопоточний.

Це особливо вірно, якщо ви пишете багатокористувацьку гру. Тоді з цим підходом все стане набагато простіше, оскільки він дозволяє тривіально серіалізувати ігровий стан та надсилати його по мережі.

Що стосується того, чому більше ігор написано не так… Я не можу сказати. Однак це справедливо у всіх областях програмування (крім можливо фінансів), тому я б не використовував це як аргумент того, що функціональні мови непридатні для ігрового програмування.

Також варто прочитати « Чисто функціональні ретрогри» .


1

Що ви шукаєте, це розробка ігор FRP.

Деякі відео вступи:

На 100% можливо і бажано зробити основну ігрову логіку чисто функціональним способом, галузь загалом просто позаду, застрягла в одній парадигмі мислення.

Це можливо зробити і в Єдності.

Щоб відповісти на запитання, новий стан гри буде оновлюватися / створюватися кожного разу, коли щось рухається, як каже автомат у своїй розмові, це не проблема. Різке зменшення когнітивних накладних витрат, що випливає з суто функціональної, дуже досяжної, гнучкої архітектури, далеко не дозволяє досягти ефективності, якщо вона взагалі існує.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.