2.6. Тестовый стенд
Когда пример Heiioworid вам покорится, посмотрите на испытательный стенд Box2D. Стенд представляет собой
каркас для тестирования механизмов и построений. Вот некоторые из его особенностей:
Движущаяся по вашему желанию камера с возможностью приблизить и отдалить изображение.
Фигуры прикрепляются к курсору мыши по щелчку.
Расширяемый набор тестов.
Графический интерфейс для выбранных тестов, настройка параметров и опция отладочной визуализации.
Пауза и пошаговое моделирование.
Визуализация текста.
Tests
1 Dominos
H
Iterations 10
3
Hertz | 60.0
3
[7 Position Correction [7 Warm Starting p Time of Impact
г Draw-
ls Shapes
p Joints
Г" Core Shapes
Г AABBs
Г OBBs
Г" Pairs
I- Contact Points
Г Contact Normals
Г Contact Forces
Г Friction Forces
Г Center of Masses
Г" Statistics
Pause
Single Step
Quit
СтендсодержитмножествопримеровиспользованияBox2D. Заглянитевисходныйкод тестовогостенда, когдабудетеразбиратьсясBox2D.
Замечание : испытательныйстенднаписансиспользованиемfreeglut иGLUI. Стендне являетсячастьюбиблиотекиBox2D. КакпоказановпримереHelloWorld, выможете использоватьBox2D безкакойлибографическойвизуализациирезультата.
Глава 3. ИнтерфейсBox2D
Содержание
3.1. Управлениединамическойпамятью 3.2. Фабрикииопределения 3.3. Единицы измерения 3.4. Пользовательскиеданные 3.5. Использование C++ 3.6. Недовольным
3.1. Управлениединамическойпамятью
НеобходимостьвбыстройиэффективнойработеспамятьювнутриBox2D стала причинойбольшогоколичествадискуссий. Вэтомразделерассказывается, какизачем
Box2D выделяет память для своих нужд.
Box2D нуждается в выделении памяти для большого количества маленьких объектов (примерно по 50-300 байт). Использование системного хипа через функции malloc или new для небольших объектов неэффективно и приводит к фрагментации памяти. При этом бОльшая часть этих объектов имеет небольшое время жизни (например, контакты), но при этом может существовать на протяжении нескольких физических циклов. Поэтому необходим аллокатор (от англ. «allocator» - объект, занимающийся выделением памяти), который сможет эффективно обеспечивать нас динамической памятью для большого количества маленьких объектов.
В Box2D для решения этой проблемы используется "аллокатор маленьких объектов" («small object allocator» или сокращенно «SOA»). SOA хранит несколько блоков памяти различного размера. При требовании выделить память, SOA предоставляет нам блок памяти наилучшим образом соответствующий необходимому размеру. Если блок больше не нужен, то он просто помечается как свободный. Обе операции выполняются очень быстро и не приводят к фрагментации памяти.
Так как Box2D использует собственный SOA, НИКОГДА не выделяйте память для тел, фигур или соединений вручную (через malloc или new). Выделение памяти вручную разрешено только для b2World. Класс b2World предоставляет фабрики (специальные функции для создания объектов) для создания тел, фигур и соединений. Фабрики позволяют использовать эффективный механизм выделения памяти, при этом скрывая ненужные детали. Аналогично, НИКОГДА не используйте delete или free для тел, фигур и соединений.
При просчете текущего временного интервала, Box2D нуждается во временной рабочей памяти. Для этого он использует стековый аллокатор, чтобы каждый раз не обращаться к хипу. Необходимости во взаимодействии с этим аллокатором нет, просто достаточно знать, что он есть.
3.2. Фабрики и определения
Как упоминалось выше, управление памятью играет очень важную роль в устройстве интерфейса Box2D. Поэтому для создания b2Body или b2Joint, необходимо вызывать функции-фабрики класса b2World (за которыми скрывается быстрый и эффективный аллокатор памяти).
Вот эти функции:
b2Body* b2World::CreateBody(const b2BodyDef* def) b2Joint* b2World::CreateJoint(const b2JointDef* def)
А вот соответствующие функции для освобождения памяти:
void b2World::DestroyBody(b2Body* body) void b2World::DestroyJoint(b2Joint* joint)
При создании тела или соединения, необходимо передавать в функцию-фабрику указатель на определение тела (definition). Определения содержат всю информацию
необходимую фабрике для создания тела или соединения. Использование определений позволяет предотвратить ошибки при создании тел и соединений, сократить количество аргументов у функций-фабрик и уменьшить число аксессоров (функций для доступа к членам класса).
Так как любая фигура должна быть присоединена к телу-родителю, то и создаются они фабричными методами тела-родителя, т.е. класса b2Body:
b2Shape* b2Body::CreateShape(const b2ShapeDef* def) void b2Body::DestroyShape(b2Shape* shape)
Фабрики не сохраняют указатели на определения тел или соединений, поэтому определения можно объявлять как локальные переменные.
3.3. Единицы измерения
Так как Box2D использует числа с плавающей точкой, необходимо сразу допустимые размеры и отклонения от них. Параметры Box2D подобраны для использования единиц МКС (метр-килограмм-секунда) и работы с динамичными объектами, размер которых составляет от 0.1 до 10 метров, т.е. от стаканов до автобусов.
Идея использовать пиксели в качестве единиц измерения очень заманчива, но, к сожалению это приведет к неточному моделированию и, возможно, очень странному поведению объектов. Попробуйте представить моделирование движения высотных зданий движком, который был настроен на работу с куклами и бочками. Получится явно не очень хорошо.