Войти на сайт

Авторизация, ждите ...
×

ТЕМА: Как улучшить случайность в RPG Makerʼе

Как улучшить случайность в RPG Makerʼе 6 года 11 мес. назад #101192

  • Dmy
  • Dmy аватар
  • Вне сайта
  • Заблокирован
  • Сообщений: 1142
  • Спасибо получено: 2478
  • УчительПрограммист RubyЗа 2 место на конкурсе маппингаДаритель СтимкеяПроект месяца 3 местоПаладинОраторРазработчикВетеранПоддержка Фонда
Как улучшить случайность в RPG Makerʼе (со скриптами)

В разделе «Курс начальных знаний» я добавил урок «Случайные действия в играх на RPG Makerʼе» с объяснением, как создавать простые случайные действия в RPG Makerʼе. Сейчас я опишу, какие проблемы могут возникнуть при использовании случайных действий и как их решить.

Эта статья для тех, кто уже умеет работать с переменными, устанавливать и вызывать скрипты. (Знание программирования не нужно.) Если вы ещё не умеете этого, возможно, вам стоит сначала почитать другие уроки на нашем сайте. Если что-то непонятно, задавайте вопросы, с радостью отвечу!



Случайность слишком случайная

Случайные числа в RPG Makerʼе создаются по алгоритму, который выдаёт все числа с равной вероятностью. Но это не всегда то, что нам нужно.

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

Поэтому нужны способы ограничить случайность. О некоторых я и напишу дальше.



Перетасовка небольшого количества чисел

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

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

Чтобы перетасовать небольшое количество чисел в RPG Makerʼах VX Ace, XP и VX можно использовать команду вызова скрипта с вот таким кодом:
[1, 2, 3, 4, 5].
  shuffle.each_with_index { |x, i|
    $game_variables[101+i] = x
  }

В RPG Makerʼе MV можно использовать такой код:
[1, 2, 3, 4, 5].
  sort(function () { return 0.5 - Math.random(); })
  .forEach(function (x, i) {
    $gameVariables.setValue(101+i, x);
  })

Вместо 1, 2, 3, 4, 5 введите номера тех чисел, которые вам нужно, главное — разделять запятыми. Можно использовать любое количество цифр. Можно разбивать список на несколько строк.

Вместо 101 в четвёртой строке введите номер переменной, в которую запишется первое число. Остальные запишутся за ней. В этом примере использована переменная 101 и пять чисел, значит, числа запишутся в переменные 101, 102, 103, 104, 105.

А если заменить 101 на 5, то числа запишутся в переменные 5, 6, 7, 8, 9.



Перетасовка большого числа чисел

Если вам нужно записать сразу много-много переменных (например, 100), то они не поместятся в окно ввода скрипта. Поэтому можно использоват другой код. Этот код всегда записывает цифры от 0 до N, не включая N (то есть, например, от 0 до 99).

Код для VX Ace, XP и VX будет выглядеть так:
N=99
[*0..N].
shuffle.each_with_index { |x, i|
    $game_variables[200+i] = x
  }

Код для MV будет выглядеть так:
var N=99
Array.apply(null, {length: N})
  .map(Number.call, Number)
  .sort(function () { return 0.5 - Math.random(); })
  .forEach(function (x, i) {
    $gameVariables.setValue(200+i, x);
  })

В результате выполнения этого кода в переменные от 200 до 300 будут записаны числа от 0 до 99 (всего 100 чисел, так как 0 — тоже число).



Разбиение суммы

Если мы имеем дело с деньгами в сундках, то можно использовать такой вариант: случайно распределить деньги по сундукам с сохранением общей суммы. В итоге если игрок соберёт все сундуки в локации, то у него будет одна и та же сумма денег. А если не все — то уж как повезло.

Тут уже придётся использовать скрипты/плагины.

В RPG Makerʼе VX Ace, XP или VX, создайте новый скрипт с таким содержанием:
def randomlySplitSum(largestSum, numberOfParts, firstVariable)
  sums = [largestSum]
  (numberOfParts - 1).times { |i|
    sums.sort!
    largestNumber = sums.pop
    part = (rand() * largestNumber).floor
    sums.push(part, largestNumber - part)
  }
  sums.shuffle.each_with_index { |x, i|
    $game_variables[firstVariable+i] = x
  }
end

Для RPG Makerʼе MV, сохраните вот этот код в файл с расширением .js в папке plugins и подключите его как плагин:
/**
 * Случайно распределяет сумму largestSum по numberOfParts переменным,
 * причём firstVariable — номер первой переменной.
 */
function randomlySplitSum(largestSum, numberOfParts, firstVariable) {
    var sums = [largestSum];
    for (var i = 0; i < numberOfParts - 1; i++) {
        sums.sort();
        var largestNumber = sums.pop();
 
        var part = Math.floor(Math.random() * largestNumber);
        sums.push(part);
        sums.push(largestNumber - part);
    }
    sums.sort(function (a, b) {
        return 0.5 - Math.random();
    });
    for (var i = 0; i < sums.length; i++) {
        $gameVariables.setValue(firstVariable + i, sums[i]);
    }
}

После этого в том месте кода, где вы хотите разбить сумму случайным образом, вызовите такой код (заменив то, что написано по-русски):
randomlySplitSum(сумма, число_переменных, номер_первой_переменной)

Например:
randomlySplitSum(1000, 10, 30)

Этот код запишет в переменные 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 десять чисел, причём их сумма будет равна 1000.



Пример

Я приготовил пример всего того, что я тут описал, для VX Ace: Randomness_demo.zip (1,3 Мб).

Если вам нужны примеры для какого-то другого движка, пожалуйста, напишите в комментариях, и сделаю и для него! :)

Также пишите, если у вас есть какие-то задачи или нужен какой-то другой алгоритм ограничения случайности. Спасибо за чтение!
Вложения:
Последнее редактирование: 6 года 8 мес. назад от Dmy. Причина: исправлены ошибки в коде для MV
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: AnnTenna, DK, Cabbit, Mur, VarVarKa, Noxmils

Как улучшить случайность в RPG Makerʼе 6 года 11 мес. назад #101254

  • Amphilohiy
  • Amphilohiy аватар
  • Вне сайта
  • Светлый дракон
  • Сообщений: 547
  • Спасибо получено: 666
  • 2 место ГотвУчительПрограммист RubyОраторПобедитель Сбитой кодировки
Я уже давненько приглядываюсь к твоей статье, и раз уж настроение у меня подбитое то и к тебе я тоже прикапаюсь. В основном про разбиение суммы.
Я тут прогнал пару тестов и построил гистограмму. Вот код:
ВНИМАНИЕ: Спойлер! [ Нажмите, чтобы развернуть ]

А тут сама гистограмма
Жадный алгоритм не сохраняет сумму, просто служит примером. Подобные ямы наблюдаются почти во всех прогонах в количестве 1-2 ям (для сундуков не страшно, но знать неплохо) Ямы в начале в конце в целом понятны, хех (забыл отсортировать хеш). При этом жадина - распределение равномерное, как и результат твоего разбиения суммы. Насчет последнего - это просто можно было упомянуть. Нормальное распределение бы держалось середины с более редкими "кукишами" или "джекпотами". Но дело же еще в том, что разбитая сумма включает в себя нули и малые/большие числа, то бишь пола у такой функции нет.

Так же дам по теме ссыль на вики доты про "гладкий" псевдорандом.
На сим откланяюсь.
Я верю, что иногда компьютер сбоит, и он выдает неожиданные результаты, но остальные 100% случаев это чья-то криворукость.
Последнее редактирование: 6 года 11 мес. назад от Amphilohiy.
Администратор запретил публиковать записи гостям.
За этот пост поблагодарили: Dmy
Время создания страницы: 0.235 секунд