• Использование вариативного шаблона функции без аргументов?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Смотри... Т.к. в предложенном коде я уже вижу немного бардака, то и вариант предлагаю слегка бардачный. :)
    Эту задачу можно решить сразу несколькими способами метапрограммирования. Предложенное решение - одно из них.
    template< typename TComponentType >
    bool HasComponent()
    {
    	return ...;
    };
    
    template< typename... TComponentTypes >
    bool HasComponents()
    {
    	// Это тип предиката для проверки наличия одного компонента.
    	using CheckingPred	= bool (*)();
    	
    	// Это тип листа проверки.
    	using PredList		= std::array<CheckingPred, sizeof...( TComponentTypes )>;
    	
    	// Определяем лист проверки, следи за руками... :-)
    	PredList predicates{{ HasComponent<TComponentTypes>... }};
    	
    	// Проверяем!
    	return std::all_of( predicates.begin(), predicates.end(), []( CheckingPred stored_pred ) -> bool { return stored_pred(); } );
    };


    Сразу заостряю внимание на форматировании и стиле. Так сказать, что понятнее и удобнее читается? :)

    UPD:
    Еще предлагаю полистать библиотеку одного интересного товарища: https://github.com/alecthomas/entityx
    Как я понимаю, тебе хочется попробовать реализовать ECS. EntityX - одна из самых прямых ECS библиотек на плюсах, если не сказать - самая прямая.
    Ответ написан
  • Как избавиться от привычки усложнять задачу?

    @MarkusD
    все время мелю чепуху :)
    Лично мне было бы интересно послушать подробности. В данной трактовке вопрос очень сложен из-за своей расплывчатости. :)
    Конкретнее! Нужна иллюстрация хода мыслей и критерии, по которым у тебя создается ощущение усложнения задачи.
    Так же очень важно понять, сам ты замечаешь усложнение или же тебе говорят об этом.
    Александр Синицын , дополни свой вопрос.

    Нередко в неадекватном усложнении задачи обвиняют именно те "соратники", кому попросту непонятна ни сама задача, ни ход твоих мыслей. Как правило это результат эффекта Даннинга-Крюгера.
    Ответ написан
    2 комментария
  • Как построить наименьшую траекторию перемещения по клеткам, имея возможность переставлять препятствия?

    @MarkusD
    все время мелю чепуху :)
    Ответ относится к стандартным алгоритмам поиска пути.

    Литература:
    algolist.manual.ru/games/wavealg.php
    algolist.manual.ru/games/smartmove.php
    www.gamedev.ru/code/articles/?id=4246

    Любой алгоритм удачно усложняется за счет использования потенциальных полей.
    https://habrahabr.ru/post/262181/
    Ответ написан
    7 комментариев
  • Как посмотреть результат работы линкера?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Для этих целей есть целый набор утилит. Всякие пакеты для разработки обычно кладут эти инструменты рядом с GCC.
    Вот, первое что вспомнилось: https://sourceware.org/binutils/docs/binutils/objd...
    Думаю, даже если это не то, то там ты найдешь нужный тебе инструмент.
    Ответ написан
    Комментировать
  • Как получил указатель на экзепляробъекта?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Это называется категориями значений.

    Литературка для чтения.
    en.cppreference.com/w/cpp/language/value_category

    Коротко.
    Объявление типа `int` - тип с хранением по значению.
    Объявление типа `int*` - тип с хранением по указателю.
    Объявление типа `int&` - тип с хранением по ссылке.

    Любая из этих форм записи типа может быть использована для определения переменных, параметров и результатов функций.

    for (auto card : hand)
    Говорит что card принимается по значению через копирование содержимого итератора. Время жизни card ограничено пространством цикла.

    for (auto& card : hand)
    Говорит что card принимается по ссылке содержимого итератора.
    Ответ написан
  • Какие есть движки для пиксельных платформеров?

    @MarkusD
    все время мелю чепуху :)
    К списку xmoonlight еще добавляю (все движки позволяют создавать игры с применением Lua):
    1. Defold
    2. MOAI
    3. Urho 3D
    4. Anki 3D
    5. Cocos2d-x
    Ответ написан
    Комментировать
  • Почему pip не хочет обновляться?

    @MarkusD
    все время мелю чепуху :)
    Самая последняя строка говорит тебе что лучше сделать.
    python -m pip install --upgrade pip

    Т.к. ты используешь две версии питона на машине под виндой, советую обновлять pip немного подругому.
    py -3 -m pip install --upgrade pip

    Команда "py" устанавливается в системную директорию ОС и является приложением Python version checker.
    Благодаря ней ты можешь запускать питон нужной версии (py -2 или py -3).

    Аналогично команде "py", команду "pip" тоже можно запустить строго для нужной версии питона. По умолчанию имя pip относится только к питону 2й версии. Если тебе надо использовать именно pip 3й версии питона, то вызывать его надо через "pip3".

    Можно вот так:
    pip3 install Django==1.10.3

    А можно и вот так:
    py -3 -m pip install Django==1.10.3
    Ответ написан
    6 комментариев
  • Какой способ организации чтения и записи файлов в разных форматах оптимальнее?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Мы используем Flatbuffers. :)
    Документация присутствует.
    Эта штука и версионирование данных поддерживает, при соблюдении некоторых условий.
    Ответ написан
  • Какими приёмами вы пользуетесь чтобы различать указатели, которые нужно освобождать, от указателей, которыми нужно только пользоваться?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    pixik , витиеватый, очень размытый вопрос. Что же тебя все-таки интересует? Как другие люди организуют схемы владения? Или каким образом лучше организовать удаление объекта при разделенном владении.
    Тебе суть вопроса, скорее всего, понятна. Но это лишь потому что у тебя есть контекст этого вопроса, а у всех остальных его нет и он явно не создается.

    Так вот.
    Если один объект (A) безраздельно владеет другим (B), то второму положено быть частью первого. Так просто легче жить.
    Если вторым (B) является указатель, то в первом (A) используется std::unique_ptr опять-же для упрощения себе жизни.
    При этом, вложенный объект (B) из родительского отдается по голому указателю. Ну да, это норма, хоть мои слова и встретят бурю негодования нетерпеливых читателей.
    В это же самое время появляется риск схлопотать AV/SEGV когда для голого указателя (B) появляются клиенты (C), время жизни которых значительно больше времени жизни (A). Все просто, (A) живет меньше семейства (C), следовательно сохраненный в (C) голый указатель на (B) обязательно приведет к AV/SEGV после окончания времени жизни (A).

    Вот, проблема оглашена. Решаем.

    Решение первое: std::shared_ptr и std::weak_ptr.
    std::shared_ptr является примитивом разделения владения. Будем хранить (B) внутри него. А наружу (A) будет отдавать st::weak_ptr с указателем на (B). Клиенты семейства (C) будут держать (B) внутри сохраненных std::weak_ptr. Таким образом все семейство (С) всегда будет защищено от обращения к удаленному (B).

    Решение второе: два std::sared_ptr.
    Ну мало ли... Я знаю несколько случаев когда именно такая схема является максимально эффективной. В частности, бывает необходимо сделать именно разделенное владение внутри всего семейства (C), давая информацию для (A) о нужности оставлять (B) в живых. Пулы, кеши по владению, мало ли таких задач...
    Эта схема достаточно сложна и требует содержать std::weak_ptr на каждый внешний std::shared_ptr для обеспечения правильной работы схемы.
    Решение сводится к тому, чтобы уже имеющийся std::shared_ptr обернуть в другой с заменой деконструктора.
    (A) отдает (B) через std::shared_ptr, но в момент запроса (A) оборачивает реальный std::shared_ptr (B) в новый, используя голый указатель на (B) и свой сторонний деконструктор. Внутри этого стороннего деконструктора делаются все нужные манипуляции над (B). Этот сторонний деконструктор вызовется тогда, когда все семейство (C) избавится от ссылки на (B).

    Решение третье: когда (A) сам лежит внутри std::shared_ptr и унаследован от std::enable_shared_from_this.
    Тут все просто, для выдачи (B) из (A) можно использовать делегируемый std::shared_ptr, который сконструирован из указателя на (B) и std::shared_ptr (A) полученного из функции shared_from_this().
    В этом случае (A) не помрет до тех пор, пока семейство (C) не отпустит (B).

    Как видишь, корень твоего вопроса решается всеми тремя способами. На самом деле способов еще больше, но самое важное что все способы дают стандартное решение. Велосипеды в этом вопросе - это от неграмотности.

    Советую максимально подробно изучить раздел управления памятью в STL: en.cppreference.com/w/cpp/memory

    Принимаю вопросы и уточнения. :)
    Ответ написан
  • Как лучше организовать многопоточную архитектуру?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Смотри, прямо готового монолитного шаблона пожалуй нет (точнее, я со своего опыта такой не нахожу).
    По описанию видно что можно использовать Thread pool + Proactor + Actor model.
    Вместо потока на девайс будет пул потоков + управляющий поток, т.е. семейства потоков только два. Каждый девайс - актор. Действия актора выполняются атомарно в необходимом потоке (главный/сервисный) благодаря планированию нужного обработчика для нужного потока.

    Вот, подкину литературку:
    www.gamedev.ru/code/articles/concurrency_models
    https://habrahabr.ru/users/eao197/topics/ - SObjectizer является довольно интересной библиотекой.

    И, да, Александр Таратин прав, твою задачу можно так же решить, возможно и с большим успехом, выделив сервис каждого девайса в отдельный рабочий процесс. При этом связь управляющего процесса с рабочими легко и эффективно организуется через обмен сообщениями.
    А вот и ссылка на библиотеку обмена сообщениями - ZeroMQ.
    Ответ написан
  • С++: Вызов различных конструкторов в зависимости от пользовательского ввода?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Итак, ссылки потеме:
    en.cppreference.com/w/cpp/language/copy_elision - буквально, используя стандартные языковые средства мы буквально избегаем конструктора копирования и оператора присвоения. Заострять внимание на RVO и NRVO.
    en.cppreference.com/w/cpp/utility/move - семантика перемещения. Поддержи ее в своем классе для конструктора и оператора присвоения.

    Для перемещения даже твой сферически условный код не надо будет править.
    Хотя... тут в целом, даже при использовании copy elision этот код не надо править.

    Да и вообще. Оптимизаторы ведущих (CL, ICC, GCC, Clang) компиляторов уже достаточно умные чтобы избавить тебя от головной боли по этому вопросу именно в этом конкретном месте. В результате программа сконструирует объект правильным конструктором в правильном месте, а конструктор по умолчанию и оператор присвоения - выкинет на мороз.
    Ответ написан
    3 комментария
  • Как обойтись без библиотеки импорта?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Библиотека импорта для dll - это вспомогательный артефакт связывания основного образа программы с динамическим модулем.
    В общем - никак, раз уж явную загрузку тебе не предлагать. :)

    Иное дело - это твои хитромудреные манипуляции для установления зависимости между основным и динамическими модулями. Зачем тебе потребовалось явно указывать линковку с lib файлом?
    У каждого проекта студии есть список зависимостей (References). Если в проекте главного модуля программы установить зависимость от проекта динамической библиотеки, то msbuild все свяжет за тебя.

    А еще есть нестандартная но широко поддерживаемая #pragma comment(lib,"xxx.lib").
    Ответ написан
    Комментировать
  • Учитывается ли тип значения, возвращаемого функцией, в решении о выборе нужной версии перегруженной функции?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Стандартом продиктовано что функции могут перегружаться только параметрами.
    eel.is/c++draft/over#2

    В то же время, стандартом описано что функция не может быть перегружена только лишь изменением возвращаемого значения.
    eel.is/c++draft/over.load#2

    А вот пояснения зарыты глубоко в 13м параграфе стандарта и отрыть их там наскоро не выйдет.
    eel.is/c++draft/#over
    И дело там не только в неявных приведениях типа. Проблем с разрешением перегрузки или инстанциирования шаблона только по возвращаемому значению выше крыши.
    Ответ написан
    Комментировать
  • Как упаковать текстуры в libGDX?

    @MarkusD
    все время мелю чепуху :)
    Андрей, у тебя вопрос, как видно по тексту, немного о другом. По описанию видно что ты перед собой стену видишь, а про дверь в стене даже не подозреваешь. Итак, вот дверь, даже несколько. :)

    Первое - надо понять, насколько много графики у тебя в проекте. Для современного mid-end устройства на андроиде 5.0 совсем не проблема держать 2-4 RGBA текстуры с разрешением 4096 по ребру. Это не говоря о сопутствующих шейдерах, буферах растра/глубины/вершин/индексов. Минимализм в ресурсах приветствуется, но и зажимать себя в тески не стоит.

    Второе - давай взглянем на параграф "Open GL Version" странички https://developer.android.com/about/dashboards/ind...
    OpenGL 3.x занимает большую долю всех устройств. Эта версия OpenGL умеет работать с форматом ETC2 (благодаря заявленной поддержке от GPU), в котором уже можно сохранять альфу. А в вики ( https://en.wikipedia.org/wiki/Ericsson_Texture_Com... ) еще и написано про обратную совместимость.
    Тут в моем опыте пробел, с ETC2 я еще не работал и наглядно про обратную совместимость с ETC1 ничего не знаю. Поэтому предлагаю устроить обмен знаниями в этой теме. :)

    Третье - Аппаратно-поддерживаемых форматов сжатия текстур на самом деле много: S3TC, ATC, PVR-TC. ETC - не единственный. Каждый из форматов поддерживается своим производителем. ATC - Quallcomm; PVR-TC - Imagination Tec. Но вот S3TC (более известный как DXT3/DXT5) поддерживается обоими QC и ImgTec, но тайно. И только ARM Mali поддерживает один лишь формат ETC.
    К чему я это. Тройка профильных форматов и альфу поддерживает, и обрабатывается быстрее того же ETC (и уж тем боле пары ETC1).
    Поэтому может тебе удобнее будет использовать конвертацию в эту тройку форматов?
    У меня на гитхабе есть очень быстрая библиотека для программного чтения PVR-TC.v2 в RGBA буфер, что позволит загрузить текстуры для Mali GPU.
    Ответ написан
    3 комментария
  • Что такое compileSdkVersion и targetSdkVersion?

    @MarkusD
    все время мелю чепуху :)
    Версии Android API обратно совместимы в определенных пределах. Это буквально означает что можно собрать приложение для Android 4.4.2 (targetSdkVersion == 19) используя Android API с версией 22 (compileSdkVersion == 22). При этом, на твои руки полностью ложится ответственность за предотвращение вызовов новых функций из Android 5.1.1 на более древних платформах. Иначе приложение упадет, автозатычек ни кто не предоставляет.
    Поэтому, да, можно пользоваться свежими версиями Android API для сборки под старые версии ОС Android.

    Относительно предупреждений о разных версиях, у тебя compileSdkVersion указана строго, а вот пакет "com.android.support" имеет гибкую зависимость на повышение версии. Скорее всего ты уже закачал свежие API для Android 5/6, из которых теперь и берется пакет "com.android.support" при сборке.
    Ответ написан
    Комментировать
  • Какие задачи на C / C++ сейчас востребованы?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Понимаешь, практика показывает, что востребованным может стать абсолютно любая библиотека. Особенно если ты берешь на себя ответственность ее поддержки.
    Людей много, задачи они порождают все время и самые разные. Зачастую, количество потребностей в коде у человека превышает возможности его создания и поддержки. И фактор нехватки ресурсов (времени/рук) чаще всего играет решающую роль в отказе от идеи.

    К тому же, у художников вот есть такие места, как deviantart.com / cghub.com (был), где они выкладывают свои работы, по которым видно их рост и общий стаж в ремесле. Я считаю что и у разработчика тоже можно проследить тенденцию роста по его проектам на гитхабе, а по открытым доскам на trello.com можно еще и проследить уровень самоорганизации человека.

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

    @MarkusD
    все время мелю чепуху :)
    Уж не карту ли для EVE Online ты решил своими руками сделать? Все предпосылки, включая картинку, говорят об этом. :)

    Любой алгоритм поиска пути тебе в помощь. Смотри в сторону A*, его реализация существует, наверное, даже на бреинфаке, поэтому код попросту неуместен.

    Поиск маршрута делается один раз для самого безопасного маршрута и еще один раз для самого короткого.
    В первом случае весовым коэффициентом узла будет сек-уровень звезды. Эвристика - средний сек-уровень на число прыжков до цели.
    Во втором случае весом будет уже число самих прыжков, а эвристику надо будет считать из числа прыжков до цели.
    Ответ написан
    1 комментарий
  • Деление игры на GameState'ы: как?

    @MarkusD
    все время мелю чепуху :)
    ps. Тут на Phaser.js кто-нибудь пишет, есть смысл вопросы по нему задавать?

    Это не форум, тут формат общения - вопрос-ответ. Один вопрос от тебя и много ответов от других.
    Пиши с тегом javascript или phaser-js и тебе наверное ответят.

    По поводу организации: как душе будет угодно. Но лучше все таки подойти к вопросу аналитически.
    Как у тебя сменяются уровни? Ширма между сценами есть?
    Если есть, то геймплей удобнее сделать двумя стадиями - стадией сцены игры и стадией ширмы. Если ширмы нет и геймплей не прерывается между уровнями, то лучше его оформить одной стадией.

    Вот мой ответ: Подходи к вопросу аналитически, пойми что для твоей структуры геймплея будет удобнее. Информации ты никакой по своему вопросу не дал, так что и ответов внятных вряд ли можно ждать. Асам вопрос очень прост.
    Ответ написан
    Комментировать
  • Как решить эту задачу без «подбора» значений?

    @MarkusD
    все время мелю чепуху :)
    Легко. Но для этого на циферблат надо посмотреть под разными углами.

    Сперва давай поглядим на него как на арифметическую прогрессию. А1 == 1; А12 == 12; D == 1.
    Формула суммы прогрессии: S = (A1 + An) * n / 2;

    Вычисляем сумму нашего ряда, она равна 78. И дальше все становится очень просто.

    Теперь давай посмотрим на циферблат как на циферблат. У него 12 значений, связанных в кольцо.
    Проведя линию и поделив циферблат на две части, мы как бы создаем две области арифметических прогрессий.
    При чем сумма сумм этих прогрессий будет равна той сумме, что мы уже посчитали.
    Стало быть, нам достаточно найти такой участок на циферблате, сумма чисел которого была бы равна ровно 39 - половине уже рассчитанной сверху суммы. Иначе условие задачи не выполнить.

    Выходит так, что элементов в искомой последовательности у нас становится не 12, а 6. D тот же, а вот A1 и A6 у нас неизвестные. Найти их можно через все ту же формулу суммы.

    39 == (A1 + A6) * 6/2
    13 == A1 + A6
    A6 == A1 + D*5
    13 == 2*A1 + 5
    8 == 2*A1
    A1 == 4
    A6 == 4 + 5 == 9

    Всё. Первая группа - это [4..9], вторая - это [1..3,10..12], суммы обеих последовательностей будут равны 39, а вместе - 78.

    UPD:
    Почему именно 6 элементов... Смотрим.

    Для множества циферблата сумма такова:
    78 == ( 1 + 12 ) * 12 / 2

    Для подмножества должна выполняться такая сумма:
    39 == ( 2A1 + N - 1 ) * N / 2

    Определим N из тожественного равенства двух сумм с поправкой что от первой нам надо только половину.
    ( 1 + 12 ) * 12 / 4 == ( 2A1 + N - 1 ) * N / 2

    Замечаем тождественность составляющих выражения и теперь рассмотрим это равенство как систему уравнений:
    1 + 12 == 2A1 + N - 1
    12 / 4 == N / 2

    Вуаля!
    N == 6; а из первого равенства очень легко вывести A1, который равен 4.
    Ответ написан
  • Как бы вы реализовали принятие решений программой в pick'n'point игре?

    @MarkusD
    все время мелю чепуху :)
    Классами это все решать - это бросок самого себя через свое бедро... Убьешься, в общем.

    Читай Шампандара, тебе нужен раздел деревьев поведения (Behavour Tree) и планировщика решений (Goal Planning).
    Любое действие игрока - это триггер. Скапливаясь, или каждый сам по себе, триггеры влияют на внутреннюю память автомата. Автомат просто выполняет то действие, которое соответствует его текущей внутренней памяти.
    Описание автомата лучше всего делать на скриптовом языке (LUA/Python embedded).
    Каждый уровень - это лишь описание автомата в скрипте.
    Сами действия. Куда то перейти итд... Это уже смотря как твоя сцена сделана. Это можно сделать как жесткой анимацией с именем (которую будет запускать автомат), так и с помощью подсистемы AI (в которую и будет отдавать указания все тот же автомат).

    С такой организацией ты себе гору времени и нервов убережешь.
    Ответ написан
    1 комментарий