Как стать автором
Обновить

Комментарии 17

Имхо идеальное решение — иметь несколько ГПСЧ, по одному под каждое независимое активити со случайными числами — один под действия мобов, один под генерацию уровней, один под случайные события, один под генерацию урона мин-макс (а-ля стреляем 6-12, выпало 11), итд. UnityEngine.Random, судя по описанному, синглтон и подобное не позволяет, при этом логика ГПСЧ ломается установкой сида при генерации уровня и отсутствием переинициализации его после завершения. И ИМХО нафиг не надо сохранять старый seed, если требуется установить сид у синглтон-ГПСЧ в некое значение, просто потом взять сид откуда-нибудь ещё, вплоть до System.random или хэша от даты вместе с ним. Проще говоря, авторы игры неправильно использовали Random, но в самом рандоме проблем нет — он работает как надо. Но новый класс использовать необязательно, можно и имеющимся обойтись, просто поаккуратнее заниматься переинициализацией сида.

Согласен, поинт валидный, можно не делать как указано в примере. Основная задача была акцентировать внимание на том, что UnitiEngine.Random — static и к каким проблемам это может привести.

Как выше уже заметили, устанавливать seed нужно только в случае, если надо получать одинаковые последовательности случайных чисел. Это может быть удобно, например, для отладки.
Зачем вы трогали seed, если вам нужны разные случайные числа — непонятно.


5 экземпляров и 1мб памяти пропадает.

Это, мягко говоря, не так.

var start = GC.GetTotalMemory(true);
var rnd = new Random();
var rnd2 = new Random();
var rnd3 = new Random();
var rnd4 = new Random();
var rnd5 = new Random();
var stop = GC.GetTotalMemory(true);
Console.WriteLine(stop - start); // 1400 получается

Либо так, либо я что-то не правильно делаю.

Это килобайт, но не мегабайт.

Верно. Ошибка, поправил.
Спасибо!
Это может быть удобно, например, для отладки.
Еще это иногда используется чтобы игрок не мог перекрутить вероятности в свою пользу перезагрузив сохранение.

Все проблемы не из-за статичности UnityEngine.Random, а из-за того, что кто-то не разбираясь воткнул первое что под руку подвернулось.
Нет никаких проблем с тем чтобы использовать ГПСЧ, seed для которого задаётся глобально, но этот seed должен задаваться один раз для проекта. Это нормальное архитектурное решение, потому что нередко нужен генератор псевдослучайных событий, но при этом нет необходимости в воспроизведении состояния. Такой подход используется во многих языках и библиотеках.


Поэтому надо не "перестать использовать UnityEngine.Random", а начать читать документацию и использовать инструменты для тех целей, для которых они предназначены, только и всего. Нужно сохранение состояния — используй подходящий генератор.


Стоит отметить, что MCG, LCG и товарищи, хоть и (относительно) быстрые, но стоит отметить, что энтропия у них хуже, чем у xorshift, который судя по отзывам используется в UnityEngine.Random, и ГПСЧ в System.Random. Это вряд ли кто-либо заметит, впрочем.

начать читать документацию и использовать инструменты для тех целей, для которых они предназначены

В документации нет ни слова о предназначении.
В целом совет не плохой, воспользуйтесь им.

Нет никаких проблем с тем чтобы использовать ГПСЧ, seed для которого задаётся глобально

Согласен, но проблема появится тогда, когда он перестанет быть единственным.
Если для уровня нужен повторяемый генератор — _для него_ надо брать отдельный генератор. Всё остальное использующее один генератор это хорошо — все события получаются смешанные и малейшее изменение начального сида дадут разное поведение для всех.

Да, важно — сид не трогать. Его вообще не должно быть видно вне тестов.
В 2020.1.16 при подключении вашего пакейджа вываливаются варнинги.

Script 'Packages/fastrandom/src/RandomSeed.cs' will not be compiled because it exists outside the Assets folder and does not to belong to any assembly definition file.
UnityEditor.Scripting.ScriptCompilation.EditorCompilationInterface:TickCompilationPipeline(EditorScriptCompilationOptions, BuildTargetGroup, BuildTarget, String[])
Исправил. Но такие вещи, лучше всего писать в issue на github.
Спасибо.
Я правильно понимаю, что борясь с особенностями реализации рандома в Unity вы заиспользовали самый тупейший из существующих генераторов, у которых случайности не случайны и призываете им пользоваться?
private double InternalSample()
    {
        var ret = _next * ModulusReciprocal;
        _next = _next * Multiplier % Modulus;
        return ret;
    }
Да, именно. Самый тупой, самый простой.
Если нужно больше, сделайте собственную реализацию интерфейса IRandom.
Долго выбирая сколько реализаций предоставлять (я рассмотрел около 10), остановился на том, что чем проще, тем лучше. Для всего остального есть интерфейс.
Ну нееет… Это так не работает. Если человек в состоянии написать нормальный генератор псевдослучайных чисел, ему вся ваша статья как бы очевидна будет. А если не в состоянии — то возьмёт ваш пример, и будет использовать там, где вы не планировали.
Вы в ответе за тех, кого приручили. Было бесчисленное количество ошибок, связанное с тем, что люди делали какой-то функционал для базовых сценариев, а все их использовали для других. Поэтому как раз в .NET и заюзали для этого не самый быстрый, но зато достаточно «случайный» метод Фиббоначи с запаздыванием. Чтобы как раз, кому надо быстроту, мог использовать и ЛКГ, а кому пофиг на всё — не ловил бы проблем из-за некачественной базовой реализации.
Проблема придет оттуда, откуда ее не ждут.
В моем случае она пришла, когда проставили seed в UE.Random.

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

Подумать за всех? Окей, добавлю SLPNG, но это не поможет решить проблему с использованием UE.Random.
Вопрос, а почему бы просто не, скажем, просто складывать глобальный сид с временем на компьютере пользователя перед тем как высчитывать рандом? Как сказали выше — глобальный сид это вещь крайне полезная, а проблема одинаковости вполне элементарно решается введением одного дополнительного элемента, а не постройкой велосипедов.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории