В поисках перспективных теней для roguelike

в 21:18, , рубрики: 2d графика, Pascal, raycasting, roguelike, графический дизайн, Дизайн игр, тени

В поисках перспективных теней для roguelike - 1

Уважаемые Хабровчане, представляю вашему вниманию продолжение изысканий на тему поиска подходящих теней для 2D рогалика.

Данный пост является сиквелом публикации, своеобразной работой над ошибками и дальнейшее развитие идеи.

В своих комментариях, уважаемые критики, совершенно справедливо отметили, что в замкнутых пространствах тени получились угловатыми, и несколько не естественными.
Было предложено несколько вариантов решения, мне понравилось предложение использовать ray casting для расчёта тени.

В поисках перспективных теней для roguelike - 2

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

В данной работе по рейкастингом понимается метод построения изображения посредством бросания лучей от наблюдателя в пространство до пересечения с препятствием (границами экрана) и подсвечиванием места их столкновения.

Здесь мы будем использовать упрощённую разновидность рейкастинга, основанную на пересечении лучом тайловой сетки. Данный метод широко использовался в псевдотрёхмерных играх прошлого (например Wolfenstein_3D, почтение тем кто в теме), мы его адаптируем для двумерного пространства.

В поисках перспективных теней для roguelike - 3

Алгоритм, достаточно прост как для понимания, так и воплощения. Приведу собственную его реализацию:

Pascal

// i,j - координаты тайла, а - угол
// X,Y - начальное смещение координат
// r - максимальный радиус для расчёта

// Инициализация направления
if cos(a)<0 then
  begin di :=-1; ddi:= 0; end
else
  begin di := 1; ddi:= 1; end;

if sin(a)<0 then
  begin dj :=-1; ddj:= 0; end
else
  begin dj := 1; ddj:= 1; end;

// Предварительный расчёт первой точки по Х и Y
x1 := (i+ddi) * tile_size;
y1 := y+ (x1-x) * tan(a);
Dx := len(x,y,x1,y1);

y1 := (j+ddj) * tile_size;
x1 := x+ (y1-y) * cotan(a);
Dy := len(x,y,x1,y1);

sum_lenX := 0;
sum_lenY := 0;

// Размер тайла по X и Y под углом a
rX := abs(tile_size / cos(a));
rY := abs(tile_size / sin(a));

// выбираем точки пересечения
repeat
  if sum_lenX+DX < sum_lenY+DY then
    begin  
      x1 := (i+ddi) * tile_size;
      y1 := y+ (x1-x) * tan(a);
      i  := i+di;
      // Проверяем тайл на наличие стены или границ экрана
      key  := is_wall(i,j); 
      sum_lenX := sum_lenX + DX;
      if DX<>rX then DX:=rX;
      // Если радиус больше нужного обрываем цикл
      if r<sum_lenX then Break;
    end
    else
    begin
      y1 := (j+ddj) * tile_size;
      x1 := x+ (y1-y) * cotan(a);
      j  := j+dj;
      // Проверяем тайл на наличие стены или границ экрана
      key  := is_wall(i,j);
      sum_lenY := sum_lenY + DY;
      if DY<>rY then DY:=rY;
      // Если радиус больше нужного обрываем цикл
      if r<sum_lenY then Break;
    end; 
until (Пока не найдём стену или границу экрана); 

// x1,y1 искомые координаты

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

В своей реализации я вынес всю тригонометрию и деления в отдельную таблицу для каждого угла, что значительно ускорило алгоритм.
Запустив лучи во все стороны с нужным шагом получим примерно такую картину:

В поисках перспективных теней для roguelike - 4

Увеличив количество лучей до нескольких тысяч и получим искомый многогранник области видимости. Возможно, конечно, бросать лучи и для каждого пикселя изображения, как на 3D ускорителях, но без видеокарты тут уже не обойтись.

В поисках перспективных теней для roguelike - 5

Дальше начинается работа со слоями.

Область видимости. Здесь и далее лучи немного проходят в глубь объектов. Такая игровая условность создаёт уникальный антураж, свойственный 2D Играм.

В поисках перспективных теней для roguelike - 6

Генерация карты освещения. Статичные источники света генерируем заранее и кешируем для улучшения быстродействия, динамические накладываем в процессе вывода на экран.

В поисках перспективных теней для roguelike - 7

Сведение всего вместе.
Не хватает только жутких монстров и сокровищ… много сокровищ.

В поисках перспективных теней для roguelike - 8

Стены с изменяемой кривизной проникновения света мне не зашли, но возможно это на любителя.

В поисках перспективных теней для roguelike - 9

В процессе создания прототипа я перепробовал множество вариаций модели, некоторые из них лучше подходят для хоррора:

В поисках перспективных теней для roguelike - 10

Особенно понравился эффект множественного переотражения лучей от стен, но даже его наивная реализация так тормозила, что я оставил её на будущее, когда подружусь с видеокартой.

Спасибо за внимание.

Ссылка поиграться (exe для виндовс)

Автор: rebuilder

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js