
Сборка для Windows: atrium-testbuild3-win32.zip (1.18 МБ).
Сборка для 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 и выше. В ближайшем будущем ожидается первый релиз проекта.
1. Лучшая программа — это та, которая не была написана.
2. Простота — мать надежности.
3. Сложное должно быть простым.
4. Обычный программист думает: «Как сделать так, чтобы оно работало?»
Хакер думает: «Как сделать так, чтобы оно не сломалось?»
5. Оптимизация — это зло.
6. Если программа падает, в ней есть ошибка.
Если программа не падает, в ней все равно есть ошибка.
Просто она еще себя не проявила.
7. Защита от дурака важнее защиты от недоброжелателя.
8. Хороший код не нуждается в комментариях.
9. Красивое решение — правильное решение.
10. Улучшить порой сложнее, чем переписать заново.
В архиве — исходники и сборки для Win32 и Linux x86:
polyshaper-all-platforms.zip (1.16 МБ)
Внимание! Пример писался достаточно давно — исходный код, скорее всего, не скомпилируется современными версиями DMD без дополнительных «танцев с бубном».
Не писал уже целый месяц, приношу за это извинения читателям этого блога =) Месяц ушел на создание каркаса физического движка для Atrium. Для решения контактов используется метод Sequential Impulses, поддерживается трение. На данный момент реализованы два типа геометрических объектов — сфера и бесконечная плоскость. Интегрирование пока производится методом Эйлера, планируется поддержка метода Рунге-Кутты.
В представленной демке симулируется система из 6 шаров и плоскости. Красным шаром можно управлять с клавиатуры (клавиши-стрелки). Зеленый шар имеет повышенную массу, большой шар — пониженную.
Сборка для Linux:
physics-testbuild1-linux-glibc28-x86.tar.bz2
«Честные» динамические тени в аркадных 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 — надеюсь, со временем этот вопрос устаканится.