Изменения доступны в ревизии r22 и выше.
Сохранение PNG в dlib
Изменения доступны в ревизии r22 и выше.
Свершилось! Результат моей работы за последние месяцы — основа будущего шутера от первого лица с физическими головоломками — доступен на GitHub. Добавлена заготовка игрового уровня, а также действующий гравитационный излучатель, при помощи которого игрок может передвигать динамические объекты (из-за ограничений в нынешнем физическом движке, таковые объекты представлены только сферами, но в будущем не исключена поддержка других типов тел). Исходники собираются DMD 2.060 и выше. Под Linux рекомендуется использовать LDC.
Сборка для Windows: atrium-testbuild3-win32.zip (1.18 МБ).
Один из распространенных приемов в игровой логике – использование элемента случайности. Он используется, например, при машинной генерации уровней, лабиринтов, или когда на локации появляются случайные враги или бонусы. При этом зачастую требуется выбрать случайный объект из какого-либо списка с учетом того, что некоторые из них имеют большую вероятность выбора, чем другие – то есть, имеют больший “вес”.
Я написал особую реализацию алгоритма такой выборки – она работает не с обычными массивами, а с перечислениями (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));
}
Иллюстрация FFT-свертки: быстрое синтетическое боке (оптическое размытие):
Изменения доступны в ревизии r21 и выше. В ближайшем будущем ожидается первый релиз проекта.
physics-src-alpha0.zip (0.95 Мб).
Пример рисования мышью многоугольников, которые сразу же начинают «жить» в физическом мире. В качестве физического движка используется ChipmunkD — прямой порт Chipmunk на D. Демка может быть использована в качестве основы для physics-based 2D-игры. Единственное ограничение — поддерживаются только выпуклые многоугольники, неконвексная геометрия просто отсеивается и не тесселируется до простых форм.
В архиве — исходники и сборки для Win32 и Linux x86:
polyshaper-all-platforms.zip (1.16 МБ)
Внимание! Пример писался достаточно давно — исходный код, скорее всего, не скомпилируется современными версиями DMD без дополнительных «танцев с бубном».
«Честные» динамические тени в аркадных 3D-играх не всегда бывают уместны. Как правило, разработчики ограничиваются статическими предрассчитанными тенями от неподвижных объектов и простым темным кружочком на земле под персонажем – дешево и сердито =) Я решил дополнить этот нехитрый метод одной простой, но важной деталью: изменение яркости персонажа в зависимости от его местоположения – в тени или на свету.
Цвет для яркости будет считываться из карты освещения, в которой «запечены» все статические тени на карте.
Допустим, у вас есть некий блок кода, в котором вы находите точку на поверхности полигона под ногами персонажа:
// Проверяем факт пересечения
IntrStatus istatus = character.downRay.intersectTriangle(tri);
if (istatus.hit)
{
// Извлекаем точку пересечения
Vector3f ipt = istatus.intersectionPoint;
if (ipt.y > currentFloorHeight)
{
currentFloorHeight = ipt.y;
// Берем материал полигона
Material mat = materialByIndex[tri.matIndex];
// Если нет карты освещения (текстура 1), то ничего не делаем
if (mat.textures[1])
{
// Берем изображение карты освещения
Image lightmap = imageByIndex[mat.textures[1].imgIndex];
// Находим текстурные координаты точки пересечения
Vector2f tc = triObjSpaceToTexSpace(tri.vertices, tri.texCoords2, ipt);
// Конвертируем текстурные координаты в дискретные
uint imgX = cast(uint)(tc.x * lightmap.width - 0.5f);
uint imgY = cast(uint)(tc.y * lightmap.height - 0.5f);
// Считываем цвет пикселя c карты освещения
Color lumel = lightmap[imgX, imgY];
// Применяем полученный цвет к материалу персонажа
chMaterial.ambientColor = lumel;
chMaterial.diffuseColor = lumel;
chMaterial.specularColor = lumel;
}
}
}
Осталось определить функцию triObjSpaceToTexSpace. Она будет использовать барицентрические координаты:
Vector2f triObjSpaceToTexSpace(
Vector3f[3] vertices,
Vector2f[3] texCoords,
Vector3f point)
{
Vector3f v0 = vertices[2] - vertices[0];
Vector3f v1 = vertices[1] - vertices[0];
Vector3f v2 = point - vertices[0];
float dot00 = dot(v0, v0);
float dot01 = dot(v0, v1);
float dot02 = dot(v0, v2);
float dot11 = dot(v1, v1);
float dot12 = dot(v1, v2);
float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
Vector2f t2 = texCoords[1] - texCoords[0];
Vector2f t1 = texCoords[2] - texCoords[0];
return texCoords[0] + t1 * u + t2 * v;
}
Решив проверить LDC на практике, я только что собрал им Atrium. Результат очень обрадовал, при компиляции в релизном режиме и с уровнем оптимизаций -O3, LDC выдал весьма шустрый код: ~100 FPS против ~80 у DMD 2.060! При этом я всего один раз столкнулся с необходимостью поправить исходники — при использовании ассоциативного массива указателей.
Как вывод: LDC вполне созрел для использовании в качестве основного компилятора D под Linux — во всяком случае, для работы с OpenGL и графикой реального времени. К сожалению, я не в курсе, как у него обстоят дела c поддержкой Windows — надеюсь, со временем этот вопрос устаканится.
> Blender: обзор дополнений (выпуск 3)
> Tears of Steel: роботы тоже плачут…
> Эффект «старинного фото» в GIMP
> Журнал GIMP Magazine
> Язык D: новости
> Семь мифов о D
> Сборщик мусора — враг или друг?
> Юникод в OpenGL. Раз и навсегда
> Почему я выбираю Linux?
> Патентные войны
Номер доступен для онлайн-чтения и загрузки на сервисе Issuu.com и Документах Google. Последние новости по проекту вы можете узнать в публичной странице журнала в социальной сети Google+.