Какую версию code blocks. Использование собственного makefile для своего проекта. Поиск и устранение неисправностей

Вайбер на компьютер 14.04.2019
Вайбер на компьютер

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

Однако не обязательно экономить таким способом, который, в общем-то, нельзя назвать совсем уж законным. Можно вместо такого мошенничества с коммерческим программным обеспечением пользоваться бесплатными программами. Стойте, не надо плеваться! Я понимаю, всё, что не похоже на любимые Microsoft Visual Studio и/или Delphi, вызывает поначалу у многих раздражение даже при простом упоминании. И тому есть логичное объяснение: большая часть бесплатного софта для программистов (особенно это касается сред разработки) даже при первом запуске вызывает одно из двух не самых лучших человеческих чувств: либо омерзение, либо скуку. Иногда - глубокую и искреннюю жалость. Однако, заметьте, большая часть - это далеко не весь софт! Как правило, самые известные из freeware и open-source продуктов действительно заслуживают внимания и разработчиков, и их руководства. Достаточно вспомнить такие проекты, как Eclipse или Dev-C++. Да и многие другие тоже. На самом деле не зря же к движению open-source присоединяются всё новые участники. Всё больше продуктов, бывших когда-то коммерческими, набирают обороты как свободные проекты. Хотя и те продукты, которые и начинались как open-source, тоже через некоторое время становятся вполне конкурентоспособными относительно коммерческих аналогов. Хотя, стоит отметить, что не всегда термин open-source синонимичен термину "свободная программа". Хотя, как правило, open-source программы распространяются под лицензиями, позволяющими пользоваться ими без каких бы то ни было отчислений разработчикам.

Среда разработки, с которой я сейчас хочу вас познакомить, как раз из тех замечательных продуктов, которые вызывают интерес, а местами даже и восхищение. Называется эта программа, как видно из заголовка статьи, Code::Blocks, а в интернете её можно найти по адресу www.codeblocks.org . Предназначена она для разработки программ с использованием C/C++. Размер закачки зависит от того, будете ли вы скачивать среду вместе с компилятором или же без него. Также зависит это ещё и от того, будете ли вы скачивать исходные тексты IDE (а они имеются в наличии, поскольку распространяется Code::Blocks под Генеральной общественной лицензией GNU), либо уже скомпилированные файлы. В целом же, объём закачки варьируется от трёх до тринадцати мегабайтов, что на самом-то деле не так уж и много для хорошей среды разработки.

Итак, среда установлена. При первом запуске глаз радует красиво выполненный экран приветствия, который обычно не характерен для свободных программных продуктов. Уже по нему можно судить о серьёзности подхода авторов Code::Blocks к разработке своего детища.

Что готова среда разработки предложить программисту, который её использует? Не так уж и мало, особенно если сравнить с некоторыми другими бесплатными IDE. Во-первых, кросс-платформенность. Однако она ограничена двумя платформами: Windows и Linux. Не очень много, однако это основные операционные системы на рынке. Впрочем, поддержка некоторых других (например, Mac OS X) всё равно не помешала бы. Лично я скачивал версию для Windows, однако, судя по скриншотам на сайте разработчиков, под Linux эта программа выглядит ничуть не хуже.

Во-вторых, каждый может подключить к среде тот компилятор, который ему/ей больше нравится. Или тот, который привычнее использовать. А компиляторы среда разработки поддерживает такие: GCC (MinGW для Windows), Microsoft Visual C++ Compiler, Digital Mars, Borland C++ (версии 5.5), Open Watcom и Sun DCC. В случае если вы скачали среду вместе с компилятором, то им будет, конечно же, GCC. Среда сама передаёт компилятору все ключи, необходимые для его работы с заданными опциями. Причём компиляция может осуществляться как напрямую, так и через make-файлы, которые Code::Blocks также умеет формировать совершенно самостоятельно.

В-третьих, в Code::Blocks имеется удобный и многофункциональный редактор кода, поддерживающий подсветку синтаксиса и фолдинг (сворачивание) блоков кода. Причём работать среда умеет не только с текстами на C/C++, но и с XML-файлами. Слева в окне программы находится проводник по классам, использующимся в её тексте, а также список всех используемых переменных, констант, классов и пространств имён. Там же имеется дерево ресурсов и список просматриваемых во время отладки переменных. Что приятно, так это то, что каждый открытый файл в среде имеет свою вкладку. Это удобный подход, и просто замечательно, что он начинает использоваться во всё большем числе сред разработки.

В-четвёртых, среда Code::Blocks поддерживает подключаемые модули, то есть плагины. Это действительно полезная возможность и с её помощью разработчики реализовали несколько удобных для программиста, использующего Code::Blocks, вещей. И главная из этих вещей - это, конечно, подсказки, возникающие на экране по ходу набора кода и содержащие списки методов классов и параметров методов или функций. Реализована эта возможность, на мой взгляд, не хуже, чем во многих коммерческих средах разработки. Среди других плагинов, которыми может похвастаться сайт проекта Code::Blocks, стоит, как мне кажется, вспомнить мастер форматирования кода, мастер создания новых классов, подсчёт статистики по исходному коду проекта и мастер внедрения XP Manifest в ресурсы проекта. Если вы, как и я, скачали самую большую версию Code::Blocks (ту, которая с компилятором), то у вас эти все плагины уже есть. Естественно, каждый желающий может создать собственный плагин к среде разработки. Для этого нужно будет скачать специальный SDK (Software Development Kit - набор для разработки программного обеспечения) с сайта проекта.

В качестве отладчика среда использует GNU Debugger. Работа с ним практически не отличается от работы с отладчиками сред Microsoft и Borland. Также в среде имеется поддержка списка тех вещей, которые разработчик должен сделать в приложении (to-do list). Его можно настроить таким образом, что если средой пользуется несколько разработчиков, для каждого из них он будет собственным и независимым от списков других разработчиков. Также в среде удобно работать с проектами. Они, как и в Microsoft Visual Studio, отделены от настроек рабочего пространства (workspace), и, что приятно, и проекты, и workspace"ы среда умеет импортировать из формата Visual Studio. Проекты, кстати, можно импортировать и из формата Dev-C++. Правда, эти возможности описаны чисто теоретически самими разработчиками IDE, и сам я о них ничего сказать не могу, поскольку сам их не пробовал в действии.

Есть у Code::Blocks ещё одна важная особенность, выделяющая его среди многих других сред разработки. Эта среда имеет тесную интеграцию с библиотекой wxWidgets, предназначенной для создания графического пользовательского интерфейса (когда-то я уже писал о ней в "Компьютерных вестях"). Библиотека эта имеет множество достоинств, и потому разработчики Code::Blocks сделали прекрасный стратегический ход, ориентировав свой продукт на работу с этой замечательной библиотекой. Правда, реализовано это, опять-таки, с помощью плагина, который называется wxSmith, но это уже не самые значительные детали. Плагин позволяет производить разработку интерфейса приложения в визуальном режиме, что не может не быть оценено разработчиками. Особенно теми, кто пробовал создавать интерфейс в невизуальном режиме. Режим редактирования похож на аналогичный из Microsoft Visual C++ или Borland C++ Builder. Похожий дизайнер, похожий редактор свойств объектов. Учитывая кросс-платформенность wxWidgets и Code::Blocks, это совершенно замечательная возможность.

Что ж, вот такая хорошая и полезная среда разработки по имени Code::Blocks. Возможно, многие скажут, что ей далеко до Visual Studio или Borland Developer Studio, и будут, конечно, правы. В ней нет, как в современных версиях этих коммерческих сред, возможности разработки приложений на многих языках и разработки для платформы.NET. Однако эта среда намного легковеснее и компактнее, чем монстры от Microsoft и Borland. Кроме того, для создания кросс-платформенных приложений для Windows и Linux связка Code::Blocks и wxWidgets представляется едва ли не одним из лучших среди всех возможных вариантов. Поэтому не стоит сразу отворачиваться от свободного программного обеспечения. Лучше сначала попробовать, а потом уже решать, отворачиваться или нет. Прописные истины? Может быть. Но ведь чем банальнее утверждение, тем сложнее до него дойти отдельно взятому человеку.

Вадим СТАНКЕВИЧ

Разработка приложений для встраиваемых устройств

Часть 2. Применение Code::Blocks для разработки AVR-приложений

Серия контента:

В предыдущей статье мы рассказали, как с помощью среды разработки Eclipse создавать приложения для микропроцессоров серии AVR фирмы Atmel с использованием комплекта компиляторов GNU AVR GCC. Рассматривалась настройка Eclipse с использованием подключаемого модуля AVR Plugin, а также ручная настройка среды. Сейчас мы покажем, как такую же задачу можно решить с помощью другой, более легкой и очень удобной среды разработки Code::Blocks.

Знакомство со средой

Создание проекта

Если еще ни одного проекта в рабочем пространстве не создано, то после запуска Code::Blocks в центральной панели активна только вкладка «Start here». Для создания нового проекта нужно выбрать команду «Create a new project» или пункт меню «File->New->Project». В любом случае откроется окно выбора шаблона будущего проекта, в котором мы указываем шаблон «AVR Project» и нажимаем кнопку «Go».

Появится приветственное окно мастера создания AVR-проекта. Нажмите кнопку «Next» и в открывшемся диалоговом окне введите название проекта и каталог, в котором он будет находиться. На основании этих данных программа автоматически предложит пользователю имя файла проекта с расширением *.cbp и каталог проекта, который будет создан. Далее следует нажать кнопку «Next».

В следующем окне предлагается выбрать конфигурации сборки, которые будут использоваться в проекте. По умолчанию активны обе конфигурации: Debug и Release. Компилятор «GNU AVR GCC Compiler» указан заранее. Также здесь можно изменить стандартные каталоги для скомпилированных файлов конфигураций.

В следующем окне мы указываем тип целевого процессора, выбрав его из выпадающего списка (позже это можно сделать в параметрах компиляции). Если в проекте используется внешняя память, стоит указать ее параметры. Далее следует задать значение глобальной переменной проекта F_CPU, указав тактовую частоту процессора в герцах. По умолчанию включено создание файла карты символов (.map) и hex-файлов, а также файла дизассемблерного листинга (.lss). Еще полезно включить параметр «Run avr-size after build» – тогда в конце журнала сборки проекта появится информация о том, сколько места будет занято в памяти программ и в оперативной памяти. По какой-то причине включение параметра создания листинга не оказывает никакого действия при создании проекта, и нужно вручную добавить соответствующую команду в «Pre/post build steps». Нажмите кнопку «Finish» (рисунок 2).


Проект создан, и в него автоматически добавлен первый файл – main.c.

Настройка проекта и среды разработки

Если проект создан с помощью шаблона AVR-проекта, то практически сразу можно перейти к программированию. Тем не менее, мы пройдемся по основным параметрам, чтобы убедиться, что все настроено правильно.

  1. Выберите пункт меню «Project->Build options». Откроется окно настроек параметров сборки (рисунок 3). В левой панели находится дерево целей сборки. На самом верхнем его уровне – настройки сборки для всего проекта. Удобнее всего сначала указать параметры для всего проекта, а уже затем добавлять что-то в отдельных вариантах сборки.

    Прежде всего нужно убедиться в том, что в поле «Selected Compiler» выбран «GNU AVR GCC Compiler». Ниже, на вкладке «Compiler Flags», приводятся флаги компилятора. По умолчанию здесь уже включен полезный флаг «Enable all compiler warnings». Также стоит убедиться в том, что мы правильно выбрали тип процессора, для которого разрабатывается проект.

    На вкладке «#defines» показано значение переменной F_CPU, если оно было задано при создании проекта.

    На вкладке «Linker Options» в панели «Other linker options» видно, что компоновщику задан правильный параметр -mmcu, а в левой панели «Link libraries» нужно указать необходимые для проекта библиотеки, если они есть.

    Перейдите к вкладке «Search directories». Ниже, на вкладке «Compiler», нужно вставить путь к заголовочным файлам, например, /usr/avr/include/. Для этого воспользуйтесь кнопкой «Добавить» и впишите правильный путь. Аналогично, на вкладке «Linker» указываем путь к библиотекам AVR GCC, например, /usr/avr/lib.

    Вкладка «Pre/post build steps». В поле «Post-build steps» можно увидеть команды для запуска утилит avr-size, avr-objcopy, avr-objdump. Например, для получения листинга (поскольку включение параметра «Create extended listing file» в мастере создания проекта не производит нужного эффекта, по крайней мере в версии 8.02) добавляем такую команду:

    avr-objdump -h -S $(TARGET_OUTPUT_FILE) > $(TARGET_OUTPUT_FILE).lss

    Если теперь с параметров всего проекта переключиться на более конкретные цели сборки, например, Debug или Release, то можно внести некоторые изменения в параметры сборки. При этом обратите внимание на то, что стал доступен параметр «Policy». Его стандартное значение – «Append target options to project options», т.е. к общим параметрам проекта добавляются параметры для конкретной цели сборки. Есть и другие варианты объединения настроек разных уровней. Это позволяет гибко настраивать проект, не повторяя уже введенные общие параметры.

    Стандартные настройки предусматривают автоматическое включение создания отладочной информации в цели Debug (параметр «-g») и оптимизацию размера полученной программы в цели Release (параметр «-Os»).

  2. Выберите пункт меню «Project->Properties». Здесь стандартные настройки вполне подходят, чтобы начать работать с проектом, ничего в них не меняя. Стоит обратить внимание на вкладку «Build targets». Для каждой цели сборки (по умолчанию: Debug и Release) указывается, куда записываются получаемые объектные файлы, а в поле «Build target files» можно задавать, какие исходные файлы участвуют в данной сборке (рисунок 4).

    При желании можно свой настроенный проект сохранить как шаблон для будущих проектов. Для этого нужно выбрать команду меню «File->Save project as user template...» и ввести имя шаблона. В дальнейшем, при создании нового проекта, можно выбрать желаемый шаблон в категории «User templates» (рисунок 5). После этого потребуется задать пустой каталог, где будет создан новый проект, а затем отредактировать имя проекта.


    Можно даже изменить существующий стандартный шаблон. Для этого в окне выбора шаблонов нажмите правую кнопку мыши на нужном шаблоне и воспользуйтесь опцией «Edit this script» в появившемся меню.

  3. Перед тем как что-нибудь собирать, нужно еще заглянуть в глобальные настройки компилятора. Это делается через главное меню: «Settings->Compiler an debugger settings». В открывшемся окне левой панели нажмите на значок «Global compiler settings». На самом верху правой панели в верхнем поле «Selected compiler» выберите «GNU AVR GCC compiler» (рисунок 6).

    На вкладке «Compiler settings» вряд ли стоит что-либо менять: эти параметры станут стандартными для всех AVR-проектов. А вот на вкладках «Search directories->Compiler» и «Search directories->Linker» в моем случае уже стояли стандартные пути /usr/include и /usr/lib соответственно, что было неверно. Можно тут указать правильные пути (например, /usr/avr/include и /usr/avr/lib), а в настройках проекта удалить эти же пути, я же просто очистил эти поля кнопками «Clear», потому что параметры проекта к этому моменту уже были настроены.

    На вкладке «Toolchain executables» проверяем, правильно ли указаны имена исполняемых файлов из комплекта AVR GCC и пути к ним. С помощью кнопки «autodetect» можно попробовать автоматически определить все эти значения. Если же что-то получилось не так (например, дистрибутив AVR GCC оказался с экзотическими именами и каталогами для размещения), то это как раз место, где все можно исправить вручную. На рисунке 7 в поле «Compiler"s installation directory» должно быть указано «/usr», если программы AVR GCC размещаются в каталоге /usr/avr/.


    И последнее. На вкладке «Other settings» есть поле «Compiler logging». В нем можно задать режим журналирования процесса компиляции. Рекомендуется установить здесь значение «Full command line». Это позволит подробно проследить команды, используемые при сборке.

Теперь Code::Blocks готов к сборке проекта!

Использование собственного makefile для своего проекта

Всегда может возникнуть нестандартная ситуация, когда процесс сборки проекта нужно взять под свой полный контроль. Для этого в Code::Blocks предусмотрена возможность работы с собственным файлом сборки. Чтобы воспользоваться ею, необходимо создать пустой проект и сохранить его. Теперь нужно указать, что используется собственный makefile:

  1. Выберите пункт меню «Project -> Properties».
  2. Перейдите на вкладку "Project Settings".
  3. Поставьте галочку в поле "This is a custom makefile".
  4. Убедитесь, что указано правильное имя файла в поле «Makefile:».
  5. Теперь на вкладке «Build targets» нужно изменить или добавить цели сборки в соответствии с имеющимся makefile, например: all cleanall

При использовании собственного makefile следует проверить, какие команды имеются на вкладке «Make Commands» в пункте меню «Project ->Build Options».

Пробная программа

Во вновь созданном по AVR-шаблону проекте уже имеется файл main.c, который содержит заготовку модуля main для программы на С. Напишем новую программу на С++.

Воспользуйтесь опцией меню «File->New->File...» , выберите «C++ source» и нажмите кнопку «Go». Появится приветственное окно мастера создания нового исходного файла. Нажмите кнопку «Next» и в следующем окне выберите язык программирования для этого файла: С++. Далее укажите имя файла (например, sample.cpp) и полный путь к этому файлу, для чего нажмите кнопку «...» справа от поля с именем файла. Затем нужно указать, в каких целях сборки этот файл будет присутствовать, для чего можно просто нажать кнопку «All». Нажмите кнопку «Finish».

В созданный пустой файл впишите простейшую C++ программу:

int main(void) { const int some_size = 1000; while (true) { for (int i = 0; i < some_size; i++) int a = 3; // какое-нибудь действие } return 0; // никогда не дойдет сюда }

Сохраните файл, нажав клавиши Ctrl+S. Файл main.c нам не нужен, его можно удалить из проекта, нажав на его имени правую кнопку мыши и выбрав из появившегося меню команду «Remove file from project» (рисунок 8).


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

Скомпилируем программу. Для этого нужно выбрать команду меню «Build->Build» или нажать знакомую многим комбинацию клавиш Ctrl+F9, также можно использовать кнопку с голубой шестеренкой в панели инструментов. Программа будет скомпилирована, а окно сообщений внизу экрана автоматически переключится на вкладку «Build messages», где будет сказано, что сборка закончена, получилось 0 ошибок и одно предупреждение: в строке 8 неиспользованная переменная «a».

Немного об отладке

Подход к отладке AVR-приложений в значительной степени зависит от используемого оборудования. При наличии устройства AVR JTAG ICE можно производить внутрисхемную отладку, подключаясь с его помощью к процессору, используя для этого утилиту avarice. Если такого устройства нет, воспользуйтесь имитатором процессора simulavr. К сожалению, этот проект уже несколько лет не развивается, но разработчики продолжают выпускать исправления.

Чтобы настроить отладку в Code::Blocks, нужно открыть свойства проекта «Project->Properties» и перейти на вкладку «Debugger». Здесь в поле «Select target» выбираем «Debug». Для этой конфигурации на вкладке «Remote connection» указываются параметры подключения avr-gdb к удаленной цели отладки:

  • «Connection type»: TCP.
  • «IP address»: localhost, если устройство отладки (или имитатор) подключено к этому же компьютеру.
  • «Port»: например, 1212.

Теперь на вкладке «Additional commands» в поле «After connection» нужно вписать следующие команды для отладчика:

load break main

Первая команда загрузит программу в цель отладки (микропроцессор или имитатор), а вторая вставит точку останова на функции main.

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

simulavr -g -p 1212 -d atmega128

(для процессора atmega128), получится примерно такой вывод:

$ simulavr -g -p 1212 -d atmega128 Simulating a atmega128 device. ... main.c:415: MESSAGE: Simulating clock frequency of 8000000 Hz Waiting on port 1212 for gdb client to connect...

Если устройство подключено к последовательному порту /dev/ttyS0, запуск avarice можно произвести такой командой:

avarice -j /dev/ttyS0 -P atmega128:1212

Теперь можно запускать отладку в Code::Blocks при помощи команды меню «Debug->Start». В окне, где запущен simulavr, добавятся примерно такие сообщения:

Connection opened by host 127.0.0.1, port -14999. decoder.c:737: MESSAGE: BREAK POINT: PC = 0x00000068: clock = 34

При этом в редакторе Code::Blocks будет загружен исходный текст, содержащий функцию main, и курсор отладчика остановится на этой функции, как это показано на рисунке 9. Теперь можно пользоваться удобными кнопками для управления отладчиком в панели инструментов, просматривать значения переменных и так далее. Более подробно об отладке можно узнать в документации на gdb, simulavr или avarice.


Заключение

Итак, мы рассказали, как, затратив минимум усилий и времени, не обращаясь к документации и руководствам, быстро приступить к разработке AVR-приложений с использованием замечательной и быстро развивающейся среды разработки Code::Blocks. В настоящее время интерфейс среды переведен на множество языков и, возможно, скоро локализованные файлы войдут в состав основной ветви разработки.

В следующей статье нам предстоит познакомиться с использованием Eclipse для сборки приложений для широкого спектра микропроцессоров с небольшим размером оперативной памяти, для которых предназначен открытый компилятор SDCC.

Совсем недавно вышла новая версия среды разработки CodeBlocks (официальное написание через два двоеточия - Code::Blocks). Эта среда разработки уже успела стать очень популярной среди новичков и профессионалов. Если работа над CodeBlocks будет продолжаться в том же духе, он сможет составить весьма достойную конкуренцию Microsoft Visual Studio.

CodeBlocks - это очень популярная свободная кроссплатформенная среда разработки. CodeBlocks имеет в своем арсенале все самое необходимое для разработки: редактор, компилятор, отладчик. Распространяется по лицензии GPL и разрабатывается под такие платформы, как Windows, Linux и Mac OS X. Эту замечательную среду разработки можно собрать из исходников практически под любую Unix-подобную систему (Linux, FreeBSD, ...). Сама CodeBlocks написана на Си++ и использует для работы библиотеку wxWidgets. Легко может масштабироваться за счет подключаемых модулей, благодаря тому, что имеет открытую архитектуру. Поддерживает такие языки программирования, как С, С++, D.

Давайте теперь подробнее остановимся на возможностях среды.

Компиляция
Отличительной особенностью среды разработки CodeBlocks является то, что в ней реализована поддержка множества компиляторов. Это очень удобно, например, когда вам нужно открыть уже написанную под какой-то компилятор ранее программу. Либо, попробовать откомпилировать свой проект с помощью разных компиляторов. Каждый компилятор имеет свои особенности и объем выдаваемого после компиляции экзешника. Для каждого проекта вы можете выбрать свой компилятор: выбрать можно как при создании проекта, так и уже в созданном проекте через свойства. Список поддерживаемых компиляторов приведен ниже.

  • MinGW / GCC C/C++
    • GNU ARM GCC Compiler
    • GNU AVR GCC Compiler
    • GNU GCC Compiler for PowerPC
    • GNU GCC Compiler for TriCore
  • Digital Mars C/C++
  • Digital Mars D (с некоторыми ограничениями)
  • SDCC (Small device C compiler)
  • Microsoft Visual C++ 6
  • Microsoft Visual C++ Toolkit 2003
  • Microsoft Visual C++ 2005/2008 (с некоторыми ограничениями)
  • Borland C++ 5.5
  • Watcom
  • Intel C++ compiler
  • GNU Fortran
  • GNU ARM
  • GNU GDC

Также в CodeBlocks имеется поддержка многопрофильных проектов, поддержка рабочих пространств. Имеется возможность импорта проектов, созданных в среде Dev-C++, импорт проектов и рабочих пространств Microsoft Visual Studio.

Интерфейс

  • Подсветка синтаксиса
  • Сворачивание блоков кода
  • Автодополнение кода
  • Браузер классов
  • Скриптовой движок Squirrel
  • Планировщик под несколько пользователей
  • Поддержка плагинов Devpack (installation packages for Dev-C++)
  • Плагин wxSmith (a wxWidgets RAD tool)


Отладка

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

Хочу рассказать о своем первом опыте в геймдеве. Сразу стоит оговориться, что статья будет чисто технической, поскольку моей целью было всего лишь получение навыков разработки графических приложений, использующих Direct3D, без привлечения высокоуровневых средств разработки игр типа Unity. Соответственно, никаких разговоров о внедрении, монетизации и раскрутке игры также не будет. Статья ориентирована на новичков в программировании приложений Direct3D, а также просто на людей, интересующихся ключевыми механизмами работы подобных приложений. Также в конце привожу список литературы по геймдеву, тщательно отобранный мной из более чем ста книг по программированию игр и компьютерной графики.

Введение

Итак, в свободное от работы время решил я изучить популярный графический API. Прочитав несколько книг и разобрав кучу примеров и туториалов (в том числе из DirectX SDK), я осознал, что настал тот самый момент, когда стоит попробовать свои силы самостоятельно. Основная проблема была в том, что большинство существующих примеров просто демонстрируют ту или иную возможность API и реализованы процедурно чуть ли не в одном cpp-файле, да еще и с использованием обертки DXUT, и не дают представления о том, какую структуру должно иметь конечное приложение, какие классы нужно спроектировать и как это все должно друг с другом взаимодействовать, чтобы все было красиво, читабельно и эффективно работало. Данный недостаток касается и книг по Direct3D: например, для многих новичков не является очевидным тот факт, что состояния рендера (render states) не всегда нужно обновлять при отрисовке каждого кадра, а также, что большинство тяжеловесных операций (типа заполнения вершинного буфера) следует выполнить всего один раз при инициализации приложения (либо при загрузке игрового уровня).

Идея

Первым делом мне необходимо было определиться с самой идеей игры. На ум сразу пришла старая игра из 1992 года под MS-DOS, которая, я думаю, многим знакома. Это логическая игра Lines компании Gamos.

Что ж, вызов принят. Вот что мы имеем:

  • есть квадратное поле из ячеек;
  • в ячейках на поле есть разноцветные шары;
  • после перемещения шара появляются новые шары;
  • цель игрока в том, чтобы выстраивать одноцветные шары в линии: накопление в одной линии определенного числа одноцветных шаров приводит к их детонации и начислению очков;
  • главная задача - продержаться как можно дольше, пока на поле не закончатся свободные ячейки.
Теперь посмотрим с точки зрения приложения Direct3D:
  • поле из ячеек сделаем в виде трехмерной платформы с выступами, каждая ячейка будет представлять из себя что-то типа подиума;
  • должно быть реализовано три вида анимации шаров:
    1. появление шара: сначала появляется маленький шар, который за короткое время вырастает до взрослого размера;
    2. перемещение шара: просто происходит последовательное передвижение по ячейкам;
    3. прыгающий шар: при выборе шара мышью он должен активизироваться и начать прыгать на месте;
  • должна быть реализована система частиц, которая будет использоваться при анимации взрыва;
  • должен быть реализован вывод текста: для отображения на экране заработанных очков;
  • должно быть реализовано управление виртуальной камерой: вращение и зум.
По сути дела пункты, перечисленные выше, являются жалким подобием документа под названием дизайн-проект. Настоятельно рекомендую перед началом разработки расписать в нем все до мелких подробностей, распечатать и держать перед глазами! Забегая вперед сразу показываю демо-ролик для наглядности реализации пунктов (кстати, видео записано с помощью программы ezvid , так что не пугайтесь их сплэш-скрина в начале):

Начало разработки

До сих пор я не упоминал, какие инструменты использовались. Во-первых, необходим DirectX software development kit (SDK), всегда доступный для свободного скачивания на сайте Microsoft: DirectX SDK . Если вы собираетесь использовать версию Direct3D 9, как я, то после установки необходимо через главное меню открыть DirectX Control Panel и на вкладке Direct3D 9 выбрать, какая версия библиотек будет использоваться при сборке — retail либо debug (это влияет на то, будет ли Direct3D сообщать отладчику о результатах своей деятельности):

Debug или retail


Почему Direct3D 9-й версии? Потому что это последняя версия, где все еще есть fixed function pipeline, то есть фиксированный графический конвейер, включающий в себя, например, функции расчета освещения, обработки вершин, смешивания и так далее. Начиная с 10-й версии, разработчикам предлагается самостоятельно реализовывать эти функции в шейдерах, что является неоспоримым преимуществом, но, на мой взгляд, сложновато для восприятия при первых опытах с Direct3D.

Почему Code::blocks? Наверное, глупо было использовать кросс-платформенную IDE для разработки приложения, использующего некросс-платформенный API. Просто Code::blocks занимает в несколько раз меньше места, чем Visual Studio, что оказалось очень актуальным для моего дачного ПК.

Старт разработки с Direct3D оказался очень прост. В Code::blocks я создал пустой проект (empty project), затем в build options нужно было сделать две вещи:

1) На вкладке search directories и подвкладке compiler добавить путь к директории include DirectX SDK — например, так:

Search directories



2) На вкладке linker добавить две библиотеки — d3d9.lib и d3dx9.lib:

Linker



После этого в исходном коде приложения нужно будет включить заголовочные файлы Direct3D:

#include "d3d9.h" #include "d3dx9.h"

Структура приложения

Здесь я допустил первую ошибку: начал размышлять над тем, какой шаблон проектирования выбрать. Пришел к выводу, что лучше всего подходит MVC (model-view-controller): моделью будет класс игры (game), включающий всю логику - вычисление путей перемещения, появление шаров, разбор взрывных комбинаций; представлением будет класс движка (engine), отвечающий за отрисовку и взаимодействие с Direct3D; контроллером будет собственно обертка (app) - сюда входит цикл обработки сообщений, обработка пользовательского ввода, а также, что самое главное, менеджер состояний и обеспечение взаимодействия объектов game и engine. Вроде бы все просто, и можно начинать писать заголовочные файлы, но не тут-то было! На этом этапе оказалось очень сложно сориентироваться и понять, какие методы должны быть у этих классов. Понятно, что сказалось полное отсутствие опыта, и я решил прибегнуть к совету одной из книг: «Не пытайтесь с самого начала написать идеальный код, пусть он будет неоптимальным и сумбурным. Понимание приходит со временем, и рефакторингом можно заняться потом.» В итоге после нескольких итераций рефакторинга уже работающего макета определение трех основных классов приняло вид:

Класс TGame

class TGame { private: BOOL gameOver; TCell *cells; WORD *path; WORD pathLen; LONG score; void ClearField(); WORD GetSelected(); WORD GetNeighbours(WORD cellId, WORD *pNeighbours); BOOL CheckPipeDetonate(WORD *pPipeCells); public: TGame(); ~TGame(); void New(); BOOL CreateBalls(WORD count); void Select(WORD cellId); BOOL TryMove(WORD targetCellId); BOOL DetonateTest(); WORD GetNewBallList(TBallInfo **ppNewList); WORD GetLastMovePath(WORD **ppMovePath); WORD GetDetonateList(WORD **ppDetonateList); LONG GetScore(); BOOL IsGameOver(); };


Класс TEngine

class TEngine { private: HWND hWindow; RECT WinRect; D3DXVECTOR3 CameraPos; LPDIRECT3D9 pD3d; LPDIRECT3DDEVICE9 pDevice; LPDIRECT3DTEXTURE9 pTex; LPD3DXFONT pFont; D3DPRESENT_PARAMETERS settings; clock_t currentTime; TGeometry *cellGeometry; TGeometry *ballGeometry; TParticleSystem *psystem; TBall *balls; TAnimate *jumpAnimation; TAnimate *moveAnimation; TAnimate *appearAnimation; LONG score; void InitD3d(); void InitGeometry(); void InitAnimation(); void DrawPlatform(); void DrawBalls(); void UpdateView(); public: TEngine(HWND hWindow); ~TEngine(); void AppearBalls(TBallInfo *ballInfo, WORD count); void MoveBall(WORD *path, WORD pathLen); void DetonateBalls(WORD *detonateList, WORD count); BOOL IsSelected(); BOOL IsMoving(); BOOL IsAppearing(); BOOL IsDetonating(); void OnResetGame(); WORD OnClick(WORD x, WORD y, BOOL *IsCell); void OnRotateY(INT offset); void OnRotateX(INT offset); void OnZoom(INT zoom); void OnResize(); void OnUpdateScore(LONG score); void Render(); };


Класс TApplication

class TApplication { private: HINSTANCE hInstance; HWND hWindow; POINT mouseCoords; TEngine* engine; TGame* game; BOOL moveStarted; BOOL detonateStarted; BOOL appearStarted; void RegWindow(); static LRESULT CALLBACK MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); void ProcessGame(); public: TApplication(HINSTANCE hInstance, INT cmdShow); ~TApplication(); TEngine* GetEngine(); TGame* GetGame(); INT MainLoop(); };


Класс TGame имеет всего 3 метода, которые может инициировать сам пользователь — New (новая игра), Select (выбор шара) и TryMove (попытка переместить шар). Остальные вспомогательные и вызываются контроллером в особых случаях. Например, DetonateTest (тест на взрывные комбинации) вызывается после появления новых шаров или после попытки перемещения. GetNewBallList, GetLastMovePath, GetDetonateList вызываются, соответственно, после появления шаров, после перемещения и после взрыва, с одной целью: получить список конкретных шаров и передать его на обработку объекту engine, чтобы он что-то нарисовал. На логике работы TGame не хочется подробно останавливаться, поскольку есть исходники с комментариями . Скажу только, что определение пути перемещения шара реализовано с помощью алгоритма Дейкстры по неориентированному графу с равными весами всех ребер.

Рассмотрим подробнее классы движка и контроллера.

TEngine

  • В классе определены поля для хранения handle окна и его прямоугольника. Они используются в методе OnResize, который контроллер вызывает при изменении размеров окна, для расчета новой матрицы проекции.
  • В поле CameraPos хранятся координаты наблюдателя в мировом пространстве. Вектор направления взгляда хранить не нужно, поскольку по моей задумке камера всегда направлена в начало координат, которое, кстати, совпадает с центром платформы.
  • Также имеются указатели на интерфейсы Direct3D: LPDIRECT3D9, который нужен только для создания устройства; LPDIRECT3DDEVICE9 — собственно, само устройство Direct3D, основной интерфейс, с которым приходится работать; LPD3DXFONT и LPDIRECT3DTEXTURE9 для работы с текстом и текстурой.
  • Поле currentTime используется для хранения текущего времени в миллисекундах и необходимо для отрисовки плавной анимации. Дело в том, что отрисовка каждого кадра занимает разное количество миллисекунд, поэтому приходится каждый раз замерять эти миллисекунды и использовать в качестве параметра при интерполировании анимации. Такой способ известен под названием синхронизация временем и используется повсеместно в современных графических приложениях.
  • Указатели на объекты класса TGeometry (cellGeometry и ballGeometry) хранят геометрию одной ячейки и одного шара. Сам по себе объект TGeometry, как понятно из названия, предназначен для работы с геометрией и содержит вершинные и индексные буферы, а также описание материала (D3DMATERIAL9). При отрисовке мы можем изменять мировую матрицу и вызывать метод Render объекта TGeometry, что приведет к отрисовке нескольких ячеек или шаров.
  • TParticleSystem — это класс системы частиц, имеющий методы для инициализации множества частиц, обновления их позиций в пространстве и, конечно же, рендеринга.
  • TBall *balls — массив шаров с информацией о цвете и статусе [прыгающий, перемещающийся, появляющийся].
  • Три объекта типа TAnimate — для обеспечения анимации. Класс имеет метод для инициализации ключевых кадров, которые представляют собой матрицы мирового преобразования, и методы для вычисления текущей позиции анимации и применения преобразования. В процедуре рендеринга объект engine последовательно отрисовывает шары и при необходимости вызывает метод ApplyTransform нужной анимации, чтобы сдеформировать либо переместить шар.
  • InitD3d, InitGeometry, InitAnimation вызываются только из конструктора TEngine и выделены в отдельные методы для наглядности. В InitD3d создается устройство Direct3D и устанавливаются все необходимые render state"ы, включая установку точечного источника освещения со specular-составляющей прямо над центром платформы.
  • Три метода AppearBalls, MoveBall и DetonateBalls запускают анимации появления, перемещения и взрыва, соответственно.
  • Методы IsSelected, IsMoving, IsAppearing, IsDetonating используются в функции менеджера состояний для отслеживания момента окончания анимации.
  • Методы с префиксом On вызываются контроллером при возникновении соответствующих событий: клика мышью, вращении камеры и т.д.
Рассмотрим основной метод Render:

TEngine::Render()

void TEngine::Render() { //вычисляем, сколько миллисекунд прошло с момента отрисовки предыдущего кадра clock_t elapsed=clock(), deltaTime=elapsed-currentTime; currentTime=elapsed; //обновляем позиции анимаций, если они активны if(jumpAnimation->IsActive()) { jumpAnimation->UpdatePosition(deltaTime); } if(appearAnimation->IsActive()) { appearAnimation->UpdatePosition(deltaTime); } if(moveAnimation->IsActive()) { moveAnimation->UpdatePosition(deltaTime); } pDevice->Clear(0,NULL,D3DCLEAR_STENCIL|D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0); pDevice->BeginScene(); //рисуем платформу DrawPlatform(); //рисуем шары DrawBalls(); //если активна система частиц, то обновляем положения частиц и рендерим их с текстурой if(psystem->IsActive()) { pDevice->SetTexture(0,pTex); psystem->Update(deltaTime); psystem->Render(); pDevice->SetTexture(0,0); } //вывод заработанных очков char buf="Score: ",tmp; itoa(score,tmp,10); strcat(buf,tmp); RECT fontRect; fontRect.left=0; fontRect.right=GetSystemMetrics(SM_CXSCREEN); fontRect.top=0; fontRect.bottom=40; pFont->DrawText(NULL,_T(buf),-1,&fontRect,DT_CENTER,D3DCOLOR_XRGB(0,255,255)); pDevice->EndScene(); pDevice->Present(NULL,NULL,NULL,NULL); }


В самом начале вычисляется, сколько миллисекунд прошло с предыдущего вызова Render(), затем обновляются прогрессы анимаций, если они активны. Очищаются буферы методом Clear и последовательно рисуются платформа, шары и система частиц, если она активна. Напоследок выводится строка с текущим значением заработанных очков.

TApplication

  • Класс имеет поле для хранения координат мыши, поскольку нам необходимо будет вычислять значения относительных смещений курсора, чтобы вращать камеру.
  • Булевы флаги appearStarted, moveStarted и detonateStarted необходимы для отслеживания статуса соответствующих анимаций.
  • В метод RegWindow вынесен код для регистрации класса окна.
  • Static-метод MsgProc — так называемая оконная процедура.
  • ProcessGame — упрощенная версия менеджера состояний, в котором оценивается текущее состояние игры и в зависимости от него предпринимаются какие-то действия.
  • MainLoop — цикл обработки сообщений.
Вот такой легковесный контроллер. Подобный цикл обработки сообщений можно встретить в любой книге по Direct3D:

TApplication::MainLoop()

INT TApplication::MainLoop() { MSG msg; ZeroMemory(&msg,sizeof(MSG)); while(msg.message!=WM_QUIT) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { //если нет сообщений, то обрабатываем состояние игры и занимаемся рендерингом ProcessGame(); engine->Render(); } } return (INT)msg.wParam; }


Внимания заслуживает только то, что находится внутри блока else — это так называемая IdleFunction, которая выполняется при отсутствии сообщений.

А вот и функция менеджера состояний:

TApplication::ProcessGame()

void TApplication::ProcessGame() { if(moveStarted) { //ждем до окончания анимации перемещения if(!engine->IsMoving()) { //перемещение окончено - тестируем на взрыв moveStarted=FALSE; if(game->DetonateTest()) { //инициируем взрыв и увеличиваем очки WORD *detonateList, count=game->GetDetonateList(&detonateList); detonateStarted=TRUE; engine->DetonateBalls(detonateList,count); engine->OnUpdateScore(game->GetScore()); } else { //иначе пытаемся добавить шары if(game->CreateBalls(APPEAR_COUNT)) { TBallInfo *appearList; WORD count=game->GetNewBallList(&appearList); appearStarted=TRUE; engine->AppearBalls(appearList,count); } else { //game over! } } } } if(appearStarted) { //ждем до окончания анимации появления if(!engine->IsAppearing()) { appearStarted=FALSE; //появление окончено - тестируем на взрыв на всякий случай if(game->DetonateTest()) { //инициируем взрыв и увеличиваем очки WORD *detonateList, count=game->GetDetonateList(&detonateList); detonateStarted=TRUE; engine->DetonateBalls(detonateList,count); engine->OnUpdateScore(game->GetScore()); } } } if(detonateStarted) { //ждем до окончания анимации взрыва if(!engine->IsDetonating()) { //просто сбрасываем флаг detonateStarted=FALSE; } } }


Что ж, пожалуй, на этом все!

Надеюсь, мои изыскания принесут кому-то пользу. Кстати, исходники на github .

Спасибо за внимание!

Обещанная литература

1. Frank D. Luna Введение в программирование трехмерных игр с DirectX 9.0 — для понимания основ;
2. Горнаков С. DirectX9 уроки программирования на С++ — тоже основы, но есть главы по DirectInput, DirectSound и DirectMusic. В примерах программ иногда встречаются ошибки;
3. Фленов М. Е. DirectX и C++ искусство программирования — забавный стиль изложения. В основном, целью книги является создание анимационных роликов с использованием интересных эффектов, в том числе с шейдерами. Судите сами по названию разделов: сердечный приступ, огненный дракон;
4. Баррон Тодд Программирование стратегических игр с DirectX 9 — полностью посвящена темам, связанным со стратегическими играми: блочная графика, ИИ, создание карт и ландшафтов, спрайты, спецэффекты с системами частиц, а также разработка экранных интерфейсов и работа с DirectSound/Music;
5. Bill Fleming 3D Creature WorkShop — книга не по программированию, а по разработке трехмерных моделей персонажей в средах LightWave, 3D Studio Max, Animation Master;
6. Thorn Alan DirectX 9 User interfaces Design and implementation — подробная книга о разработке графических интерфейсов с DirectX. Рассматривается иерархическая модель компонентов экранных форм, подобная реализованной в Delphi;
7. Adams Jim Advanced Animation with DirectX — рассматриваются типы анимации (скелетная, морфинг и разновидности) и их реализация, а также работа с геометрией и анимацией из X-файлов;
8. Ламот Андре Программирование игр для Windows. Советы профессионала — эта книга уже посерьезнее: рассматриваются вопросы оптимизации, выбора структур данных под различные задачи, многопоточность, физическое моделирование, ИИ. В последней главе описывается создание игры про космический корабль и пришельцев;
9. David H. Eberly 3D Game engine design — хорошая книга для понимания всей теории игростроения: сначала описываются технологии графических API (трансформации, растеризация, затенение, смешивание, мультитекстурирование, туман и т.д.), затем такие темы, как граф сцены, выбор объектов, определение столкновений, анимация персонажей, level of detail, ландшафты;
10. Daniel Sánchez-Crespo Dalmau Core techniques and algorithmes in game programming — подробно рассматриваются алгоритмы и структуры данных, используемые в задачах игростроения, такие как ИИ, скриптинг, рендеринг в закрытых и в открытых пространствах, алгоритмы отсечения, процедурные техники, способы реализации теней, реализация камеры и т.д.;
11. Ламот Андре Programming Role Playing Games with directX 9 — тысячестраничное подробное руководство по разработке RPG. Включает как теоретические главы по программированию с Direct3D, DirectInput, DirectSound, DirectPlay, так и прикладные главы, имеющие непосредственное отношение к игровому движку.

Теги: Добавить метки



Рекомендуем почитать

Наверх