Блог ☯

03.04.2017

Основы создания игр - рандом, рандомный лут и сундуки

Сегодня мы с вами разберём механизмы лута и рандома в играх. Продолжаем курс - основы создания игр.

Как работает рандом (случайная генерация чисел) в играх (и в программах вообще) и как сделать такие нужные для RPG вещи как открытие сундуков со случайными вещами.

Основы создания игр - рандом, рандомный лут и сундуки

Что такое лут и рандом


Начнём немного издалека. Loot и random, понятное дело, английские слова.

Лут (Loot) - это награда, можно перевести как - трофеи. Обычно выпадает из мобов, даётся за прохождение уровня или за выполнение квеста.

Рандом (Random) - все мы знаем что такое, это случайность. Рандомные числа, рандомные события и т.д. Эти слова уже давно в лексиконе многих.


Существует-ли случайность?



Теперь давайте сделаем еще одно отступление касательно вероятности и рандома вообще. Ранее считалось, что случайности вообще не существует. Просто мы не понимаем как что-то происходит и в следствии этого не можем объяснить почему, условно говоря, выпало решко или орёл.

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

Тут на самом деле очень серьезно придётся уйти в философию, если мы начнём разбирать этот вопрос, но, что интересно. Хотя с 19-го века теория вероятности доказала, что случайности таки случайны, в играх и программировании все программы, которые отвечают за генерацию случайных чисел, очень даже подчиняются вполне определённым законам.

Запустите игру в game maker и пропишите там генерацию случайного числа, от 0 до 10. Потом запустите её еще раз, у вас выпадет то-же число если все условия абсолютно равны. Забавно как виртуальный мир абсолютно предсказуем, а все элементы непредсказуемости очень даже можно разобрать и понять что будет дальше.

Вы вероятно знаете или слышали про такое понятие как game seed - игровое зерно. Слышали? По любому. Это есть даже в Minecraft. Зачем оно нужно? А в том-то и соль, что вся генерация мира будет привязана к конкретному зерну, и если знать лишь одно это число - зерно, то вы можете полностью воссоздать весь автосгенерированный мир один в один!

Разве не странно? Сгенерировался миллион разных блоков, а если забивать зерно = 5, всегда мир будет тем-же самым. Потому что дело не в генерации каждого конкретного блока, она не случайна, а дело только в одном числе - общей генерации мира. Короче, конкретно объяснить сложно, но общий принцип я думал я донёс.

Я кстати реализовывал этот механизм очень давно в своей игре Lands, добавлялось зерно, так-как без зерна все автосгенерированные миры выходили типовыми. Про всё это я наверное расскажу больше в видео и статье про автогенерацию мира.


Псевдорандом



Давайте еще проще. Любое случайное число, которое выдаёт программа random(10) - нефига не случайно. Есть очень чёткий алгоритм его генерации. А это значит, что зная алгоритм, можно выдавать всегда один результат. Если вам интересны все эти моменты, проследуйте в википидию. Например - случайная величина.

Давайте вспомним такое понятие из Доты как псевдорандом. Это значит - создание видимости рандома. Допустим, шанс крита = 10%. Но мы знаем, что теоретически у нас может быть подряд 10, 30 или даже 10000 ударов без крита. Есть вероятность что так будет.

Общая вероятность падает с количеством попыток и падает сильно, однако чисто теоретически это возможно. Таким образом рандом, как вы можете знать и из World of Tanks - это странная и не очень честная штука. Не просто так придумали Корейский и Белорусский рандом.

Для преодоления этого в некоторых играх придумывают некий псевдорандом. Это когда например при шансе крита 10%, при невыпадении крита, шанс на его выпадение повышается. Кажется бредом, да и кстати это нечестно, но с другой стороны, а разве честно если из 100 атак крит в 10% так и не выпадет? А такое может быть.

Хорошо, это всё была просто некая небольшая теоретическая база, мозги размять, как говориться. Теперь давайте приступим к конкретному коду и посмотрим как сделать сундуки с рандомным лутом.


Как сделать сундук с рандомным лутом в игре (game maker studio)



Опять-же, в качестве базы я буду использовать игру Lonely Dude. Сделал я вот что:

Основы создания игр - рандом, рандомный лут и сундуки

Новые сундучки - слева

Полоска хипов там не обязательна, она просто показывает когда он откроется. По сути дела когда герой рядом (или его касается), герой бьёт сундук и отнимает хипы. Хипы заканчиваются - сундук открывается.

Забыли как делать полоску хипов? Вам сюда:


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

Основы создания игр - рандом, рандомный лут и сундуки

Всё прописал в новом объекте - сундук

CREATE

open = 300
Просто локальная переменная, может быть любая, хоть hp. В данном случае, если отнимать 1 в тик, то сундук откроется через 10 секунд.

DESTROY

Тут я на самом деле сделал без уничтожения, хотя выпадение предметов можно было-бы запихнуть и вот сюда.

STEP

Вот тут у нас всё и лежит.

Основы создания игр - рандом, рандомный лут и сундуки


Вот код сундука со случайным лутом:
if distance_to_object(o_hero)<5 then open-=1
if open=0
{
effect_create_above(ef_ring,x,y,1,c_red)
loot=irandom(4)
if loot=0 instance_create(x,y,o_gold)
if loot=1 instance_create(x,y,o_grenade)
if loot=2 instance_create(x,y,o_shotgun)
if loot=3 instance_create(x,y,o_ammo_4_1)
if loot=4 instance_create(x,y,o_hp_1)

instance_destroy()
}
Вообще, всё просто. Тут еще есть один стандартный эффект game maker, ну а так...
if distance_to_object(o_hero)<5 then open-=1 
Это один из способов отнимать у сундука "жизни", просто если рядом с ним есть герой.

Способ редко где используется, обычно делаю коллизию и пишут всё это там, можете сделать как угодно. Просто при коллизии нужно зажимать кнопку (идти в сторону сундука), а вот так он просто откроется через 10 секунд если мы рядом и всё.

Основное я выделали жирным, всё что нам нужно это функция:
irandom(n)
Это возьмёт число (n) в случайном диапозоне. Напишем там 10, возьмёт от 0 до 10, случайное. Не забывайте что берёт тут от 0.

Если просто напишем random - то там будут в том числе и не округлённые числа, не целые. Часто этого нам не надо.

Раньше я писал round(random(n)) - чтобы как раз округлять, но нет нужны так извращаться.

Достаточно использоваться irandom(n)

Далее просто создаёт приз, предмет или что хотите при каждом варианте.

Тут 5 вариантов, шанс выпадения каждого 20%.

Еще один вопрос, а как сделать например шанс выпадения лута допустим 5%, при том что может выпасть только 1 тип лута. Например - супер меч или что-то еще крутое.

Это у меня записано при смерти врагов, записано вот так:

Основы создания игр - рандом, рандомный лут и сундуки

 Вот тут уже чуток по другому:
if random(100)>99 then instance_create(x,y,o_gold) // 1%
if random(100)>95 then instance_create(x,y,o_ammo_1) // 5%
Опять-же, "then" тут писать не обязательно. Вот как-то так я раньше делал все рандомы.

Тут бросаем кубик от 0 до 100, при выпадении числа больше 99 (95), даже включая не целые, вы создаём наш лут. И это всё написано при смерти врага.

В видео я рассказываю еще некоторые фишки, можете посмотреть (11 минут):