jarg
Модераторы: Sanja, Максим Кич
Re: jarg
Да, задачка занятная. Если не получается в лоб, попробуй с другой стороны.
Генери дороги, а к ним привязывай города. Например, если генератор выдаёт конец дороги, пристыкуй к ней хутор. К пересечению дороги и реки - деревню. К пересечению дорог - город и т.д.
Генери дороги, а к ним привязывай города. Например, если генератор выдаёт конец дороги, пристыкуй к ней хутор. К пересечению дороги и реки - деревню. К пересечению дорог - город и т.д.
Re: jarg
Вариант с генерацией относительно дорог, как по мне правильный.
По сути дороги - это кривые от точки до точки.
Каждый новый сегмент карты при генерации пристыкован к одной или более стороне уже существующих сегментов. Пусть те и сообщат, есть ли на соединительной стороне концы дорог и их координаты. Сегменты для удобства даже могут в специальном списке хранить координаты дорог, которые уходят за их край.
Теперь генератору сегмента на вход подаешь входящие дороги от соседей, тот решает (случайным образом) будут ли дороги выходить за его стороны, которые пока соединены с "неизвестностью", будут ли в сегменте города/пещеры/точки интереса и т.д.
Вот у тебя и есть набор входящих и выходящих точек в сегменте для генерации дорог.
По сути дороги - это кривые от точки до точки.
Каждый новый сегмент карты при генерации пристыкован к одной или более стороне уже существующих сегментов. Пусть те и сообщат, есть ли на соединительной стороне концы дорог и их координаты. Сегменты для удобства даже могут в специальном списке хранить координаты дорог, которые уходят за их край.
Теперь генератору сегмента на вход подаешь входящие дороги от соседей, тот решает (случайным образом) будут ли дороги выходить за его стороны, которые пока соединены с "неизвестностью", будут ли в сегменте города/пещеры/точки интереса и т.д.
Вот у тебя и есть набор входящих и выходящих точек в сегменте для генерации дорог.
Re: jarg
Вообще, я мыслил себе это более "лениво" Т.е. есть, допустим, генератор шума, у которого коеффициенты выставлены так, что он геренирит крывые на определённой высоте.
(как на последней картинке, например)
Соответственно, для следующего сектора он автоматически нагенерит сеть дорог, которая УЖЕ совмещена с со всеми окружающими Даже не опрашивая соседние зоны можно генерить сектор.
(как на последней картинке, например)
Соответственно, для следующего сектора он автоматически нагенерит сеть дорог, которая УЖЕ совмещена с со всеми окружающими Даже не опрашивая соседние зоны можно генерить сектор.
- Максим Кич
- Администратор
- Сообщения: 1642
- Зарегистрирован: 03 дек 2006, 20:17
- Откуда: Витебск, Беларусь
- Контактная информация:
Re: jarg
Вообще, надо просто делать прегенерацию через сектор. Покажу на одномерном примере, допустим на текущий ход, игрок перешёл из сектора 1 в сектор 2. Под «городами» тут следует понимать любой объект на карте, к которому можно проложить дорогу.
Начало генерации:
Конец генерации:
Таким образом между игроком и краем карты всегда находится как минимум один полностью сгенерированный сектор. Это исключит ситуации, когда игрок видит, как на карте появляется новая дорога.
Начало генерации:
Код: Выделить всё
Сектор | Состояние
-------+--------
1 | Тут мы уже прошли, дороги к секторам 0 и 2
2 | Тут находится игрок. Дороги к секторам 1 и 3
3 | Сектор полностью сгенерирован. Дороги к секторам 2 и 4
4 | Сгенерированы города сектора и дороги от них к сектору 3
Код: Выделить всё
Сектор | Что делаем
-------+--------
1 | Ничего
2 | Тут находится игрок. Ничего
3 | Ничего
4 | Создаём дороги к городам сектора 5
5 | Создаём новый сектор. Генерируем города.
Dump the screen? [y/n]
Re: jarg
Руби. Шучу, он с шарпом будет интегрироваться еще хуже.ishellstrike писал(а):Луа так то было неплохо, но интеграция с шарпом как-то не слишком гладкая.
Подключать - да скорее всего ручной или автоматической генерацией кода заголовков.
Хотя для шарпа наверняка есть можно как-то рефлексию задействовать, но как именно не представляю.
Ну а гугл, вроде бы, советует все-таки использовать C#: http://stackoverflow.com/questions/1379 ... pplication
- Cfyz
- Сообщения: 776
- Зарегистрирован: 30 ноя 2006, 10:03
- Откуда: Санкт-Петербург
- Контактная информация:
Re: jarg
Как бы я ни любил С++, один законченный проект на C# с терпимой производительностью стоит куда больше дюжины незаконченных на С++.
Если код логики пожух и уже сил нет хочется переписать, то может быть какое-то зерно тут и есть, благо 10к строк это еще не катастрофа. Но если у текущей архитектуры все еще впереди, раскатывать ее бульдозером ради FPS сомнительная затея. Зависимость от .NET/Mono уже не проблема, они максимум на расстоянии репозитория, а чаще уже стоят из коробки. Если не нравится XNA и морально готов к лоу-левел графике, возьми OpenTK (тонкая обертка над OpenGL/OpenAL, ссылка), он кроссплатформеннен и без лишних зависимостей.
Если код логики пожух и уже сил нет хочется переписать, то может быть какое-то зерно тут и есть, благо 10к строк это еще не катастрофа. Но если у текущей архитектуры все еще впереди, раскатывать ее бульдозером ради FPS сомнительная затея. Зависимость от .NET/Mono уже не проблема, они максимум на расстоянии репозитория, а чаще уже стоят из коробки. Если не нравится XNA и морально готов к лоу-левел графике, возьми OpenTK (тонкая обертка над OpenGL/OpenAL, ссылка), он кроссплатформеннен и без лишних зависимостей.
Пытается раскуклиться
Re: jarg
Сам использую вариант чем-то близкий к 2. Только работу с тегами собрал в отдельный класс который включается в наследование, чтобы можно было функциями класса HasTag AddTag RemoveTag получать что нужно.
Подумай над тем как ты будешь реализовывать приоритет обработки таких флагов функционала.
Если у тебя есть ключ "печка" и ключ "замок" как дать понять, что пока не открыт замок недоступна печка.
Подумай над тем как ты будешь реализовывать приоритет обработки таких флагов функционала.
Если у тебя есть ключ "печка" и ключ "замок" как дать понять, что пока не открыт замок недоступна печка.
- Cfyz
- Сообщения: 776
- Зарегистрирован: 30 ноя 2006, 10:03
- Откуда: Санкт-Петербург
- Контактная информация:
Re: jarg
Было бы интересно услышать немного подробнее про каждый из подходов, что именно показалось удобным, что, напротив, было записано в минусы. "Некоторые ограничения на логику" это все-таки мало для понимания ситуации.
Я думаю лучше всего взять понемногу из каждого. Из #1 взять иерархию-наследование и динамическое, фабричное создание экземпляров класса. Из #2 взять идею динамической комбинации блоков поведения в одну сущность. Из #3 взять гибкость логики обработки. Т. е. объект полностью строится из блоков (#2), которые имеют не только поведение, но и данные, и сами выстроены в удобную иерархию классов (#1), но при этом каждый блок в своем "обработчике" имеет доступ к контексту (#3) объекта-контейнера.Этот блок-компонент PrimitiveAI можно навесить на сундук. Потом добавить сундуку компонент Fear и тем самым заставить его шарахаться от каких-нибудь крыс и рандомно ходить иначе. Потом, если будет добавлен NotSoPrimitiveAI, который не просто шарахается в стороны, но аккуратно обходит по дуге, достаточно заменить название компоненты в конфиге монстра.
Т. е. я конечно немного ударился в то, как я сам предполагаю делать :D я пока ничего точно не знаю, только собираюсь игру писать.
Я думаю лучше всего взять понемногу из каждого. Из #1 взять иерархию-наследование и динамическое, фабричное создание экземпляров класса. Из #2 взять идею динамической комбинации блоков поведения в одну сущность. Из #3 взять гибкость логики обработки. Т. е. объект полностью строится из блоков (#2), которые имеют не только поведение, но и данные, и сами выстроены в удобную иерархию классов (#1), но при этом каждый блок в своем "обработчике" имеет доступ к контексту (#3) объекта-контейнера.
Код: Выделить всё
void PrimitiveAI::Process() {
if (auto fear = parent.GetComponent("Fear")) {
if (map.InVicinity(fear->GetFearedType())) {
parent.GetComponent("Movement")->Flee();
}
} else {
BaseAI::Process();
}
}
Т. е. я конечно немного ударился в то, как я сам предполагаю делать :D я пока ничего точно не знаю, только собираюсь игру писать.
Пытается раскуклиться
Re: jarg
Тут еще такой нюанс. Ты из академического интереса хочешь сделать супер модульный роглайк движок или больше по прикладному игру написать?ishellstrike писал(а):Предлагаю обсудить представление игровых объектов
Хотелось бы услышать ваше мнение по этому поводу.
Если второе, лучше сразу делать прототип и испытывать его. Чем больше понимаешь реальный востребованный объем этих модульных фич - тем ближе от идеальной теории до работающей практики.
Представь что после большого объема труда по разработке и реализации "идеальной модульной концепции" твои АИ монстра вместо супер-реалистичного поведения топчется на двух тайлах. Потому что на дальнем тайле ему хочется преследовать противника, а на ближнем тайле он боится костра. И более простая логика на конечном автомате "охота->преследование->побег" дает лучший результат. А из всех пересечений модульности в объектах у тебя "дверь" и "замок" как максимум, хотя движок позволяет туда еще с десяток впихнуть и то пришлось еще костылями их подпереть, потому что там нужен еще был вот такой нюанс практический или же вставлять проверки на существование конкретного модуля во все остальные, чтобы он корректно работал. И тогда это сложно уже модульностью то назвать. Печалька? Столько труда на смарку пойдет.
Посему если задача "грязная" и неизведанная, чем ближе к практике и работающим прототипам, тем ближе к результату.
- Cfyz
- Сообщения: 776
- Зарегистрирован: 30 ноя 2006, 10:03
- Откуда: Санкт-Петербург
- Контактная информация:
Re: jarg
Хотя вопрос был не ко мне, прокомментирую касаемо компонентного подхода к реализации объектов.
То, что я писал выше -- это адаптация описанного в Evolve Your Hierarchy. Проблема простой логики из хардкода и проверок флагов в том, что она слабо поддается модификации (что, по-моему, одна из отличительных особенностей разработки roguelike), суровое наследование, к слову, тоже обычно не очень хорошо себя показывает. Игровые объекты -- это обычно не сплошные монолиты с раз и навсегда предопределенным поведением, а достаточно пестрый набор из различных аспектов игровой механики. Причем изменения в механие затрагивают разные части разных объектов, из-за чего одна иерархия просто не работает. Компонентный подход, по идее, позволяет выделить эти самые аспекты -- способ передвижения, форма и содержание, визуальное представление, AI, модификаторы и т. д. -- и структурировать их максимально независимо. Ну и плюшки выноса сборки в рантайм и упрощения сериализации тоже стоит иметь в виду.
То, что я писал выше -- это адаптация описанного в Evolve Your Hierarchy. Проблема простой логики из хардкода и проверок флагов в том, что она слабо поддается модификации (что, по-моему, одна из отличительных особенностей разработки roguelike), суровое наследование, к слову, тоже обычно не очень хорошо себя показывает. Игровые объекты -- это обычно не сплошные монолиты с раз и навсегда предопределенным поведением, а достаточно пестрый набор из различных аспектов игровой механики. Причем изменения в механие затрагивают разные части разных объектов, из-за чего одна иерархия просто не работает. Компонентный подход, по идее, позволяет выделить эти самые аспекты -- способ передвижения, форма и содержание, визуальное представление, AI, модификаторы и т. д. -- и структурировать их максимально независимо. Ну и плюшки выноса сборки в рантайм и упрощения сериализации тоже стоит иметь в виду.
Ну само собой, нужно не перегибать палку. Если раздробить аспекты механики обратно до бинарных флагов, то ничего хорошего не получится. Идея AI-компонента в том, что его-то как раз может быть иерархия классов (так как, вероятно, у разных реализаций AI все равно будет много общего). Зато не придется грузить базовый класс монстра всеми мыслимыми вариантами поведения ради возможных mind control или maddness, которые меняют логику AI полностью.Oreyn писал(а):Представь что после большого объема труда по разработке и реализации "идеальной модульной концепции" твои АИ монстра вместо супер-реалистичного поведения топчется на двух тайлах. Потому что на дальнем тайле ему хочется преследовать противника, а на ближнем тайле он боится костра.
Ну и тут примерно то же самое. Ключевых типов модулей должно быть немного, но могут быть чрезвычайно легковесные компоненты-метки типа "травматическая боязнь того-то" или "предрасположенность к этому-то". Которые сами не несут особой логики, но имеют состояние (читай -- переменные) и могут быть (а могут и не быть) учтены другими компонентами. Это, конечно, можно было бы выделить в отдельную сущность со своим интерфейсом, но если вся инфраструктура и так поддерживает необходимые операции, то зачем?Oreyn писал(а):потому что там нужен еще был вот такой нюанс практический или же вставлять проверки на существование конкретного модуля во все остальные
Пытается раскуклиться
Re: jarg
Насчёт компонентного подхода, BTW, могу порекомендовать подход Юнити - присмотреться к нему, во всяком случае, стоит.
Подход этот заключается в том, что игровой объект имеет один обязательный компонент (Transform, позиция/поворот/скейл) и до черта всяческих опциональных (рендерер, столкновениекоробка, партиклы et cetera, et cetera). При этом сам код поведения тоже аттачится к объекту по принципу "один класс - один компонент".
Учитывая популярность Юнити, такая структура, очевидно, вполне себе жизнеспособна, обладая достаточной гибкостью и при этом не превращаясь в слабосвязанную кашу с плавающими в ней кусочками кода.
Подход этот заключается в том, что игровой объект имеет один обязательный компонент (Transform, позиция/поворот/скейл) и до черта всяческих опциональных (рендерер, столкновениекоробка, партиклы et cetera, et cetera). При этом сам код поведения тоже аттачится к объекту по принципу "один класс - один компонент".
Учитывая популярность Юнити, такая структура, очевидно, вполне себе жизнеспособна, обладая достаточной гибкостью и при этом не превращаясь в слабосвязанную кашу с плавающими в ней кусочками кода.
Всё вышесказанное - ИМХО, если не указано обратное.
- Jesus05
- Сообщения: 1840
- Зарегистрирован: 02 дек 2009, 07:50
- Откуда: Норильск, сейчас Санкт-петербург.
- Контактная информация:
Re: jarg
Вот это бы еще заменить на события.
типа
а в дальнейшем вообще вынести этот набор параметров в класс Event и сделать
Код: Выделить всё
virtual void onDbLoad(std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
virtual void onInit(std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
virtual void onUpdate(std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
virtual void onDraw(std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
virtual void onInteract(std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
virtual void onDamage(std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
virtual void onDestroy(std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
virtual void onEnter(std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
virtual void onLeave(std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
Код: Выделить всё
virtual void onEvent(int eventType, std::shared_ptr<Object> &par, Level *l, const glm::vec3 &pos, const GameTimer& gt);
Код: Выделить всё
virtual void onEvent(Event &ev);
- Jesus05
- Сообщения: 1840
- Зарегистрирован: 02 дек 2009, 07:50
- Откуда: Норильск, сейчас Санкт-петербург.
- Контактная информация:
Re: jarg
Мне кажется так удобнее будет добавлять новые события при необходимости.ishellstrike писал(а):Думаешь разбор
будет удобнее? Если уж делать универсальные события, то, вероятно, надо делать какую-то подписку на них. Типа шины событийКод: Выделить всё
void onEvent(Event &e) { switch(e.type) { case EVENT_SOME: ... }}
...
А если придумать систему непересекающихся номеров событий, тогда классы наследники смогут пользоваться какой-нить группой событий о который родитель вообще ничего не знает.
- Jesus05
- Сообщения: 1840
- Зарегистрирован: 02 дек 2009, 07:50
- Откуда: Норильск, сейчас Санкт-петербург.
- Контактная информация:
Re: jarg
Для размышлений... в oxygine уникальность событий сделана на чем-то типа имен событий.
https://github.com/oxygine/oxygine-fram ... rc/Event.h
https://github.com/oxygine/oxygine-fram ... spatcher.h
https://github.com/oxygine/oxygine-fram ... syncTask.h
https://github.com/oxygine/oxygine-fram ... rc/Input.h
https://github.com/oxygine/oxygine-fram ... KeyEvent.h
https://github.com/oxygine/oxygine-fram ... gressBar.h
https://github.com/oxygine/oxygine-fram ... uchEvent.h
В примерах есть объявление своего события не системного.
https://github.com/oxygine/oxygine-fram ... rc/Scene.h
https://github.com/oxygine/oxygine-fram ... rc/Event.h
https://github.com/oxygine/oxygine-fram ... spatcher.h
https://github.com/oxygine/oxygine-fram ... syncTask.h
Код: Выделить всё
ERROR = sysEventID('A', 'T', 'E'),
PROGRESS = sysEventID('A', 'T', 'P'),
COMPLETE = sysEventID('A', 'T', 'C')
Код: Выделить всё
event_platform = sysEventID('I', 'P', 'L')
Код: Выделить всё
KEY_DOWN = sysEventID('K', 'E', 'D'),
KEY_UP = sysEventID('K', 'E', 'U')
Код: Выделить всё
PROGRESS_CHANGED = sysEventID('P', 'C', 'h')
Код: Выделить всё
enum
{
__FIRST = sysEventID('T', 'O', 0),
CLICK,
OVER,
OUT,
MOVE,
TOUCH_DOWN,
TOUCH_UP,
WHEEL_UP,
WHEEL_DOWN,
__LAST//system
};
https://github.com/oxygine/oxygine-fram ... rc/Scene.h
Код: Выделить всё
EVENT = makefourcc('S', 'H', 'i', 'd')
Кто сейчас на конференции
Сейчас этот форум просматривают: нет зарегистрированных пользователей и 23 гостя