- Сообщений: 1142
- Спасибо получено: 2483
Как улучшить случайность в RPG Makerʼе
8 года 5 мес. назад - 8 года 2 мес. назад #101192
от Dmy
Dmy создал тему: Как улучшить случайность в RPG Makerʼе
Как улучшить случайность в RPG Makerʼе (со скриптами)
В разделе «Курс начальных знаний» я добавил урок « Случайные действия в играх на RPG Makerʼе » с объяснением, как создавать простые случайные действия в RPG Makerʼе. Сейчас я опишу, какие проблемы могут возникнуть при использовании случайных действий и как их решить.
Эта статья для тех, кто уже умеет работать с переменными, устанавливать и вызывать скрипты. (Знание программирования не нужно.) Если вы ещё не умеете этого, возможно, вам стоит сначала почитать другие уроки на нашем сайте. Если что-то непонятно, задавайте вопросы, с радостью отвечу!
Случайность слишком случайная
Случайные числа в RPG Makerʼе создаются по алгоритму, который выдаёт все числа с равной вероятностью. Но это не всегда то, что нам нужно.
Случайные события по-настоящему случайны. Кто-то купит один лотерейный билет и сразу выиграет, а кто-то покупает их всю жизнь и ничего не выигрывает. В играх так делать нельзя: если в игре одни игроки всегда побеждают, а другие всегда проигрывают, и это не зависит от них, то такая игра будет неинтересной.
Поэтому нужны способы ограничить случайность. О некоторых я и напишу дальше.
Перетасовка небольшого количества чисел
Один способ, как сделать игру случайной, но не слишком случайной, можно подглядеть в карточных играх. В карточных играх есть ограниченный набор карт, который мы просто перетасовываем. Но карты в колоде всё равно те же самые. Никто не может получить шесть козырных тузов, потому что козырный туз в колоде только один. Это обеспечивает некоторый баланс.
В RPG Makerʼе такая случайность не встроена, но в него встроена возможность использования скриптов, которая позволяет добавить любую недостающую функцию.
Чтобы перетасовать небольшое количество чисел в RPG Makerʼах VX Ace, XP и VX можно использовать команду вызова скрипта с вот таким кодом:
В RPG Makerʼе MV можно использовать такой код:
Вместо 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 будет выглядеть так:
Код для MV будет выглядеть так:
В результате выполнения этого кода в переменные от 200 до 300 будут записаны числа от 0 до 99 (всего 100 чисел, так как 0 — тоже число).
Разбиение суммы
Если мы имеем дело с деньгами в сундках, то можно использовать такой вариант: случайно распределить деньги по сундукам с сохранением общей суммы. В итоге если игрок соберёт все сундуки в локации, то у него будет одна и та же сумма денег. А если не все — то уж как повезло.
Тут уже придётся использовать скрипты/плагины.
В RPG Makerʼе VX Ace, XP или VX, создайте новый скрипт с таким содержанием:
Для RPG Makerʼе MV, сохраните вот этот код в файл с расширением .js в папке plugins и подключите его как плагин:
После этого в том месте кода, где вы хотите разбить сумму случайным образом, вызовите такой код (заменив то, что написано по-русски):
Например:
Этот код запишет в переменные 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 десять чисел, причём их сумма будет равна 1000.
Пример
Я приготовил пример всего того, что я тут описал, для VX Ace: Randomness_demo.zip (1,3 Мб).
Если вам нужны примеры для какого-то другого движка, пожалуйста, напишите в комментариях, и сделаю и для него!
Также пишите, если у вас есть какие-то задачи или нужен какой-то другой алгоритм ограничения случайности. Спасибо за чтение!
В разделе «Курс начальных знаний» я добавил урок « Случайные действия в играх на RPG Makerʼе » с объяснением, как создавать простые случайные действия в RPG Makerʼе. Сейчас я опишу, какие проблемы могут возникнуть при использовании случайных действий и как их решить.
Эта статья для тех, кто уже умеет работать с переменными, устанавливать и вызывать скрипты. (Знание программирования не нужно.) Если вы ещё не умеете этого, возможно, вам стоит сначала почитать другие уроки на нашем сайте. Если что-то непонятно, задавайте вопросы, с радостью отвечу!
Случайность слишком случайная
Случайные числа в RPG Makerʼе создаются по алгоритму, который выдаёт все числа с равной вероятностью. Но это не всегда то, что нам нужно.
Случайные события по-настоящему случайны. Кто-то купит один лотерейный билет и сразу выиграет, а кто-то покупает их всю жизнь и ничего не выигрывает. В играх так делать нельзя: если в игре одни игроки всегда побеждают, а другие всегда проигрывают, и это не зависит от них, то такая игра будет неинтересной.
Поэтому нужны способы ограничить случайность. О некоторых я и напишу дальше.
Перетасовка небольшого количества чисел
Один способ, как сделать игру случайной, но не слишком случайной, можно подглядеть в карточных играх. В карточных играх есть ограниченный набор карт, который мы просто перетасовываем. Но карты в колоде всё равно те же самые. Никто не может получить шесть козырных тузов, потому что козырный туз в колоде только один. Это обеспечивает некоторый баланс.
В RPG Makerʼе такая случайность не встроена, но в него встроена возможность использования скриптов, которая позволяет добавить любую недостающую функцию.
Чтобы перетасовать небольшое количество чисел в RPG Makerʼах VX Ace, XP и VX можно использовать команду вызова скрипта с вот таким кодом:
Code:
[1, 2, 3, 4, 5].
shuffle.each_with_index { |x, i|
$game_variables[101+i] = x
}
В RPG Makerʼе MV можно использовать такой код:
Code:
[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 будет выглядеть так:
Code:
N=99
[*0..N].
shuffle.each_with_index { |x, i|
$game_variables[200+i] = x
}
Код для MV будет выглядеть так:
Code:
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, создайте новый скрипт с таким содержанием:
Code:
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 и подключите его как плагин:
Code:
/**
* Случайно распределяет сумму 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]);
}
}
После этого в том месте кода, где вы хотите разбить сумму случайным образом, вызовите такой код (заменив то, что написано по-русски):
Code:
randomlySplitSum(сумма, число_переменных, номер_первой_переменной)
Например:
Code:
randomlySplitSum(1000, 10, 30)
Этот код запишет в переменные 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 десять чисел, причём их сумма будет равна 1000.
Пример
Я приготовил пример всего того, что я тут описал, для VX Ace: Randomness_demo.zip (1,3 Мб).
Если вам нужны примеры для какого-то другого движка, пожалуйста, напишите в комментариях, и сделаю и для него!
Также пишите, если у вас есть какие-то задачи или нужен какой-то другой алгоритм ограничения случайности. Спасибо за чтение!
Последнее редактирование: 8 года 2 мес. назад пользователем Dmy. Причина: исправлены ошибки в коде для MV
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
8 года 4 мес. назад - 8 года 4 мес. назад #101254
от Amphilohiy
Я верю, что иногда компьютер сбоит, и он выдает неожиданные результаты, но остальные 100% случаев это чья-то криворукость.
Amphilohiy ответил в теме Как улучшить случайность в RPG Makerʼе
Я уже давненько приглядываюсь к твоей статье, и раз уж настроение у меня подбитое то и к тебе я тоже прикапаюсь. В основном про разбиение суммы.
Я тут прогнал пару тестов и построил гистограмму. Вот код:
А тут сама гистограмма
Жадный алгоритм не сохраняет сумму, просто служит примером. [strike]Подобные ямы наблюдаются почти во всех прогонах в количестве 1-2 ям (для сундуков не страшно, но знать неплохо)[/strike] Ямы в начале в конце в целом понятны, хех (забыл отсортировать хеш). При этом жадина - распределение равномерное, как и результат твоего разбиения суммы. Насчет последнего - это просто можно было упомянуть. Нормальное распределение бы держалось середины с более редкими "кукишами" или "джекпотами". Но дело же еще в том, что разбитая сумма включает в себя нули и малые/большие числа, то бишь пола у такой функции нет.
Так же дам по теме ссыль на вики доты про "гладкий" псевдорандом.
На сим откланяюсь.
Я тут прогнал пару тестов и построил гистограмму. Вот код:
ВНИМАНИЕ: Спойлер!
Code:
$game_variables = []
SUM = 50000
PARTS = 10000
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
def greedy(numberOfParts, tops)
Array.new(numberOfParts) {rand(tops + 1)}
end
def to_gist(array)
array.reduce({}) do |hash, val|
hash[val] ||= 0
hash[val] += 1
hash
end
end
randomlySplitSum(SUM, PARTS, 0)
post = to_gist($game_variables)
greedy = to_gist(greedy(PARTS, $game_variables.max))
require 'gruff'
g = Gruff::Line.new
g.title = 'rng'
g.labels = post.keys.map{ |v| [v, v] }.to_h
g.data :post, Hash[post.sort].values
g.data :greedy, Hash[greedy.sort].values
g.write('rng.png')
А тут сама гистограмма
Жадный алгоритм не сохраняет сумму, просто служит примером. [strike]Подобные ямы наблюдаются почти во всех прогонах в количестве 1-2 ям (для сундуков не страшно, но знать неплохо)[/strike] Ямы в начале в конце в целом понятны, хех (забыл отсортировать хеш). При этом жадина - распределение равномерное, как и результат твоего разбиения суммы. Насчет последнего - это просто можно было упомянуть. Нормальное распределение бы держалось середины с более редкими "кукишами" или "джекпотами". Но дело же еще в том, что разбитая сумма включает в себя нули и малые/большие числа, то бишь пола у такой функции нет.
Так же дам по теме ссыль на вики доты про "гладкий" псевдорандом.
На сим откланяюсь.
Я верю, что иногда компьютер сбоит, и он выдает неожиданные результаты, но остальные 100% случаев это чья-то криворукость.
Последнее редактирование: 8 года 4 мес. назад пользователем Amphilohiy.
Спасибо сказали: Dmy
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
Время создания страницы: 0.095 секунд
