BeaRLibMG - генератор карт

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

Модератор: Apromix

Аватара пользователя
Jesus05
Сообщения: 1840
Зарегистрирован: 02 дек 2009, 07:50
Откуда: Норильск, сейчас Санкт-петербург.
Контактная информация:

Re: BeaRLib

Сообщение Jesus05 » 03 сен 2011, 11:06

Apromix писал(а):Пришлось для твоего примера качать Rtl60.bpl и Vcl60.bpl, но оно того, хе-хе, стоило :) Остался СИШАРП :lol:
куда я спешил :) выложил зачем-то дебажный вариант.
вот этот должен просить только dll-ку
BorlandLoadLibraryExe.zip
(241.5 КБ) 62 скачивания
по идеи через LoadLibrary должно работать везде.

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

Re: BeaRLib

Сообщение Cfyz » 03 сен 2011, 11:12

В WinAPI, среди множества прочих, есть функция GetConsoleOutput, которая возвращает текущее содержимое (символы и их цвета) указанной области консоли. Сигнатура:

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

BOOL WINAPI ReadConsoleOutput(
  __in     HANDLE hConsoleOutput,
  __out    PCHAR_INFO lpBuffer,
  __in     COORD dwBufferSize,
  __in     COORD dwBufferCoord,
  __inout  PSMALL_RECT lpReadRegion
);
В этой функции массив структур CHAR_INFO, описывающих символ, записывается в область памяти, предоставленную по указателю lpBuffer. Выполняемая функцией задача достаточно схожа с задачей бурно обсуждаемой GenMap; по меньшей их можно сравнить-свериться, в MS тоже наверняка не с потолка взяли.

Ок, до того, что область памяти, куда будет записана карта, надо передавать в библиотеку, методом тыка дошли =) На самом деле, ну по крайней мере мне так кажется, это вообще единственно разумный способ. Ведь черт его знает, как и откуда память была выделена и кто потом за нее будет ответственный. Бывает, библиотеки предоставляют еще и функцию для освобождения памяти, но тогда может пострадать кроссплатформенность -- в самом простом случае какой-нибудь язык со сборщиком мусора может попросту подмести отданный в его ведение блок памяти, а может и проигнорировать.

Второй момент, который странно, что еще никто не заметил -- это какбы CHAR_INFO. Слабо верится, что библиотеке навсегда хватит восьми бит на одну ячейку карты. Стены всегда будут одинаковые? Стен с царапинами, обшарпанных и заляпанных не предвидится? Расставленные по уровню факелы всегда будут одного цвета и яркости? Вода в ручейке одной глубины?

Кроме того, в ячеках карты рано или поздно появятся предметы; казалось бы, при чем тут генератор уровней, но астролябия в подземелье, кучи готовой городской еды в джунглях и прочие преступления против тематики? Не спорю, полноценная работа с предметами -- это прерогатива самой игры, я же имею в виду что-то типа классов предметов и своеобразных предметных уников. При генерации карты у генератора есть куда больше информации о том, что это за ячейка-место-область и он может куда качественнее расставить предметы или вообще сгенерировать комнату с охраной вокруг какого-нибудь артефакта подороже. Что, в свою очередь, подталкивает к мысли, что генератор неплохо бы как-нибудь параметризовать при вызове: насколько пустынна или еще чего-нибудь местность (в игре с небольшими уровнями, если мы двигается от города в лес, логично сделать один-два промежуточных, переходных), сколько на уровне тех или иных ключевых мест. Попасть на уровень, по трем тайлам опознать тип местности и точно знать, что на этом уровне два алтаря в разных углах? С другой стороны, полный рандом на усмотрение генератора тоже нехорошо -- в одной игре алтарь на каждом уровне может быть непозволительной роскошью, в то время как в другой они являются сюжетно обоснованным расходным материалом.

Я к тому, что char, byte или даже unsigned long long -- это несерьезно для проекта с хоть какими-то амбициями.
Пытается раскуклиться

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

Re: BeaRLib

Сообщение Apromix » 03 сен 2011, 11:24

Cfyz
Может повторюсь, но мне кажется, что генератор карт должен генерить карту только в базовом виде, как есть сейчас. Уже сама игра должна по этой карте определять важность тайла, его тип, подтип и цвет (ну или там картинку-тайл), расставлять объекты (предметы, монстры, NPC) и т. д.

Так я сейчас делаю в HoD'e. Там есть только массивы из структур (слоев на карте) из целых чисел (номера объектов). Получив из либы карту, HoD на месте разбирается, что и куда :)

Аватара пользователя
Jesus05
Сообщения: 1840
Зарегистрирован: 02 дек 2009, 07:50
Откуда: Норильск, сейчас Санкт-петербург.
Контактная информация:

Re: BeaRLib

Сообщение Jesus05 » 03 сен 2011, 11:33

вариант опять-же для C++ builder через .lib файл.
1. надо создать либ файл через утилиту которая есть в билдере
implib.exe -c BeaRLibMG.lib BeaRLibMG.dll
на выходе получим BeaRLibMG.lib
2. включить в проект BeaRLibMG.lib
3. определение функции выгляди так

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

extern "C" __declspec(dllimport) void __stdcall GenMap (int,int,int,char**,int);
соотвественно LoadLibrary и GetProcAddr уже не нужны.

JustHarry
Сообщения: 655
Зарегистрирован: 30 июл 2010, 17:13

Re: BeaRLib

Сообщение JustHarry » 03 сен 2011, 11:38

Минимальные отличия тайлов конечно же нужны, чтобы отличать хотя бы пол квартиры от тайла земли.

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

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

Re: BeaRLib

Сообщение Cfyz » 03 сен 2011, 11:48

Apromix писал(а):генератор карт должен генерить карту только в базовом виде, как есть сейчас
Вполне допускаю, но...
Apromix писал(а):Уже сама игра должна по этой карте определять важность тайла, его тип, подтип и цвет <...> расставлять объекты
Получается, игра, выцепив из генератора почти готовый уровень (а у вас, извините, хоть сразу на экран вставляй), должна вычислять границы комнат-переходов, расставлять высоты холмов и прочую информацию, которая уже была вычислена на стадии генерации? Вычислять с неизбежными ошибками. Цвет и тайл -- черт с ними, это очевидно, я имел в виду информацию, которая потеряется в ASCII и для восстановления которой необходимо будет применять алгоритмы порядка распознавания изображения. Мы же со случайными числами работаем, какой алгоритм определения важности тайла не применяй, рано или поздно артефакт таки будет поставлен не стой стороны стены.

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

Ну и наконец,
Apromix писал(а):Так я сейчас делаю в HoD'e. Там есть только массивы из структур (слоев на карте) из целых чисел (номера объектов).
Примерно про это я и говорил. Реализация объектов, разумеется -- это в самой игре. Но что это за тайл и зачем он тут нужен, можно описать и поподробнее.

___
Не успеваешь комментировать =)
JustHarry писал(а):Параметризация генератора зависит на мой взгляд только от типа карты(город может быть разрушенным\целым, лес густым\редким, река глубокой\иссушенной и т.д)
Практически это я и имел в виду. Если учитывать и количество чего-то на карте (комнат, озер, башен), то получается, что для каждого типа карты необходимо что-то типа структуры параметров. Что приводит к...
JustHarry писал(а):Все это очень важно, но не первостепенно сейчас. Слава богу, получилось хотя бы обеспечить более-менее стабильную работу dll.
Когда руки дойдут до параметризации, будет "слава богу, получилось, часть вторая". Имхо надо придумать это сейчас, но на саму реакцию со стороны генератора на эти параметры пока действительно можно смело бить болт.
Пытается раскуклиться

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

Re: BeaRLib

Сообщение Apromix » 03 сен 2011, 12:10

Ну теперь более-менее понятно... Тогда как лучше эти параметры получать из либы, в структуре и этой процедуре? Или вызывать еще одну процедуру, которая и возвращает в структуре дополнительную информацию о созданной карте? Может, еще есть варианты?

JustHarry
Сообщения: 655
Зарегистрирован: 30 июл 2010, 17:13

Re: BeaRLib

Сообщение JustHarry » 03 сен 2011, 12:13

должна вычислять границы комнат-переходов, расставлять высоты холмов и прочую информацию, которая уже была вычислена на стадии генерации?
Это кому-то нужно? Мы же делаем генератор в первую очередь для того, чтобы хоть как-то облегчить вот эту вот реакцию первых разработчиков рогаликов:
"День 1. Написал движок игры.
День 2. Пишу генератор карты....

День 123. Ушел читать Макконнелла.
"

Рано или поздно любой более-менее искушенный разработчик рогаликов захочет свой собственный уровень с блэкджеком... ну ты понял. А пока, все что ему нужно - разнообразие и простота работы.

Ну и в конце концов, на первую пору хватит передачи не символов а т.н кодов тайлов(0 - земля, 1 - грязь, 2 - стена дома, 3 - угол дома, 4 - высокая гора и т.д).

Насчет параметризации согласен полностью, начинать стоит прямо сейчас.

Аватара пользователя
Jesus05
Сообщения: 1840
Зарегистрирован: 02 дек 2009, 07:50
Откуда: Норильск, сейчас Санкт-петербург.
Контактная информация:

Re: BeaRLib

Сообщение Jesus05 » 03 сен 2011, 12:40

а я тем временем пытаюсь заставить MinGW скушать lib сделаный его-же инструментами пока не удачно... т.е. если обозначать функцию как не stdcall он кушает и даже запускает функцию, но вот работает она точно не правильно ибо не возвращает никаких данных.
а если использовать stdcall то MinGW-шкой скомпилированный экзешник усиленно ищет в dll функцию GenMap@20 (которой там конечно-же нету)
как ему обьяснить что GenMap надо читать без особой stdcall-ской магии :) пока не знаю. мучаю гугл :) он пока не сдается.

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

Re: BeaRLib

Сообщение Apromix » 03 сен 2011, 13:13

Думаешь меньше было бы вот этих странных проблем, если бы либа изначально была бы написана на С?

Аватара пользователя
Jesus05
Сообщения: 1840
Зарегистрирован: 02 дек 2009, 07:50
Откуда: Норильск, сейчас Санкт-петербург.
Контактная информация:

Re: BeaRLib

Сообщение Jesus05 » 03 сен 2011, 13:34

Apromix писал(а):Думаешь меньше было бы вот этих странных проблем, если бы либа изначально была бы написана на С?
с моим знанием этих странных инструментов от MinGW было бы ровно столько-же :) по любому можно писать через LoadLibrary и GetProcAddr с ними все нормально работает :)
в моем случае с MinGW проблема, что он не умеет читать lib сделаные для Builder у каждого блин свой формат :)(если мне память не изменяет Visual C++ имеет свой формат lib фалов не совместимый не с тем не с тем)
у билдера все просто было :) либу сделал утилькой подключил описал функцию в коде и все.
у мингв насколько я пока разобрался надо руками написать def файл где описать какие есть функции и как они выглядят в dll-ке после чего собрать lib подключить к проекту и попробовать... при чем походу на уровне сбора lib файла утилька вообще не проверяет а есть ли функции описанные в def файле в dll файле короче проблема в утилитах MinGW, а не в вашей dll-ке.

Аватара пользователя
Jesus05
Сообщения: 1840
Зарегистрирован: 02 дек 2009, 07:50
Откуда: Норильск, сейчас Санкт-петербург.
Контактная информация:

Re: BeaRLib

Сообщение Jesus05 » 03 сен 2011, 14:28

я его победил :) код конечно попахивает говнокодом

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

extern "C" __declspec(dllimport) void GenMap(int,int,int,char**,int);
typedef _stdcall void (*TGenMap)(int, int, int, char**, int);
TGenMap GenMap1;

int main()
{
  GenMap1 = (TGenMap)GenMap;  //это явно плохо пахнет
  int width = 25;
  int height = 25;
    char *test = new char[width*height];
    for (int i = 0; i < width*height; i++) test[i] = 0;
    GenMap1(width,height,3,&test,width*height);
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
          printf("%c", test[x+y*width]);
        }
        printf("\r\n");
    }
    delete[] test;
    return 0;
}
перед этим надо создать файл BeaRLibMG.def в котором написать

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

LIBRARY    BeaRLibMG.dll
EXPORTS
	GenMap			@1
после этого запустить dlltool.exe из набора MinGW с параметрами
dlltool.exe -D BeaRLibMG.dll -d BeaRLibMG.def -l BeaRLibMG.lib
скопировать полученный lib в папку с проектом
добавить линкеру инструкцию на подключение BeaRLibMG (важно без расширения иначе будет ругаться)
добавить линкеру в Search Directory директорию проекта он по умолчанию там не ищет.

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

Re: BeaRLib

Сообщение Cfyz » 03 сен 2011, 17:03

Jesus05 писал(а)://это явно плохо пахнет
Забавно, ведь это тот самый метод, с помощью которого "подгружаются" расширения OpenGL. Определяется указатель на функцию, посредством вызова wglGetProcAddress драйвер возвращает адрес функции, он присваивается указателю, вуаля.

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

Имхо здесь два варианта.
1. Забить на name mangling совсем и сделать a la OpenGL вызовы по указателям.
2. Распространять в дистрибутиве .lib для всех популярных компиляторов.

Вариант 1 можно оформить почти опрятно:

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

// BeaRLib.h

#include <windows.h>

#define SOME_MAP_TYPE 3

typedef _stdcall void (*GenMapProc)(int,int,int,char**,int);
GenMapProc GenMap;

void InitializeBeaRLib()
{
	HMODULE BeaRLib = LoadLibrary(TEXT("BeaRLibMG.dll"));
	GenMap = (GenMapProc)GetProcAddress(BeaRLib, "GenMap");
}

// main.cpp

#include <stdio.h>
#include <stdlib.h>
#include "BeaRLib.h"

int main(int argc, char *argv[])
{
	InitializeBeaRLib();
	
	int width = 25, height = 25;
	char *test = new char[width*height];
	GenMap( width, height, SOME_MAP_TYPE, &test, width*height );
	for ( int y=0; y<height; y++ )
	{
		for ( int x=0; x<width; x++ ) putchar( test[x + y*width] ); 
		printf( "\r\n" );
	}
	delete[] test;

	system( "pause" );
	return 0;
}
И никаких гвоздей .def с .lib, проверено на Dev-C++ 5.0.0.2 (если бы не вы со своим MinGW, я бы еще сто лет не знал, что Dev-C++ к жизни вернулся =) ).
Пытается раскуклиться

Аватара пользователя
Jesus05
Сообщения: 1840
Зарегистрирован: 02 дек 2009, 07:50
Откуда: Норильск, сейчас Санкт-петербург.
Контактная информация:

Re: BeaRLib

Сообщение Jesus05 » 04 сен 2011, 04:49

Cfyz писал(а):
Jesus05 писал(а)://это явно плохо пахнет
Забавно, ведь это тот самый метод, с помощью которого "подгружаются" расширения OpenGL. Определяется указатель на функцию, посредством вызова wglGetProcAddress драйвер возвращает адрес функции, он присваивается указателю, вуаля.

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

Имхо здесь два варианта.
1. Забить на name mangling совсем и сделать a la OpenGL вызовы по указателям.
2. Распространять в дистрибутиве .lib для всех популярных компиляторов.
....
И никаких гвоздей .def с .lib, проверено на Dev-C++ 5.0.0.2 (если бы не вы со своим MinGW, я бы еще сто лет не знал, что Dev-C++ к жизни вернулся =) ).
ты видимо не понял чего я пытался добится :)
как я писал выше
по любому можно писать через LoadLibrary и GetProcAddr с ними все нормально работает :)
можно реализовать так думаю на любом языке на котором есть вызов ВинАпи функций, а я пытался сделать через lib что-бы загрузкой библиотеки занималась таблица импорта которую создал бы линкер. но мне не удалось ему обьяснить что мне нужна функция которая вызывалась бы как stdcall но которая в библиотеки называется GenMap (по каким-то там :) полу соглашениям функции stdcall имеют названия GenMap@20 (20 здесь кол-во байт в параметрах)) и мне не удалось обьяснить линкеру МинГВ-шному, что мне не нужны его преобразования в имени функции. С другой стороны если верить описаниям по утилитам создающим либы он вроде в либу должен уметь записывать альясы т.е. в коде пишу GenMapFromBearLib а вызывается GenMap, но эта хрень тоже не прокатила. т.ч. либо я не понял как эти утильки работают :) либо одно из двух (я уверен что линкер умеет делать то что мне нужно)
а говнокод это потому, что разницы почти нету между вызовом через LoadLibrary и тем как я сделал.

и еще :) OpenGL насколько я помню использует принцип загрузки своих дополнений в Винде через GetProcAddres потому, что мелкомягкие вставляют\вставляли палки в колеса когда ОпенГЛ был еще в версии 1.0, мелкомягкие были против другого АПИ кроме Дирекса.

JustHarry
Сообщения: 655
Зарегистрирован: 30 июл 2010, 17:13

Re: BeaRLib

Сообщение JustHarry » 04 сен 2011, 18:13

Вернулся к работе над генератором.

Сперва сделал его независимым от тайлсета, то есть карта теперь хранится не символами, а целым типом(integer), а уже игра решает, как визуализировать тот или иной тайл.
Скрытый текст: ПОКАЗАТЬ
const TILE_CAVE_WALL=0;
const TILE_GROUND=1;
const TILE_WATER = 2;
const TILE_TREE = 3;
const TILE_MOUNTAIN = 4;
const TILE_DOOR=5;
const TILE_ROAD=6;
const TILE_HOUSE_WALL = 7;
const TILE_HOUSE_FLOOR = 8;
const TILE_GRASS = 9;
const TILE_EMPTY = 10;

Поправлены кое-какие баги, улучшен генератор деревни\города(в городе теперь практически нету пустых улиц, и заполняется город с деревней теперь практически полностью, вот только существенно увеличилось время генерации, 200Х200 карта генерится около 5 секунд, будет оптимизировано в дальнейшем).

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

На очереди: генераторы рек, улучшения текущих генераторов, их параметризация и оптимизация по времене генерации.
Вложения
21.PNG
21.PNG (44.34 КБ) 3266 просмотров
2.PNG
2.PNG (13.4 КБ) 3267 просмотров
1.PNG
1.PNG (14.6 КБ) 3267 просмотров

Ответить

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

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