Неизменный игровой объект, основной вопрос функционального программирования - PullRequest
8 голосов
/ 20 июля 2010

Я пытаюсь «узнать больше» и «извлечь уроки» из функционального программирования и идеи неизменности, полезной для параллелизма и т. Д.

В качестве мыслительного упражнения я представил себепростая игра, в которой персонаж типа Mario-esq может бегать и прыгать с врагами, которые стреляют в него ...

Затем я попытался представить, что это написано функционально с использованием неизменных объектов.

Это подняло некоторыевопросы, которые озадачивали меня (будучи программистом по императивному OO).

1) Если мой маленький парень в позиции x10, y100 двигается вправо на 1 единицу, я просто восстанавливаю его, используя его старые значения со +1 к егопозиция x (например, x11, y100)?

2) (Если мое первое предположение верно) Если мой входной поток перемещает маленького парня вправо на 1 единицу, и мой вражеский поток AI стреляет в маленького парня, а вражеский поток ai разрешаетсяперед потоком ввода мой парень потеряет здоровье, затем после разрешения потока ввода вернет его обратно и переместится вправо ...

Означает ли это, что я не могу уволить - и - забытьмои темы даже с неизменяемостью?Нужно ли мне отправлять свои потоки, чтобы они синхронно делали свое дело, затем new (), когда у меня есть результаты обеих потоковых операций?или есть простое «функциональное» решение?

Это немного другая проблема с многопоточностью, с которой я сталкиваюсь ежедневно.Обычно я должен решить, волную ли меня, в каком порядке разрешаются потоки или нет.Где, как и в приведенном выше случае, технически мне все равно, получает ли он урон или двигается первым.Но мне не все равно, из-за того, что условия гонки во время создания экземпляра приводят к полной потере данных одного потока.

3) (Опять же, если мое первое предположение верно) Имеет ли постоянно создаваемый экземпляр новых экземпляров объекта (например, парень из Марио)ужасные накладные расходы, которые делают это очень серьезным / важным дизайнерским решением?

РЕДАКТИРОВАТЬ Извините за это дополнительное редактирование, я не очень рекомендую здесь о последующих вопросах ...

4) Если неизменность - это то, что я долженстремиться и даже прыгать через обручи создания новых версий объектов, которые изменились ... И если я создаю экземпляр моего парня каждый раз, когда он движется (только с другой позицией), разве у меня нет точно таких же проблем, как если бы онбыл изменчив?в той степени, в которой что-то, что ссылалось на него в какой-то момент времени, на самом деле смотрит на старые значения? .. Чем больше я копаюсь в этом, тем больше вращается моя голова, поскольку генерация новых версий одной и той же вещи с разными значениями просто кажется изменчивостью, черезхак.: ¬?

Наверное, мой вопрос: как должно работать?и как это выгодно просто поменять свою позицию?

for(ever)//simplified game-loop update or "tick" method
{
   if(Keyboard.IsDown(Key.Right)
      guy = new Guy(guy){location = new Point(guy.Location.x +1, guy.Location.y)};
}

Также сбивает с толку: приведенный выше код означает, что парень изменчив! (даже если его свойства не таковы)

4.5)что вообще возможно с абсолютно неизменным парнем?

Спасибо,

J.

Ответы [ 5 ]

3 голосов
/ 20 июля 2010

Пара комментирует ваши очки:

1) Да, может быть. Чтобы уменьшить накладные расходы, практический проект, вероятно, в конечном итоге будет разделять много состояний между этими экземплярами. Например, возможно, ваш маленький парень имеет структуру «Оборудование», которая также является неизменной. Новая копия и старая копия могут безопасно ссылаться на одну и ту же структуру «оборудования», поскольку она неизменна; так что вам нужно всего лишь скопировать ссылку, а не все. Это общее преимущество, которое вы получаете только благодаря неизменности - если «оборудование» было изменчивым, вы не могли бы поделиться ссылкой, так как если бы оно изменилось, ваша «старая» версия тоже изменилась бы.

2) В игре наиболее практичным решением этой проблемы, вероятно, было бы использование глобальных «часов» и выполнение подобного рода обработки один раз за один такт. Обратите внимание, что ваш точный сценарий все еще будет проблемой, если вы не напишите его в функциональном стиле: предположим, что H0 - это состояние здоровья в момент времени T. Если вы передали H0 функции, которая приняла решение о состоянии здоровья в момент времени T, вы приняли повреждение в момент времени T + 1, а затем функция, возвращенная в момент времени T + 5, возможно, она приняла неверное решение в зависимости от вашего текущего состояния здоровья.

3) На языке, который поощряет функциональное программирование, создание объектов часто делается как можно дешевле. Я знаю, что в JVM создание небольших объектов в куче происходит так быстро, что это вообще не учитывает производительность в любой практической ситуации, а в C # я никогда не сталкивался с такой ситуацией.

2 голосов
/ 21 июля 2010

1) Если мой маленький парень на позиции х10, у100 движется вправо 1 единицу я просто восстановить его, используя его старый значения с +1 к его позиции х (например, x11, y100)?

Ну, не обязательно. Вы можете создать экземпляр этого парня один раз и изменить его положение во время игры. Вы можете смоделировать это с агентами. Парень - агент, как и ИИ, и поток рендеринга, и пользователь.

Когда ИИ стреляет в парня, он отправляет ему сообщение, когда пользователь нажимает клавишу со стрелкой, которая отправляет другое сообщение и т. Д.

 let guyAgent (guy, position, health) =
     let messages = receiveMessages()
     let (newPosition, newHealth) = process(messages)
     sendMessage(renderer, (guy, newPosition, newHealth))
     guyAgent (guy, newPosition, newHealth)

«Все» теперь является неизменным (на самом деле, под капотом очередь дипатча агента, вероятно, имеет некоторое изменяемое состояние).

4) Если неизменность это то, что я должен стремиться и даже прыгать, хотя Обручи создания новых версий объекты, которые изменились ... И если я создавать экземпляр моего парня каждый раз, когда он движется (только с другой позиции) не У меня точно такие же проблемы, как и у меня был бы, если бы он был изменчивым?

Ну да. Цикл с изменяемыми значениями и повторение с неизменяемыми эквивалентны.

Edit:

  1. Для агентов wiki всегда полезен.
  2. Лука Болоньезе имеет F # реализацию агентов.
  3. Эта книга (называемая некоторыми Книгой интеллектуальных агентов ), хотя и нацелена на приложения ИИ (вместо того, чтобы иметь инженерную точку зрения ПО), превосходна.
0 голосов
/ 13 июня 2014

Другой функциональный подход к решению проблемы такого рода - сделать шаг назад и отделить идею состояния от идеи вашего маленького парня.

Ваше состояние будет включать в себя положение вашего маленького парня, а также положение вашего злодея и его выстрела, а затем у вас есть некоторые функции, которые принимают некоторые или все состояния и выполняют такие вещи, как создание следующего состояния и рисование экрана. .

Проблемы синхронизации, о которых вы говорите, когда вещи, которые вы хотите распараллелить, зависят друг от друга, являются реальными проблемами, которые волшебным образом не исчезнут, хотя решения могут быть более или менее удобными на разных языках.

Несколько предложений уже были сделаны, и существует множество решений для параллелизма. Центральные часы и агенты будут работать, как и программная транзакционная память, мьютексы или CSP (каналы в стиле go) и, возможно, другие. Лучший подход будет зависеть от специфики проблемы и в определенной степени от личного вкуса.

Что касается закручивания головы, постарайтесь не слишком увлекаться тем, меняется ли вещь или нет. Суть неизменности состоит не в том, что вещи не меняются, а в том, что вы можете создавать чистые функции, чтобы ваша программа была легче рассуждать.

Например, у ОО-программы может быть функция рисования, которая перебирает все объекты в сцене и просит их всех нарисовать себя, тогда как функциональная программа может иметь функцию, которая принимает состояние и рисует рамку.

Конечным результатом будет та же сцена, но способ, которым организована логика и состояние, сильно отличается.

Я, например, нахожу, что намного легче работать, когда у вас есть все данные здесь, в одном большом входном кусочке, и вся логика рисования там, инкапсулированная в некоторых функциях. Также есть несколько довольно четких архитектурных побед - сериализация, тестирование и замена внешних интерфейсов намного проще с такой структурой.

0 голосов
/ 21 июля 2010

Если все в глобальном системном состоянии, за пределами текущего кадра стека, является неизменным, если только другой поток не ссылается на что-то в стеке ( ОЧЕНЬ ОПАСНО ), не будет никакого способа темы, чтобы сделать что-нибудь, чтобы повлиять друг на друга. Вы можете выстрелить и забыть, или просто не беспокоиться об увольнении, и эффект будет тот же.

Предполагая, что есть некоторые части глобального состояния, которые являются изменяемыми, один полезный шаблон:

Do
  Latch a mutable reference to an immutable object
  Generate a new object based upon the latched reference
Loop While CompareExchange fails.

Обмен сравнениями должен обновить изменяемую ссылку на новую, если она все еще указывает на старую. Это позволяет избежать накладных расходов на блокировку, если нет одновременного доступа, но может работать хуже, чем блокировка, если многие потоки пытаются обновить один и тот же объект, и генерация нового экземпляра из заблокированного экземпляра идет медленно. Одним из преимуществ этого подхода является отсутствие опасности тупика, хотя в некоторых ситуациях может возникнуть liveLock.

0 голосов
/ 20 июля 2010

Не все в вашей программе должно быть неизменным.Положение игрока - это то, что вы ожидаете изменить.Его имя, может быть, нет.

Неизменность хороша, но вам, возможно, следует пересмотреть свой подход, чтобы использовать более параллельные решения, чем простые «неизменяемые», то есть все.Учтите это

Нить AI получает копию вашей позиции. Вы перемещаете три единицы влево.ИИ стреляет в вас, основываясь на вашей старой позиции, и попадания ... не должны происходить!

Кроме того, большая часть игр выполняется в «игровых тиках» - многопоточность не так уж и велика!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...