Доброго всем!
Я тут пытаюсь разобраться с освещением в 2Д (примитивным, очень, очень примитивным), вроде всё просто, но тут немного залип, если кто поможет - буду крайне признателен.
Суть проблемы в следующем:
Имеется массив 10х10 заполненный точками, где-то в центре стоит "лампочка" (@):
.......... .......... .......... .......... .......... .....@.... .......... .......... .......... ..........
От этой лампочки по окружности исходит "свет" ("*"):
.......... .......... .....*.... ...*****.. ...*****.. ..***@***. ...*****.. ...*****.. .....*.... ..........
"Алгоритм" тащем-то простой:
(x - x0)^2 + (y - y0)^2 == radius^2 - верхушки "окружности"
(x - x0)^2 + (y - y0)^2 < radius^2 - точки внутри неё
Надо каким-то образом проверить доступность/видимость точки внутри "окружности" из начальной точки в массиве, т.е. что бы между точкой внутри окружности и точкой map[y0][x0] (лампочки) не было бы "стенок" или непроницаемых для света объектов. И если для верхушек "окружности" - это в общем-то не сложно, то вот для остальных точек - у меня что-то никаких идей не возникло.
Подскажите как сделать или хоть в какую сторону копать, буду очень благодарен.
ну проводишь линию и смотришь чтоб на пути не было объектов
А еще можно готовые алгоритмы отсюда
http://www.roguebasin.com/index.php?title=Field_of_Vision
взять. (ну это если то что в #1 не устраивает, какие-нибудь артефакты или ассиметричности).
TarasB
>ну проводишь линию и смотришь чтоб на пути не было объектов
Я это как понимаю: проверить диапазон точек находящихся между точкой А и точкой Б и если в этом диапазоне есть препятствие, точка А не рисуется. Это работает на прямых и с диагоналями, но в "окружности" есть точки, которые не находятся на диагонали и прямой от начальной точки. И как вот проверить эти точки, ведь получается что между ними и начальной уже будет от двух и более точек, эм, в общем, я где-то тут теряюсь в своих рассуждениях.
kipar
>А еще можно готовые алгоритмы отсюда
Спасибо - посмотрю.
Grinvich
линия между точками в 2д проводится так:
1.......... .XXX....... ....XXX.... .......XXX. ..........2
см. Брезенхам (ну или просто сделай цикл с округлением).
kipar
Спасибо ещё раз, кажется теперь понятно!
я определял область видимости для юнитов, проходя все тайлы (клетки) по спирали от ближних к дальним. каждую клетку проверяем - если она не попадает ни в один из перекрытых секторов - значит она видима. если это препятствие - добавляем соотв сектор в массив перекрытых секторов.
код на сишарпе:
public List<Tile> GetVisiblePlots(Tile from, int view)
{
var ring = new HashSet<Tile>(from.Neightbours); //first circle plots
HashSet<Tile> newRing = null; //next circle plots
var visiblePlots = new List<Tile>() { from }; //this will be returned in the end
var processedPlots = new HashSet<Tile>(ring);
processedPlots.Add(from);
var hiddenView = new List<Sector>();
var allIsHidden = false;
var height = from.TerrainType.Height;
var viewRadius = (int)(view + height);
for (int r = 1; r <= viewRadius; r++)
{
newRing = new HashSet<Tile>();
foreach (var plot in ring)
{
processedPlots.Add(plot);
var a = new Angle(from, plot); //direction to the plot
if (!hiddenView.Any(v => v.Includes(a))
{
visiblePlots.Add(plot);
}
if (!allIsHidden && plot.TerrainType.Height > (int)height) //this is an obstacle, hide some view
{
var w = Math.Atan(1 / (double)r); //an angular width of the obstacle
var sect = new Sector(a.Rad - w / 2, a.Rad + w / 2);
for (int i = hiddenView.Count - 1; i >= 0; i--)
{
var s = hiddenView[i];
var comb = sect.Combine(s); //try to combine sectors. if they dont overlap null is returned
if (comb == Sector.Full)
{
allIsHidden = true;
break;
}
if (comb != null)
{
sect = comb;
hiddenView.RemoveAt(i); //remove the consumed sector
}
}
hiddenView.Add(sect);
}
//add neightbours to a new ring
foreach (var p in plot.Neightbours)
{
if (!processedPlots.Contains(p))
{
newRing.Add(p);
}
}
}
ring = newRing;
}
return visiblePlots;
}Сделать свой z-буфер =) Только одномерный. Вот моя реализация, успешно работает http://habrahabr.ru/post/204782/
Там в конце есть ссылка на исходники, можно конкретные вычисления глянуть.
я как-то делал подобное, по результатам понял, что вариант с рисованием тени от каждого объекта или каждого пикселя не очень хорош для простого освещения - медленно и геморно, особенно, если источников несколько. гораздо проще и быстрее такой вариант:
Допустим x,y координаты лампочки.
x0,y0 координаты объекта.
Тогда (псевдокод):
Если корень((x-x0)^2 + (y-y0)^2) > radius то объект вне источника света.
Viaceslav(C)
( (x-x0)^2 + (y-y0)^2 ) > radius^2
ну что же ты
clc
> Viaceslav(C)
> ( (x-x0)^2 + (y-y0)^2 ) > radius^2
> ну что же ты
>
Неправильно.
Viaceslav(C)
Суть в том что даже если точка в радиусе, там еще непрозрачные стены могут быть.
Тема в архиве.