Журнал “FPS” №26

Вышел 26 номер электронного PDF-журнала “FPS”, посвященного разработке игр, программированию, компьютерной графике и звуку.

Читайте в этом номере:

> Tube Open Movie. Интервью с Бассамом Курдали
> Обзор дополнений Blender, выпуск 5
> GIMP: ломо-эффект как в Instagram
> Физический движок своими руками, часть III
> Making-of: логическая мини-игра Arrow
> Генерация случайных уровней
> Осваиваемся в SDL2
> Пишем плагин для DeleD на D
> Как я стал D-шником или Путь художника в IT
> Игровые новости из мира СПО и Linux
> “Корпорация зла”. Почему у Microsoft нет будущего

Номер доступен для онлайн-чтения и загрузки на сервисе Issuu.com, Документах Google и Dropbox.

Последние новости по проекту вы можете узнать в публичной странице журнала в социальной сети Google+: http://gplus.to/fpsmag. Добавляйте нас в круги, оставляйте свои комментарии и отписывайтесь в нашем сообществе.

Архив номеров журнала здесь.

Случайная выборка с учетом веса

Один из распространенных приемов в игровой логике – использование элемента случайности. Он используется, например, при машинной генерации уровней, лабиринтов, или когда на локации появляются случайные враги или бонусы. При этом зачастую требуется выбрать случайный объект из какого-либо списка с учетом того, что некоторые из них имеют большую вероятность выбора, чем другие – то есть, имеют больший “вес”.

Я написал особую реализацию алгоритма такой выборки – она работает не с обычными массивами, а с перечислениями (enum). В шаблон функции передаются два перечисления – самих элементов и их весов. Этот пример иллюстрирует также богатые возможности метапрограммирования, CTFE и интроспекции в D.

import std.stdio;
import std.traits;
import std.random;
import std.algorithm;

T weightedRandomEnum(T, W)()
if (isNumeric!W &&
is(T == enum) && is(W == enum) &&
EnumMembers!T.length == EnumMembers!W.length)
{
enum members = [EnumMembers!T];
enum weights = [EnumMembers!W];
enum weightsSum = reduce!("a + b")([EnumMembers!W]);

auto randomNumber = uniform(0, weightsSum);

foreach(i, weight; weights)
{
if (randomNumber < weight)
return members[i];
else
randomNumber -= weight;
}

assert(0, "Should never get here");
}

enum Color
{
Red, Yellow, Green, Blue
}

enum Weights
{
Red = 100,
Yellow = 20,
Green = 20,
Blue = 5
}

void main()
{
foreach(i; 0..10)
writeln(weightedRandomEnum!(Color, Weights));
}