Pull to refresh

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

Reading time3 min
Views3.9K


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

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

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



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

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

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



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

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 искомые координаты

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

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

Запустив лучи во все стороны с нужным шагом получим примерно такую картину:



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



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

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



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



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



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



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



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

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

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

Часть 1, Часть 3
Tags:
Hubs:
+15
Comments16

Articles

Change theme settings