BeaRLibFOV - поле зрения

Форум библиотеки BeaRLib

Модератор: Apromix

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BeaRLibFOV

Сообщение Apromix » 19 окт 2011, 15:40

А может для LOS отдельную либу предусмотреть :lol: ?

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BeaRLibFOV

Сообщение Apromix » 11 янв 2012, 11:04

Напишите кто-нибудь рабочую демку на Delphi.

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BeaRLibFOV

Сообщение Apromix » 25 янв 2012, 17:59

Ура! Cfyz прислал мне исходники демки на паскале :D
Вложения
bearlibfov-pascal_demo.7z
(120.62 КБ) 147 скачиваний

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BeaRLibFOV

Сообщение Apromix » 25 янв 2012, 18:01

Также Влад Фомин прислал мне свою реализацию демки на Delphi с использованием тайлов и GDI :D
Вложения
PNG_GDIfin_FOVDLL.RAR
(275.84 КБ) 149 скачиваний

Аватара пользователя
Shirson
Сообщения: 427
Зарегистрирован: 03 окт 2011, 13:52

Re: BeaRLibFOV

Сообщение Shirson » 27 янв 2012, 14:42

А как реализация LOS связана с тайтлами и тем более с GDI :shock:

UPD: А, речь про реализацию демки. Сорри :)

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение Apromix » 11 янв 2013, 12:01

Прямой код из паскалевского примера:
Скрытый текст: ПОКАЗАТЬ

Код: Выделить всё

program demo;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  bearlibfov in 'bearlibfov.pas';

type
  pstring = ^string;


const
  SCREEN_WIDTH = 80;
  SCREEN_HEIGHT = 25;

function Cell(map: FOV_map; x: integer; y: integer): pFOV_Cell;
begin
  Result := map.Cells + (y * map.Width + x) * SizeOf(FOV_Cell);
end;

begin
  { TODO -oUser -cConsole Main : Insert code here }
end.
...в Delphi показывает ошибку "Operator not applicable to this operand type" внутри Cell. Как заставить код работать?

Аватара пользователя
Cfyz
Сообщения: 771
Зарегистрирован: 30 ноя 2006, 10:03
Откуда: Санкт-Петербург
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение Cfyz » 11 янв 2013, 16:18

Apromix писал(а):Прямой код из паскалевского примера <...> в Delphi показывает ошибку "Operator not applicable to this operand type" внутри Cell
Если это вопрос ко мне, то, боюсь, вы не по адресу =) Я паскаль знаю на уровне сложения чисел в цикле. Пример набирался методом тыка в досовской версии freepascal. Что именно из того весьма размытого явления, именуемого паскалем, по-своему воспринимает Delphi -- это вопрос к людям, хорошо знающим предметную область. Sizeof возвращает какой-нибудь нехарактерный тип или указатели нельзя складывать с числами со знаком или еще чего в подобном духе. Попробуй это выражение разбить на наэлементарнейшие действия, можно будет хоть сузить область поиска.

Справедливости ради, в C/C++ не лучше. Кросскомпиляция в GCC и MSVC тоже та еще головная боль.
Пытается раскуклиться

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение Apromix » 11 янв 2013, 16:37

Эх, жаль :D А без каллбеков переписать либу нельзя? Чтоб еще проще было взаимодействие?

Аватара пользователя
Cfyz
Сообщения: 771
Зарегистрирован: 30 ноя 2006, 10:03
Откуда: Санкт-Петербург
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение Cfyz » 11 янв 2013, 16:49

Apromix писал(а):А без каллбеков переписать либу нельзя? Чтоб еще проще было взаимодействие?
Не коллбеков, а указателей, обратных вызовов и так там нет. Вообще можно, я уже подумал обойтись вообще функциями:
* сбросить все
* установить прозрачность ячейки (x, y)
* рассчитать видимость из точки (x, y)
* проверить видимость ячейки (x, y)
Отдав управление памятью полностью на совесть либы. Дешево и сердито.
Пытается раскуклиться

phomm
Сообщения: 40
Зарегистрирован: 13 сен 2012, 07:14
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение phomm » 11 янв 2013, 16:54

Дельфя малость построже к типизации чем фпц.
Я переписал вот так, соблюдая сие дело.

Код: Выделить всё

Cell := pfov_cell(Integer(map.Cells) + (y*map.Width+x)*SizeOf(FOV_Cell));
Честно говоря, сперва вообще не въехал как такое может быть, но закралось сомнение насчёт типа Cells, полез в хедер - и вправду - pointer )))
Мой-то хедер я писал более типизировано (см. демку из поста Апромикса выше) и у меня там такой фокус без арифметики на указателях работает, а просто доступом к индексам массива в структуре.

У меня кстати ещё такой вопрос - возможно ли добавление в перечисление для клетки флага изменения состояния клетки - т.е. если клетка в результате алгоритма изменила своё состояние - то флаг тру, а если нет - то фолс, в начале работы алгоритма этот флаг всем проставляется в фолс. Объясняю - это для оптимизации - ведь можно не рисовать вообще то , что не изменилось, а брать из предыдущего кадра или ещё как.
Хотя, не отрицаю, к сути дела ФОВ-расчета оно особо не относится и вполне обосновано может быть причиной для отказа ))

Аватара пользователя
Cfyz
Сообщения: 771
Зарегистрирован: 30 ноя 2006, 10:03
Откуда: Санкт-Петербург
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение Cfyz » 11 янв 2013, 17:19

phomm писал(а):возможно ли добавление в перечисление для клетки флага изменения состояния клетки - т.е. если клетка в результате алгоритма изменила своё состояние
Да возможно, почему бы и нет. Там этих флагов завались (может показаться, что всего байт, но из-за особенностей выравнивания памяти "зарезервировано" все равно четыре; недоглядел), одним больше, одним меньше.

Тем более, что в данном случае парадигма использования предполагает хранение реальной информации именно в этом массиве FOV_MAP. Вот если переделать на интерфейс без указателей (указатель на массив структур через C-style API -- мне тоже чем-то неуловимо не нравится), тогда да, там только суть, видно-не видно, а карта с какими угодно флагами хранится у пользователя либы как ему удобно.

Но без указателей будет много-много мелких вызовов функций и это надо еще на производительность протестировать прежде чем бросаться делать.
Пытается раскуклиться

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение Apromix » 11 янв 2013, 19:20

phomm писал(а):Cell := pfov_cell(Integer(map.Cells) + (y*map.Width+x)*SizeOf(FOV_Cell));
Спасибо, вроде работает :)
Cfyz писал(а):Вообще можно, я уже подумал обойтись вообще функциями. Отдав управление памятью полностью на совесть либы. Дешево и сердито.
А как будет со скоростью? Нынешний вариант на указателях очень шустр :)

Аватара пользователя
Cfyz
Сообщения: 771
Зарегистрирован: 30 ноя 2006, 10:03
Откуда: Санкт-Петербург
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение Cfyz » 06 июл 2013, 18:45

Два года назад в соседней теме kipar была высказана идея:
Скрытый текст: ПОКАЗАТЬ
Есть объект CellObject - любой видимый или участвующий в поиске пути объект. Т.е. и кусок пола и монстр и игрок.
Он обладает следующими свойствами:
- Прозрачность - 1 байт, от непрозрачного до пустого. (пока используем только один бит)
- Проходимость - 1 байт, от непроходимого до ровного пола (пока тоже используем один байт).
- 4 байта - глиф, т.е. рисуемая картинка. Рисование реализуется самой игрой или другой библиотекой, так что не конкретизируем его, просто Pointer\void*.
- 4 байта - маркер для поиска, который будет использоваться при поиске цели. Интерпретация тоже зависит от игры, например так:
0 - пустое место
1 - игрок или его союзник
2 - еда
3 - враг игрока
и т.д.
------------------------

Карта TMap - двумерный массив, в каждой клетке находится список этих объектов плюс дополнительная инфа, соответствующая им, типа флага видел ли игрок эту клетку, видна ли она сейчас.

Этот TMap используется и в генерации карты, и в FOV, и в PF, и в AI. И в рисовании карты.
Преимущества например такие:
- в простой игре клеток могут указывать на один и тот же CellObject, т.е. не нужно создавать 100*100 объектов с прозрачностью 0, проходимостью 0, картинкой "#", а достаточно чтобы все клетки со стенами ссылались на один экземпляр стены.
- а если понадобиться сделать разрушаемость стен, то вуаля - создаем 100*100 объектов стен и можем разрушать их по отдельности, изменяя их проходимость, прозрачность и картинку, при этом на алгоритмах поиска пути и прочем это не скажется.

Далее, монстры - тоже являются такими объектами. Потому что непрозрачные монстры это экзотика, а вот непроходимые - норма. Так что в поиске пути их надо учитывать. Соответственно для них можно в библиотеке сделать процедуры перемещения на одну клетку (которая будет удалять его из списка текущей клетки и добавлять в другую) и потому на долю программиста рогалика останется только создание этих самых объектов.

Рисование тоже частично автоматизируем - просто для каждой клетки в определенной области последовательно вызываем пользовательские процедуры рисования, передавая им картинки объектов. И игра нарисует сначала клетку пола, потом лежащее там барахло, потом стоящих там монстров, потом всякие облака тумана. Правда есть два ньюанса - во первых добавим к CellObject еще 4 байта, определяющие его порядок в отрисовке (в нашем пример для пола это будет 1, для предметов 2, для монстров 3. А могло быть наоборот, в зависимости от исп-мого графического движка).
И второй ньюанс - придумать механизм коллбеков. Т.е. как вызывать пользовательскую функцию рисования. Потому что вызов функции по адресу в C# опять-таки работать не будет. А привязываться к внутреннему механизму рисования как в libtcod имхо нехорошо.
В целом, интересная идея. Но предлагаемый вариант требует идеально точного повторения структуры памяти объекта-карты в каждой программе. Это неудобно:
1. Весьма низкоуровнево: должна быть возможность построить объект с именно таким расположением полей, их размером, паддингом и т. д. Полагаю, некоторые динамические и/или скриптовые языки могут вообще не иметь подобного инсрументария.
2. Жесткая привязка к однажды выбранной структуре. Любые последующие изменения, сколь угодно малые, потребуют колоссальных усилий.

Посему имею предложить свой вариант:

Код: Выделить всё

int map_alloc(int width, int height, const char* description);
void map_free(int map_id);
int map_copy(int map_id);
int map_assign(int dst_map_id, int src_map_id);
void map_clear(int map_id);
void map_clear_layer(int map_id, int layer);
void map_set(int map_id, int x, int y, int layer, int value);
void map_setf(int map_id, int x, int y, int layer, float value);
int map_get(int map_id, int x, int y, int layer);
float map_getf(int map_id, int x, int y, int layer);
int map_width(int map_id);
int map_height(int map_id);
Суть заключается в чем: карта хранится где-то там в библиотеке. Предположений о том как именно в общем случае делать не следует. Доступ к карте осуществляется посредством весьма обобщенного интерфейса.

map_alloc: создает объект-карту указанных размеров и структуры, возвращает ее id. Дальнейшая работа осуществляется по этому id. Структура карты описывается строкой, где перечисляются поля (или, в выдуманных мною терминах, слои). Например, map_alloc(80, 25, "flag, int, float"); создаст карту, где каждая клетка имеет одно битовое поле-флаг, одно целочисленное и одно с плавающей запятой.

map_get/map_set: Унифицированный доступ к полям. map_get(id, 10, 10, 0) вернет значение первого поля (в приведенном выше примере — флага) ячейки {10, 10} карты c идентификатором id. Аналогично, map_set(id, 10, 10, 1, 12345) установит значение второго поля той же ячейки. Функции set/get для дробных чисел отдельные, так как в отличие от bool/byte/short/int этот тип так просто к целочисленному не приводится =)


Как же это работает с другими библиотеками? Возьмем, к примеру, FOV:

Код: Выделить всё

int fov_calc(int map_id, int opacity_layer, int visibility_layer, int x, int y, int radius);
Глядите, этой функции для работы требуется только id карты, номер поля-слоя с информацией о прозрачности клеток (opacity_layer) и номер поля-слоя куда будет записан результат расчета. Актуальная же структура ячейки может быть любой. Возможно, другой библиотеке требуются еще пара полей помимо прозрачности. Возможно, opacity_layer — это только для FOV и поэтому это только flag. А может быть и так, что игра сама хранит в этой карте данные и opacity_layer это заодно и тип стены. FOV же на это наплевать, ему важно 0 или не 0 в этом поле.

На самом деле, тут еще много места для доработок и оптимизаций. Например, наверняка следует ввести типы данных между битом и четырехбайтным целым — байт и слово, со знаком и без. Может быть даже "цвет". Кроме того, скорость вызова функции на порядки (!) меньше, чем обращения к памяти напрямую. На самом деле все равно очень быстро (порядка 1Е-8 секунды на вызов на Core i3), но тем не менее. Это можно исправить путем получения из библиотеки адресов и смещений и написания врапперов под конкретный язык. Типа на С++ можно быстро, на lua не столь, но интерфейс тот же.

Но общую идею, я думаю, вы уже уловили.


К слову, в экспериментальном FOV есть еще один вызов:

Код: Выделить всё

typedef void (*fov_callback)(int map_id, int x, int y, void* opaque);
int fov_calc_cb(int map_id, int opacity_layer, int x, int y, int radius, fov_callback callback, void* opaque);
Он позволяет пройтись по FOV коллбеком. В этом случае, очевидно, номер visibility_layer функции не нужен: хочешь — сам выставляй флаг в коллбеке.


Пример обеих библиотек (BearLibMap, BearLibFOV) и демо, которое интенсивно с ними работает (DemoLighting), в собранном под Windows виде и в исходниках есть в архиве по следующей ссылке: BearLib_Cfyz_20130706.zip
Пытается раскуклиться

Аватара пользователя
Apromix
Мастер
Сообщения: 1197
Зарегистрирован: 04 июл 2011, 10:44
Откуда: Украина, Черновцы
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение Apromix » 29 май 2015, 06:15

Cfyz
А можно как-то эту Lights в отдельную библиотеку вынести? Ну или встроить в терминал?

Аватара пользователя
Cfyz
Сообщения: 771
Зарегистрирован: 30 ноя 2006, 10:03
Откуда: Санкт-Петербург
Контактная информация:

Re: BeaRLibFOV - поле зрения

Сообщение Cfyz » 29 май 2015, 15:24

Apromix, ты говоришь про расчет FOV? Да, его можно отделить от той весьма экспериментальной либы Map и вынести в отдельную маленькую, оставив только коллбеки.

Есть навязчивая идея сделать один универсальный FOV на все случаи жизни -- честно геометрический, рассматривающий карту как набор линий-стен, а не точек-клеток. Разом уйдут все проблемы типа симметричности, артефактов от колонн и черти чего там еще. Шестигранники опять же, у них с FOV/LOS все еще хуже. Есть неплохой шанс, что с применением ряда оптимизаций такой подход будет работать не намного медленнее классического (а в случае небольшого количества ровных комнат -- может еще и обгонит). Но в полный рост встает проблема как донести до библиотеки карту уровня -- коллбеки тут уже не помогут. Можно попытаться развить идею универсального же представления карты (на которой этот тред заглох на пару лет).

По поводу встроить в терминал, тут неочевидно. В минимальном виде (чисто расчет FOV по коллбекам) это такая штука, которая к терминалу не имеет отношения, ее логично отдельно иметь. Терминал и так вон начинает пухнуть от логгирования всякого и хранения опций во внешних файлах. Еще немного и пора будет делать выбор -- или делить на BearLibTerminal, BearLibLog, BearLibConfig и т. п. или переименовываться и эволюционировать в сторону цельного фреймворка.
Пытается раскуклиться

Ответить

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость