jarg

Форум для проектов, находящихся на стадии Альфа и Бета. В них ещё не реализована вся задуманная автором функциональность, а значит идёт активная разработка.

Модераторы: Sanja, Максим Кич

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

Re: jarg

Сообщение Shirson » 03 окт 2013, 22:54

Да, задачка занятная. Если не получается в лоб, попробуй с другой стороны.
Генери дороги, а к ним привязывай города. Например, если генератор выдаёт конец дороги, пристыкуй к ней хутор. К пересечению дороги и реки - деревню. К пересечению дорог - город и т.д.

Аватара пользователя
Oreyn
Сообщения: 297
Зарегистрирован: 07 авг 2013, 14:59

Re: jarg

Сообщение Oreyn » 04 окт 2013, 07:23

Вариант с генерацией относительно дорог, как по мне правильный.

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

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

Re: jarg

Сообщение Shirson » 04 окт 2013, 12:56

Вообще, я мыслил себе это более "лениво" :) Т.е. есть, допустим, генератор шума, у которого коеффициенты выставлены так, что он геренирит крывые на определённой высоте.

(как на последней картинке, например)
Изображение

Соответственно, для следующего сектора он автоматически нагенерит сеть дорог, которая УЖЕ совмещена с со всеми окружающими :) Даже не опрашивая соседние зоны можно генерить сектор.

Аватара пользователя
Максим Кич
Администратор
Сообщения: 1642
Зарегистрирован: 03 дек 2006, 20:17
Откуда: Витебск, Беларусь
Контактная информация:

Re: jarg

Сообщение Максим Кич » 06 окт 2013, 10:48

Вообще, надо просто делать прегенерацию через сектор. Покажу на одномерном примере, допустим на текущий ход, игрок перешёл из сектора 1 в сектор 2. Под «городами» тут следует понимать любой объект на карте, к которому можно проложить дорогу.

Начало генерации:

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


Сектор |  Состояние
-------+--------
1      | Тут мы уже прошли, дороги к секторам 0 и 2
2      | Тут находится игрок. Дороги к секторам 1 и 3
3      | Сектор полностью сгенерирован. Дороги к секторам 2 и 4
4      | Сгенерированы города сектора и дороги от них к сектору 3

Конец генерации:

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


Сектор |  Что делаем
-------+--------
1      | Ничего
2      | Тут находится игрок. Ничего
3      | Ничего
4      | Создаём дороги к городам сектора 5
5      | Создаём новый сектор. Генерируем города.
Таким образом между игроком и краем карты всегда находится как минимум один полностью сгенерированный сектор. Это исключит ситуации, когда игрок видит, как на карте появляется новая дорога.
Dump the screen? [y/n]

Аватара пользователя
kipar
Сообщения: 2120
Зарегистрирован: 10 мар 2010, 13:16
Откуда: Москва

Re: jarg

Сообщение kipar » 04 янв 2014, 17:25

ishellstrike писал(а):Луа так то было неплохо, но интеграция с шарпом как-то не слишком гладкая.
Руби. Шучу, он с шарпом будет интегрироваться еще хуже.

Подключать - да скорее всего ручной или автоматической генерацией кода заголовков.
Хотя для шарпа наверняка есть можно как-то рефлексию задействовать, но как именно не представляю.
Ну а гугл, вроде бы, советует все-таки использовать C#: http://stackoverflow.com/questions/1379 ... pplication

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

Re: jarg

Сообщение Cfyz » 02 апр 2014, 12:31

Как бы я ни любил С++, один законченный проект на C# с терпимой производительностью стоит куда больше дюжины незаконченных на С++.

Если код логики пожух и уже сил нет хочется переписать, то может быть какое-то зерно тут и есть, благо 10к строк это еще не катастрофа. Но если у текущей архитектуры все еще впереди, раскатывать ее бульдозером ради FPS сомнительная затея. Зависимость от .NET/Mono уже не проблема, они максимум на расстоянии репозитория, а чаще уже стоят из коробки. Если не нравится XNA и морально готов к лоу-левел графике, возьми OpenTK (тонкая обертка над OpenGL/OpenAL, ссылка), он кроссплатформеннен и без лишних зависимостей.
Пытается раскуклиться

Аватара пользователя
Oreyn
Сообщения: 297
Зарегистрирован: 07 авг 2013, 14:59

Re: jarg

Сообщение Oreyn » 14 окт 2014, 12:31

Сам использую вариант чем-то близкий к 2. Только работу с тегами собрал в отдельный класс который включается в наследование, чтобы можно было функциями класса HasTag AddTag RemoveTag получать что нужно.

Подумай над тем как ты будешь реализовывать приоритет обработки таких флагов функционала.
Если у тебя есть ключ "печка" и ключ "замок" как дать понять, что пока не открыт замок недоступна печка.

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

Re: jarg

Сообщение Cfyz » 14 окт 2014, 13:28

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

Я думаю лучше всего взять понемногу из каждого. Из #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();
    }
}
Этот блок-компонент PrimitiveAI можно навесить на сундук. Потом добавить сундуку компонент Fear и тем самым заставить его шарахаться от каких-нибудь крыс и рандомно ходить иначе. Потом, если будет добавлен NotSoPrimitiveAI, который не просто шарахается в стороны, но аккуратно обходит по дуге, достаточно заменить название компоненты в конфиге монстра.

Т. е. я конечно немного ударился в то, как я сам предполагаю делать :D я пока ничего точно не знаю, только собираюсь игру писать.
Пытается раскуклиться

Аватара пользователя
Oreyn
Сообщения: 297
Зарегистрирован: 07 авг 2013, 14:59

Re: jarg

Сообщение Oreyn » 16 окт 2014, 05:23

ishellstrike писал(а):Предлагаю обсудить представление игровых объектов

Хотелось бы услышать ваше мнение по этому поводу.
Тут еще такой нюанс. Ты из академического интереса хочешь сделать супер модульный роглайк движок или больше по прикладному игру написать?
Если второе, лучше сразу делать прототип и испытывать его. Чем больше понимаешь реальный востребованный объем этих модульных фич - тем ближе от идеальной теории до работающей практики.

Представь что после большого объема труда по разработке и реализации "идеальной модульной концепции" твои АИ монстра вместо супер-реалистичного поведения топчется на двух тайлах. Потому что на дальнем тайле ему хочется преследовать противника, а на ближнем тайле он боится костра. И более простая логика на конечном автомате "охота->преследование->побег" дает лучший результат. А из всех пересечений модульности в объектах у тебя "дверь" и "замок" как максимум, хотя движок позволяет туда еще с десяток впихнуть и то пришлось еще костылями их подпереть, потому что там нужен еще был вот такой нюанс практический или же вставлять проверки на существование конкретного модуля во все остальные, чтобы он корректно работал. И тогда это сложно уже модульностью то назвать. Печалька? Столько труда на смарку пойдет.

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

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

Re: jarg

Сообщение Cfyz » 16 окт 2014, 16:23

Хотя вопрос был не ко мне, прокомментирую касаемо компонентного подхода к реализации объектов.

То, что я писал выше -- это адаптация описанного в Evolve Your Hierarchy. Проблема простой логики из хардкода и проверок флагов в том, что она слабо поддается модификации (что, по-моему, одна из отличительных особенностей разработки roguelike), суровое наследование, к слову, тоже обычно не очень хорошо себя показывает. Игровые объекты -- это обычно не сплошные монолиты с раз и навсегда предопределенным поведением, а достаточно пестрый набор из различных аспектов игровой механики. Причем изменения в механие затрагивают разные части разных объектов, из-за чего одна иерархия просто не работает. Компонентный подход, по идее, позволяет выделить эти самые аспекты -- способ передвижения, форма и содержание, визуальное представление, AI, модификаторы и т. д. -- и структурировать их максимально независимо. Ну и плюшки выноса сборки в рантайм и упрощения сериализации тоже стоит иметь в виду.
Oreyn писал(а):Представь что после большого объема труда по разработке и реализации "идеальной модульной концепции" твои АИ монстра вместо супер-реалистичного поведения топчется на двух тайлах. Потому что на дальнем тайле ему хочется преследовать противника, а на ближнем тайле он боится костра.
Ну само собой, нужно не перегибать палку. Если раздробить аспекты механики обратно до бинарных флагов, то ничего хорошего не получится. Идея AI-компонента в том, что его-то как раз может быть иерархия классов (так как, вероятно, у разных реализаций AI все равно будет много общего). Зато не придется грузить базовый класс монстра всеми мыслимыми вариантами поведения ради возможных mind control или maddness, которые меняют логику AI полностью.
Oreyn писал(а):потому что там нужен еще был вот такой нюанс практический или же вставлять проверки на существование конкретного модуля во все остальные
Ну и тут примерно то же самое. Ключевых типов модулей должно быть немного, но могут быть чрезвычайно легковесные компоненты-метки типа "травматическая боязнь того-то" или "предрасположенность к этому-то". Которые сами не несут особой логики, но имеют состояние (читай -- переменные) и могут быть (а могут и не быть) учтены другими компонентами. Это, конечно, можно было бы выделить в отдельную сущность со своим интерфейсом, но если вся инфраструктура и так поддерживает необходимые операции, то зачем?
Пытается раскуклиться

Аватара пользователя
Феникc
Сообщения: 679
Зарегистрирован: 27 ноя 2010, 15:01
Откуда: Челябинск

Re: jarg

Сообщение Феникc » 16 окт 2014, 17:55

Насчёт компонентного подхода, BTW, могу порекомендовать подход Юнити - присмотреться к нему, во всяком случае, стоит.
Подход этот заключается в том, что игровой объект имеет один обязательный компонент (Transform, позиция/поворот/скейл) и до черта всяческих опциональных (рендерер, столкновениекоробка, партиклы et cetera, et cetera). При этом сам код поведения тоже аттачится к объекту по принципу "один класс - один компонент".
Учитывая популярность Юнити, такая структура, очевидно, вполне себе жизнеспособна, обладая достаточной гибкостью и при этом не превращаясь в слабосвязанную кашу с плавающими в ней кусочками кода.
Всё вышесказанное - ИМХО, если не указано обратное.

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

Re: jarg

Сообщение Jesus05 » 27 фев 2015, 12:07

Всегда приятно слышать новости о проекте. любые!

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

Re: jarg

Сообщение Jesus05 » 28 янв 2016, 12:36

Вот это бы еще заменить на события.

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

    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);
а в дальнейшем вообще вынести этот набор параметров в класс Event и сделать

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

virtual void onEvent(Event &ev);

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

Re: jarg

Сообщение Jesus05 » 28 янв 2016, 13:19

ishellstrike писал(а):Думаешь разбор

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

void onEvent(Event &e) {
  switch(e.type) {
    case EVENT_SOME: ...
}}
будет удобнее? Если уж делать универсальные события, то, вероятно, надо делать какую-то подписку на них. Типа шины событий
...
Мне кажется так удобнее будет добавлять новые события при необходимости.
А если придумать систему непересекающихся номеров событий, тогда классы наследники смогут пользоваться какой-нить группой событий о который родитель вообще ничего не знает.

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

Re: jarg

Сообщение Jesus05 » 28 янв 2016, 14:24

Для размышлений... в 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

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

ERROR = sysEventID('A', 'T', 'E'),
PROGRESS = sysEventID('A', 'T', 'P'),
COMPLETE = sysEventID('A', 'T', 'C')
https://github.com/oxygine/oxygine-fram ... rc/Input.h

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

 event_platform = sysEventID('I', 'P', 'L')
https://github.com/oxygine/oxygine-fram ... KeyEvent.h

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

KEY_DOWN = sysEventID('K', 'E', 'D'),
KEY_UP = sysEventID('K', 'E', 'U')
https://github.com/oxygine/oxygine-fram ... gressBar.h

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

PROGRESS_CHANGED = sysEventID('P', 'C', 'h')
https://github.com/oxygine/oxygine-fram ... uchEvent.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')

Ответить

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

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