Как улучшить случайность в 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 Мб).
Если вам нужны примеры для какого-то другого движка, пожалуйста, напишите в комментариях, и сделаю и для него!
Также пишите, если у вас есть какие-то задачи или нужен какой-то другой алгоритм ограничения случайности. Спасибо за чтение!