Box2D в картинках – Часть 2 (Привет мир!)

Итак сегодня напишем первое  небольшое приложения с использованием Box2D.

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

Но сначала надо сказать о общих положениях касающиеся Box2D. Эти положения будут предоставлены в виде тезисов:

- как единицу измерения Box2D  НЕ ИСПОЛЬЗУЕТ пиксели;

- как единицу измерения Box2D ИСПОЛЬЗУЕТ международную систему С (си) — метры, килограммы, секунды (МКС);

-  Box2D был настроен на работу с динамическими объектами в диапазоне от 10 сантиметров до 10 метров, то есть возможно создавать объекты от стакана до автобуса;

(еще можно встретить другую терминологию единиц измерения — это unit (юниты) — просто какая то единица. В такой терминологии Box2D работает от 1 до 100 юнитов)

- так как единицы которыми оперирует Box2D не совпадает с экранными единицами (пикселями), то надо задавать некоторый коефициент преобразования метров (юнитов) в пиксели. Например можно задать что  10 сантиметров = 30 пикселям. Или если в юнитах оперировать то 1 юнит = 30 пикселям. Это коэффициент уже каждый сам для себя определяет. (Далее буду оперировать только в метрах)

- Box2D оперирует с двумя типами объектов: динамические и статические;

- Динамические объекты участвуют в процессе анализа столкновений между собой (кирпичи, мячи, молекулы, вертолеты, машины, люди…. :) ), статические — нет (земля, фундамент, каркас — все что абсолютно нерушимое);

- Box2D реализует столкновения с следующими фигурами: круг, квадрат, выпуклые многоугольники. Есть механизм который разрешает добавить свои фигуры, но также надо будет добавлять и свой алгоритм обработки этих фигур;

- Имена большинства структур в  Box2D начинаются с префикса «b2» для того чтобы лучше визуально выделить структуры движка и сделать меньшую вероятность конфликта с структурами пользователя;

Ну вот вроде пока все. Теперь начнем создавать мир физики…

_____

1. Создадим границы мира

Первое что надо создать это границы физического мира. Представьте себе большую коробку внутри которой происходят физические процессы (столкновения, гравитация, трение и т.д.), а за рамками этой коробки физики нет. Вот так и работает Box2D. Все объекты которые вылетают за эти границы автоматически перестают просчитываться движком и они как бы «замораживаются». Многие после этого объяснения пишут что «… потому делайте границы мира достаточно большими, чтобы ваши объекты не вылетели случайно за них и не «замерзли», то есть не выпали из процесса просчета».
В принципе все правильно, только если оговорится что «это надо в случае если вам действительно нужен такой огромный физический мир когда все и всегда будет просчитываться в нем». Ведь чем больше объектов на сцене тем больше вычислений и тем больше тормоза. Потому это все очень зависит от конкретной задачи. Например, можно создать технику когда все физ объекты будут просчитываться только в том случае если они попадают в поле зрение игрока, то есть находятся на экране и с такой техникой можно создать довольно сложною, насыщенную физическими объектами игру, которая будет работать без тормозов. Но это пока для нас не актуально, потому мы сделаем классический большой квадрат :)

За границы мира отвечает структура b2AABB . Далее код с комментарием:

 
var borderWorld:b2AABB = new b2AABB();
// Делаем очень большой квадрат
borderWorld.lowerBound.Set(-1000.0, -1000.0);
borderWorld.upperBound.Set(1000.0, 1000.0);

Затем нам надо создать сам мир. За мир отвечает класс b2World. Но как и в любом мире надо задать гравитацию. Гравитация может быть как вниз так и вверх так и в сторону… короче в любом направлении. Гравитация это вектор, а потому используется обычный класс вектора b2Vec2, параметры которого x и y. Они задают не только направление гравитации, а и в зависимости от величины значения, силу гравитации.

Далее создается классическая гравитация вниз с силой 10 (а вот какие единицы характеризируют это число, увы, не знаю (настоящая характ. вот так м?·с-?·кг?1)) :)

 
// задаем вектор гравитации в сторону Y (вниз) с силой 10
 
var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);

Теперь создадим сам мир:

// создаем мир и задаем ему начальные параметры - размеры, гравитацию и разрешение объектам "засыпать"
var world:b2World = new b2World(borderWorld, gravity, true);

Третий параметр разрешает/запрещает динамическим объектам «засыпать». Когда динамические объекты (далее ДО) успокаиваются (прекращают всякое движение, взаимодействие… ) путем этого ключа Box2D их выкидывает из обработки, тем самым оптимизируется процесс вычисления и повышается производительность. Но как только на этот ДО будет воздействовать какая то сила, движок сразу «пробудит» его, то есть включит в процесс обработки на столкновения.

(Если заметили то у Box2D очень много всяких фишек по оптимизации вычислений, как только какой то объект не нужен или может быть игнорирован Box2D сразу исключает его из процесса просчета (симуляции))
Ну вот физический мир создан! Он пока пустой, но уже полноценный :)

_____

2. Добавим тела в мир.

Сначала поговорим о телах. Box2D оперирует телами. А что такое тело?

Тело эта какая то абстракция которая не имеет ни отображения, ни формы, ни границ.

Тело (класс b2Body) состоит из определения тела (класс b2BodyDef) и определения формы (класс b2ShapeDef).
Создадим статическое тело, которое будет платформой или землей, как хотите называйте.
Далее создаем определение тела и задаем ему позицию, этим мы говорим где будет находится тело, в каких координатах (пусть это будет в координатах 100 х 100).

// Определение статического тела
var groundDefination:b2BodyDef;
 
// создаем и определяем параметры стат. тела
groundDefination = new b2BodyDef();
// задаем координаты. Так как <strong>Box2D </strong>оперирует метрами (а 0.1 метр = 30 пикселям) то мы должны пиксели привести в метры,
// а это значит задаваемые значения в пикселях делим на 30.
groundDefination.position.Set(100/30, 100/30);

У нас тело пока что пустота. Чтобы оно набрало какую-то форму и свойства нам надо его наполнить. Для этого надо создать форму (фигуру), задать свойства и применить к телу.
Тогда тело уже можно будет «пощупать». Не тело, а именно форма участвует в столкновениях и других физических просчетах. У тела может быть несколько присоединенных форм. Форма не может быть самостоятельной, без тела, если есть форма то она должна быть присоединена к телу.
Создадим форму (фигуру) (например, прямоугольник с шириной 100 и высотой 100):

// Определение фигуры статического тела
var groundShapeDefination:b2PolygonDef;
 
// определяем полигон (форму) для нашего тела, он будет учавствовать в столкновениях.
// Используем готовый метод SetAsBox - он просто установит что наша форма прямоугольник. 
// Как параметры он принимает полуширину и полувысоту. А также нам надо привести к метрам, потому делим на 30. 
groundShapeDefination = new b2PolygonDef();
groundShapeDefination.SetAsBox((100/2)/30, (100/2)/30);

Тут для фигуры был использован класс b2PolygonDef, это класс наследник b2ShapeDef класса. Для прямоугольников проще использовать его так как у этого класса есть готовый метод SetAsBox, который создает фигуру прямоугольника. Как параметры метод принимает полуширину и полувысоту от требуемой величины, потому делим на 2 (ну и также не забываем поделить на коефициент преобразования в экранные координаты, то есть 30).

Ну вот вроде все объявления создали, теперь надо все их применить к телу.

// создаем тело с помощь его описания 
groundBody = world.CreateBody(groundDefination);
 
// придаем ему форму (из описаной выше формы создаем форму нашего тела)
groundBody.CreateShape(groundShapeDefination);

Теперь надо задать массу тела. Это можно сделать вручную, но это не рекомендуется. Лучше создавать массу тела автоматически при помощи метода SetMassFromShapes(). Box2D автоматически рассчитает массу тела из плотности фигуры.

// устанавливаем (рассчитываем) массу нашего тела из расчета форм в нашем теле (Box2D делаем это автоматически)
groundBody.SetMassFromShapes();

И вот тут надо кое что объяснить, а именно разницу в создании динамического тела и статического.
На самом деле разницы нет. Когда создаются формы, по умолчанию плотность равна 0 и соответственно масса тела при вычислении также равна 0. И если плотность не задать то она так и останется 0. А когда фигура имеет плотность 0 Box2D автоматически переводит ее в разряд статических. А это значит что это тело не принимает участие в столкновениях с другими статическими телами.

Когда создается динамическое тело то ему присваивается масса больше 0.
Вся разница будет только вот в этой строчке:

groundShapeDefination.density = 1.0;	// коефициент плотности объекта

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

3. Цикл симуляции
Итак, создали статические и динамические тела. И они уже существуют в мире… Но ничего не происходит, нету никаких взаимодействий.
Потому что нету процесса симуляции — Box2D ничего не просчитывает. Нам надо вызывать вручную метод, который будет говорить Box2D что надо сделать просчет физики (шаг симуляции).
Метод вызывается из объекта мира (b2World) и называется Step. Далее процитирую документацию:

Для моделирования движения тел Box2D использует численное дифференцирование (а точнее метод Эйлера). Выгляди это так: мир Box2D содержит функцию Step(float timeStep,int iterations), имеющую два аргумента: время, которое необходимо смоделировать в мире и количество итераций для разрешения взаимодействий между объектами.

Так вот, timeStep это время которое ты хочешь смоделировать в мире. Обычно это 1/20 — 1/30 секунды. Проще говоря чем это время больше тем все взаимодействия в мире происходят быстрее, чем меньше тем медленней и плавнее.
iterations — это количество итераций на каждом шаге моделирования. Далее цитата из документации:

В коде Box2D большую часть занимает constraint solver («решальщик» ограничений). Задача Constraint solver — просчёт ограничений для правильного поведения тел при столкновениях. При просчёте одного ограничения не возникает особых трудностей. Однако при просчете нескольких ограничений, разрешение одного ограничения слегка нарушает остальные. Поэтому для получения хорошего результата необходимо произвести просчет всех ограничений несколько раз (т.е. сделать несколько итераций).

Чем больше таких итераций тем точнее происходит моделирование, НО тем больше надо времени для этого, что тянет за собой больший расход ресурсов процессора.
Потому в зависимости от критичности приложения рекомендуется использовать от 10 — 20 итераций.
Далее небольшой код как это будет выглядеть:

// Количество итераций которые для просчета физики (чем больше тем точнее просчет и тем больше надо времени для этого)
private var iterations:int = 20;
 
// Время которое надо смоделировать в мире
private var timeStep:Number = 1/20.0;
 
addEventListener(Event.ENTER_FRAME, updateWorld);
 
private funcntion updateWorld(event:Event):void
{
   world.Step(timeStep, iterations);
}

Вот теперь в мире уже все моделируется — Ньютон работает по полной :)

4. Отображение
Хоть у нас все моделируется но ничего не видно! Естественно, ведь у нас задана только математическая модель и никакого графического представления мы не задавали.
В классе определения тела (b2BodyDef) есть поле userData типа Object. Туда мы можем сохранять любые пользовательские данные в частности и графическое отображение.
Поэтому при создании (которое было описано выше) тела сразу можно создавать его отображение (Sprite, MovieClip…) и запихивать его в поле userData.
Далее небольшой код демонстрирующий создание динамического тела, кирпича :) (это код из прикрепленного исходника только немного модифицирован (упрощен)):

private function createDinamycBody():void 
{
	var kirpich:Sprite = new Sprite();
	addChild(kirpich);
 
	kirpich.graphics.beginFill(0x660000);
	kirpich.graphics.drawRect(-25, -20, 50, 40);
	kirpich.graphics.endFill();
 
	kirpich.x = 100;
	kirpich.y = 100;
 
	var dynamicBody:b2Body;
	var dynamicBodyDefination:b2BodyDef;
	var dynamicShapeDefination:b2PolygonDef;
 
	dynamicBodyDefination = new b2BodyDef();
	dynamicBodyDefination.position.Set(kirpich.x / 30, kirpich.y / 30);
	dynamicBodyDefination.userData = kirpich;
 
	dynamicShapeDefination = new b2PolygonDef();
	dynamicShapeDefination.SetAsBox((kirpich.width) / 30 / 2, (kirpich.height) / 30 / 2);
 
	dynamicShapeDefination.density = 1.0;		// коефициент плотности 
	dynamicShapeDefination.friction = 1.0; 		// коефициент трения 
	dynamicShapeDefination.restitution = 0.1; 	// коефициент упругости
 
	dynamicBody = world.CreateBody(dynamicBodyDefination);
	dynamicBody.CreateShape(dynamicShapeDefination);
	dynamicBody.SetMassFromShapes();
}

Ну вот отображение есть.

5. Изменение позиции отображение в соответствии физической модели.

Хоть отображение у нас есть но на экране ты не увидишь чтобы это отображение куда то двигалось или хоть как то менялось.
Для этого надо каждый раз (каждый кадр) вручную получать данные от физической модели (позиция, угол наклона) и применять к своему отображению.
Далее пример кода:

private function updateWorld(event:Event):void 
{
	//"делаем шаг" физического мира - тут рассчитываются положения физических тел
	world.Step(timeStep, iterations);
 
	//пробегаем по всем физическим телам и двигаем их мувики на свои места
	//"их мувики" храним в пользовательских данных тела
	for (bodiesList = world.GetBodyList(); bodiesList; bodiesList = bodiesList.GetNext()) 
	{
		// Извлекаем вектор позиции тела
		var tVector:b2Vec2 = bodiesList.GetPosition();
 
		// Присваиваем значения этого вектора, заранее умножив на коефициент перевода с метров в пиксели, нашему графическому отображению.
		bodiesList.m_userData.x = tVector.x * 30;
		bodiesList.m_userData.y = tVector.y * 30;
 
		// Извлекаем угол (в радианах) множим на коефициент перевода в градусы и присваиваем нашему отображению
		bodiesList.m_userData.rotation = bodiesList.GetAngle() * 180 / Math.PI;
	}
}

6. Исходники

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

7. Заключение
В заключении еще несколько напоминаний и объяснений.
Box2D работает с радианами и потому не забывай переводить их в градусы.

Отдельно хочется сказать в методе setBullet(val:Boolean). Метод вызывается для тел и отвечает за то что тело для которого setBullet был установлен в true будет вычисляться намного точнее и соответственно ресурсов процессорных будет потреблять больше. А это значит что если тел на сцене будет много и для каждого установить этот флаг в true то будут наблюдаться тормоза.
Из названия метода можно догадаться что он был создан для быстро движущихся тел, таких как пуля, ядро (отсюда и название bullet).
Попробуй поэкспериментировать с этим флагом, заметишь что если он установлен в false то тела будут немного проскакивать друг в друга.
Кстати, на статические тела этот флаг никак не действует.

Для балансировки скорости приложения можно выделить несколько параметров с которыми следует поиграться:
- частота кадров самой флешки;
- количество итераций;
- временной шаг (Время которое надо смоделировать в мире);
- параметр setBullet;
- да и просто не забывать о оптимизациях. Например, не просчитывать позицию отображения статического тела;

Все остальное найдешь в исходнике.

В исходнике пример, который создает в случайной позиции квадратики которые падают на статическую платформу. Те из квадратиков которые уходят за пределы видимости уничтожаются.
(Если вдруг ниже в примере ничего не падает, значит уже все до падало :) — просто перегрузи страницу).

Заодно ссылки:
Русская документация
Английские видео уроки

This movie requires Flash Player 9

Поделиться в соц. сетях

Опубликовать в LiveJournal
Опубликовать в Google Plus
  • Антон

    А где почитать как подключить библиотеки к проекту? получается нелогично как-то — изучаем базовые знания, а кусок пропущен и как мне — новичку в работе с этим движком разобраться в этом простом вопросе?

  • VirtualMaestro

    Привет, Антон. Вторая строка сверху, я не шутил когда ее писал, так как это настолько фундаментальное знание, что оно даже не относится к программированию как такому. Поищи в нете как подключаются исходники к проекту.
    Это библиотека по сути просто набор исходников, автор с них даже не сделал SWC.
    Дам подсказку для FlexBuilder.
    На проекте правой кнопкой мыши -> Properties -> ActionScript Build Path -> Source Path -> Add Folder…

  • AlexiyIII

    Прикольно! Всё работает! А можно пример как отобразить MovieClip из библиотеки вместо того чтобы рисовать на Sprite.

  • VirtualMaestro

    Без проблем. Кстати, я сначала так и сделал но потом подумал что лучше немного упростить для понимания.
    Я весь проект для FlexBuilder заархивировал, потому там есть есть еще левые классы, которые не имеют отношения к Box2D, там главное это класс MyFirstBox2D и testForBox2d.fla.
    Все происходит элементарно:
    создаешь фла, в нем рисуешь два мувика — один кирпич, второй какую то статичискую балку, каркас или как хочешь называй. Дай им какие то названия классов, после это сделай экспорт в SWC файл. Этот файл подключи к проекту и в коде создавай экземпляры тех классов которые ты задал внутри FLA проекта (Kirpich, Planka).
    Там все просто в коде разберешься.

    Тут сорс http://www.sharemania.ru/0103535

    • AlexiyIII

      Увы у меня только Adobe Flash, там вроде разработчики переменную предусмотрели userData, можно експортировать MovieClip из библиотеки в ActionScript и присвоить этой переменной а потом добавить слой userData в отображение и потом в цикле присваивать ему координаты физического тела
      bodyDef.userData = new Kirpich();
      bodyDef.userData.width = 120;
      bodyDef.userData.height = 40;
      addChild(bodyDef.userData);

      for (var bodies:b2Body = myWorld.GetBodyList(); bodies; bodies = bodies.GetNext()){
      if (bodies.m_userData is Sprite){
      bodies.m_userData.x = bodies.GetPosition().x * 30;
      bodies.m_userData.y = bodies.GetPosition().y * 30;
      bodies.m_userData.rotation = bodies.GetAngle() * 180 / Math.PI;
      }
      }

      • VirtualMaestro

        Так это не проблема, в проекте все равно используется только один класс и подключенная библиотека. Можешь просто создать новый проект в FlashIDE и документ классу указать вот этот главный класс (MyFirstBox2D.as) и в свойствах проекта подключить готовую SWC (которую я создал testForBox2d.swc) или даже не надо подключать просто прямо в своем проекте создай какие хочешь кирпичи дай им какие то названия классов и используй их вместо моих классов Kirpich и Planka.
        Только еще удали в классе MyFirstBox2D вот такой мета тег вверху,
        [SWF(width="800", height="600", frameRate="30")]

        Да, про userData ты правильно написал, посмотри в классе есть как оно используется.

  • Pagefile

    Спасибо за урок, помогло. А откуда ты черпал первоначальные сведения? Только ссылка на русскую документацию?

  • VirtualMaestro

    Русская документация несомненно помогла — она более детально описала процессы и возможности Box2D, но этот пример сделал и детально задокументирован после изучения исходника товарища Johnny-k. Вот тут ты сможешь его посмотреть и скачать исходники — http://www.johnny-k.ru/?p=249

    Право не знаю стоит ли изучать сейчас эту версию Box2D, так как уже был релиз C++ версии 2.1, теперь жду когда выйдет и флешовская версия. Там много разных концептуальных новшеств. Хотя знаю что многие еще работаю на версии 2.0.2 так как считают ее более надежной (ввиду того что 2.1 только альфа) и быстрее версии 2.1. Но все этот надо будет сравнить когда выйдет релиз 2.1

    • Pagefile

      Спасибо! Я использую уроки http://www.emanueleferonato.com/category/box2d/, но искал чегото более фундаментального. Не знал что Johnny-K выкладывает исходники.
      Думаю что имеет смысл изучать текущую версию, т.к. она даёт отличный проверенный результат)) И опять же, много материалов в сети.

  • Серега

    Уважаемы VirtualMaestro.
    Вы пробовали запустить этот пример на Adobe Flash CS4 ?

  • Серега

    Блин,ну и сложная ж это задачка для начинающего, все работает. Проблема была в версии Box.

  • VirtualMaestro

    Нет не запускал. Честно говоря я очень редко (когда это просто необходимость) запускаю и разрабатываю проекты в Flash CS4. Обычно там только графику делаю, а работаю и компилирую либо в FlashBuilder или в FlashDevelop.

  • Mo3g

    классный урок. для того, чтобы начать копать Box2D — самое адекватное из того, что нашёл в сети.

  • VirtualMaestro

    Старался доступно и детально описать, так как сам знаю что не очень есть по этой теме :)
    Думаю что как время появится напишу о Box2D 2.1 так как это уже шаг вперед да и сам пользуюсь этой версией.

  • http://www.fungamesonline.eu Alxs

    Привет коллегам по «цеху»! Занимаюсь разработками игрушек. Наткнулся на твой блог, как раз только сам начал осваивать бокс2Д. Cпасибо за урок. Как продвинулся за это время в изучении… Я пока парюсь… Везде какая то урывочная инфа… Только разве по сухому мануалу изучать приходится… Если что, давай в друзья. Я на flashgamedev и на flashgameblogs под ником Alxs…

  • VirtualMaestro

    Привет, Alxs.
    Не знаю как сказать, насколько далеко, с одной стороны пишу обертку для него, а с другой стороны сильно вглубь пока не было причин лезть (может быть потому что сейчас другие задачи стоят). Этот урок стар, так как я писал его для версии 2.0.2, хотя сейчас работаю с версией 2.1а. Хотел урок по нему написать, да все руки не дошли. Версия 2.1 более продвинута и по моему более проще стала, возможно есть смысл тебе в ее сторону смотреть.
    Я сейчас параллельно изучаю новый двиг Nape (возможно ты видел несколько последних постов). Как на мой взгляд очень перспективный движок — в 2-2.5х быстрее, много удобных плюшек, есть вещи которые боксу не снились. Конечно есть свои минусы в лице малого сообщества, недочетов, так как движок совсем молодой, но это и плюс так как есть возможность влиять на его развитие (что я собственно и пытаюсь делать :) ), кстати, по нему еще как минимум два поста запланировано. В общем мне его архитектура на много больше нравится чем бокса. Но пока еще работаю с боксом так как уже были наработки, но обязательно буду думать о переходе. Чем меня бокс беспокоит, так это то что уже более 100 дней ничего не делается над ним, боюсь как бы он не умер.
    В друзья можно, на flashgamedev под тем же ником, а вот в flashgameblogs меня нету, там вроде как по инвайтам… короче пока не получилось туда попасть.
    Если есть вопросы по боксу задавай, попробую ответить. Конечно если ты целенаправленно решил изучить и изучаешь все фичи и нюансы бокса, то наверное ты уже дальше продвинулся чем я, у меня пока такой задачи не было.

    • carac

      to VirtualMaestro
      Добрый день. У меня образовался вопрос: как можно в box2d создать тела с такими формами как — овал, или сектор круга ( http://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D0%BA%D1%82%D0%BE%D1%80_%28%D0%B3%D0%B5%D0%BE%D0%BC%D0%B5%D1%82%D1%80%D0%B8%D1%8F%29 )?

      • VirtualMaestro

        В рамках Box2D это сделать не возможно, так как Box2D оперирует с двумя типа фигур — круг и полигон. В нем даже реализации грани нет нормальной (как бы есть но надо вручную доделывать). Но если допустить что грань есть тогда можно вручную слепить типа эллипс или другую любую фигуру, но это изврат.
        А по умолчанию такой возможности нет.

  • FieryWall

    Доброго времени суток!
    Ваш блог пришелся мне по душе, но есть одна неувязочка. В библиотеках Box2D.Collision.Shapes нету класса b2PolygonDef. И ругается компилятор при использовании b2World.
    Помогите пожалуйста продолжить изучение. С уважением, FieryWall.

  • VirtualMaestro

    Данная статья была написано с помощью библиотеки Box2D версии 2.0.2
    Может быть вы используете 2.1 (я правда сейчас не помню есть ли отличия в названиях классов)
    Скорее всего возможно вы как то не правильно подключили классы, потому что класс b2World должен полюбому быть в обеих версиях.

  • FieryWall

    Здравствуйте еще раз!
    Я поменял библиотеки и все нормально.
    Остается проблема с классом b2World, возможно не в нем проблема но при компиляции строки

    dinamicBody=world.CreateBody(body);

    Выдает ошибку:

    1061: Call to a possibly undefined method CreateBody through a reference with static type Box2D.Dynamics:b2World.

    Почему?

  • VirtualMaestro

    В какой среде пишете код?
    Пример кода из статьи компилируется у вас?
    (тут код если вдруг не нашли http://flashnotes.ru/downloads/examplebox2d/SimpleBox2D.as)

  • alex

    Я совсем запутался! помогите. Какую версию флеша и откуда скачать чтобы запустить Adobe box2d 2.1?????

  • VirtualMaestro

    Box2.1 существует две версии — одна для 9-го FlashPlayer, а вторая для 10-й версии.
    Вот отсюда можно скачать версию какую вам нужно (Box2D) http://www.box2dflash.org/download

    FlashPlayer можно скачать на официальной странице Adobe — http://get.adobe.com/ru/flashplayer/

    (это не Adobe Box2D — Adobe это компания которая разрабатывает FlashPlayer (а также Photoshop, Illustrator, FlashIDE и другие продукты).
    Box2D — это физическая библиотека, которая была написана Erin Catto на языке C++, а другие ребята портировали эту версию на ActionScript3, и теперь флеш разработчики тоже могут пользоваться этой физ. библиотекой)

  • vorodis2

    Разбераюсь в движке, не как не могу понять можно ли обьект в нутри мира остоновить, а потом запустить, тобиш не удолить и создать а что то типа visible, что бы этот объект не участвовоал в расчотах и не сжирал память.

  • VirtualMaestro

    Да, можно. У тела есть такой параметр как SetActive. Если ему присвоить false, то тела больше не будет принимать участие в расчетах.
    Когда то я делал так — если мне надо было деактивировать объект то вызывались последовательно методы:
    SetAwake(false);
    SetActive(false);

    SetAwake — это метод тела, который принуждает его заснуть (или проснуться). В данном случае вызывается он потому что снимает с объекта все силы, чего не делает метод SetActive. Например, если на объект подействовала какая нибудь сила и он двигался в соответствии с ней (напр. летел куда нибудь) и тут мы его деактивировали (был вызван метод SetActive(false)) , то после того как он будет обратно активирован (то есть вызван метод SetActive(true)) объект продолжит двигаться под действием той же силы. А метод SetAwake(false) нейтрализует силы.

  • alex

    спасибо большое за информацию. Можно еще один нелепый вопрос?

  • alex

    как вы начинали изучать flesh? может посоветутет что-нибудь почитать для начала?

  • VirtualMaestro

    Нашел первую русскую книгу по ActionScript, тогда это была Сборник Рецептов. (http://easyflash.org/flashlearn/flashbooks/87-actionscript-3.0-sbornik-receptov.-dzhoi-lott..html)

    Если ActionScript для вас это первый язык программирования, тогда наверное не буду советовать начинать изучать с Сборника.

    Возьмите любую книгу Колина Мука и точно не прогадаете (например вот эту http://easyflash.org/flashlearn/flashbooks/144-actionscript-3.0-dlja-flash.-podrobnoe.html).

    И конечно же практика. Что то изучили сразу попробовали что то написать.

    Напр., когда я немного почитал, пописал Хелоу Ворлды, решил написать простенький тетрис (ну как же, все мы писали простенький тетрис :) ). При написании вроде бы казалось столь простой программы очень многому научился.

    Ставьте себе задания и пробуйте выполнять их.
    Практика это основное.

  • http://deleted vorodis2

    VirtualMaestro Спасибки за совет, буду пробывать. Облизывал Nape но что то не понравился, вернее, понравился но проскоки при связке дух обьектов, совсем не гуд, завтра попробую перенксти на box2d.

  • VirtualMaestro

    Пожалуйста.
    Я перестал изучать Box2D так как не вижу перспектив его использования — он не развивается, а то что есть реальный тормоз. Да и кстати все порты Box2D которые существуют это реальные тормоза (WCK, Box2DFlash, Motor2).
    Конечно, если мы говорим о каком то простеньком пазле, тогда все ок, но не дай Бог что нибудь средней сложности — бокс висит.
    Если все же смотришь в сторону Box2D могу еще посоветовать SimpleBox2D, правда он основан на Box2D 2.0.2 но там мужичек чего то допилил, доделал (какие то улучшения и баги были исправлены, плюс методы облегчающие работу были добавлены) и вроде как на нем легче разрабатывать (http://www.psyked.co.uk/box2d/simple-box2d-custom-polygon-creation.htm). Сам сильно не копал. Но опять же проект не развивается, да и от библиотеки какого то супер прироста ускорения не жди.
    У Nape хватает вопросов (на которые так или иначе можно найти ответы), но и у бокса тоже далеко не все ровно.

  • http://deleted vorodis2

    Box2D пригоден действительно только для пазлов. Да и сложнее в упровлении. Единственый плюс относительно точная привязка. Да и спосибо за методы
    SetAwake(false);
    SetActive(false);
    Таки очищает и выводит обьект из расчетов. Но все равно както по сравнению с Nape не большой плюс))Вот результаты тестов Nape и Boxe2d 2.1a (может это и демо версия либы но..)
    http://vorodis2.com/Data/testFizic/

    VirtualMaestro можно еще пару вопросов по Nape
    Глянь демку там цепи снизу, их точки привязки слетают, (да и колеса).
    1. Вобщем как можно жостко прикрепить один обьект ко второму?
    2. Как усипить и пробудить элемент в Nape. На сейчас я его делаю статическим.
    arrBody[i].stopAll();
    И пробуждаю
    arrBody[i].allowMovement();
    arrBody[i].allowAll();
    arrBody[i].calcProperties();
    arrBody[i].update();
    Но пробуждения работает 50/50, может где туплю, пробывал методом тыка)))+доки с переводчиком ))

  • http://913st.com Юрий

    Спасибо за туториал!
    К моменту прочтения я уже успел во многом разобраться, но setBullet был приятной неожиданностью.
    Вопрос на засыпку:
    Как получать данные о столкновениях? Событие какое-нить или ещё чё, чтоб определить кто и во что врезался по факту столкновения.

  • VirtualMaestro

    У класса b2World есть метод SetContactListener, который как параметр принимает экземпляр класса b2ContactListener.
    Этот класс вы наследуете и переопределяете его методы (BeginContact, EndContact, PreSolve, PostSolve). Как параметры все эти методы принимают экземпляр класса b2Contact — в нем вам передаются информация кто и с кем.

    Дополнительно метод PreSolve принимает так же экземпляр класса b2Manifold — если не ошибаюсь то в нем содержаться информация о векторах нормалей и точки пересечения.

    А в методе PostSolve вторым параметром идет экземпляр класса b2ContactImpulse, который содержит информацию о импульсах после столкновения (точнее прочтите в документации).

    И того сигнатура этих методов:

    override public function PreSolve(contact:b2Contact, oldManifold:b2Manifold):void
    {
    }

    override public function PostSolve(contact:b2Contact, impulse:b2ContactImpulse):void
    {
    }

    override public function BeginContact(contact:b2Contact):void
    {
    }

    override public function EndContact(contact:b2Contact):void
    {
    }

  • kem

    Монтажный кадр 1, слой «Слой 1″, кадр 1, строка 45 1120: Обращение несуществующего свойства groundBody.

    какую библиотеку подключать?

  • VirtualMaestro

    В зависимости от того для какого плеера пишите — если для 9 то качайте и подключайте Box2D для 9-тки, если для 10 тогда соответствующую версию Box2D для 10. Если не уверены тогда качайте для 9-тки точно не ошибетесь.
    А вообще то тут всего один класс, там сложно чему не заработать. Совет — не пишите код в FlashIDE, возьмите любой редактор, например, бесплатный FlashDevelop и ваяйте в нем.

  • http://deleted vorodis2

    Да уже нашол)), работает стобильно, так же мне еще понравился вот этот метод
    wakeConstraint
    пробуждает связи.
    Не знаеш что за зверь
    addGroup
    Может жосткость кроеться где то там)) Хотя лично я вобще сомневаюсь что она существует, так как я еще не в одной демке ее не видел. Но если она есть то скорее всего завязана имено на group (только очухался после болезни, завтра ее опробую)))

  • VirtualMaestro

    Метод addGroup добавляет в мир группу объектов. Группа (класс Group) дает возможность управлять несколькими объектами так как будто управление происходит над одним объектом. Это очень удобно.
    Например, допустим тебе надо сделать так, чтобы все объекты (которые находятся в группе) перестали сталкиваться и больше не генерировали события столкновения.
    Для этого у класса Group есть такое свойство ignore, которое надо установить в true. Вот и все. Объекты сталкиваться не будут.

    Также у группы можно отслеживать события столкновения (также как и у объектов), например, когда группа столкнулась с другой группой.
    Только если для обработки двух столкнувшихся объектов мы используем объект obj_arb, то для двух столкнувшихся групп надо использовать group_arb.

    Я сильно пока не влезал в группы (может потом напишу более подробно), потому для дополнительной информации можно посмотреть вот эти ссылки:
    http://deltaluca.me.uk/doc/pckg/nape/phys/Group.html
    http://deltaluca.me.uk/doc/docs/Chapter%205.%20Viewport,%20collision%20layers%20and%20Callbacks.html

  • vorodis2

    Да хорошое свойство
    ignore
    Если вдруг найду жосткую связь отпишу, если вдруг найдеш отпиши.

  • Zumso

    Доброго времени суток. Никак не могу задать нужный угол телу, например платформе из данного примера. Пробовал с помощью angle, но что-то не выходит. Подскажите пожалуйста как в данном примере задать угол платформе. Заранее спасибо

  • VirtualMaestro

    Для Box2d версии 2.0.2 (рассмотренная в данном примере) надо использовать метод SetXForm (класса b2Body).
    Для версии 2.1 есть метод SetAngle.

  • alex

    скажите пожалуйста, а как в этом примере вместо падающих квадратов поставить свою картинку?
    пробывал так:
    groundDefination.userData = groundGr;
    groundDefination.userData.height=10;
    groundDefination.userData.width=300;
    addChild(groundDefination.userData);

  • Stip vokin

    Всем привет! А подскажите как запустить эту прогу?

  • Aspiring

    Дружище, спасибо большое за этот пост. Очень помогло вообще понять что такое Box2d и как его использовать.

    Насчет второго предложения ты зря, конечно :) Например, я могу добавлять исходники в проекте Qt, но я никогда не пользовался готовыми движками поэтому и добавлял «пофайлово».

    Спасибо за ссылки, особенно видео

  • eXo

    Спасибо! :)

  • akuba

    спасибо, отличная статья — для начинающих в самый раз

  • Андрей

    Поражает что время на описание точней копирование с документации нашлось, как подключить исходники Box2D библиотеки к своему проекту или вообще поэтапно для начинающего считают западлом)))))))) Проходи мимо…в руководстве VS описывается процес двумя строчками

  • VirtualMaestro

    Мы все учимся с того, что есть и в частности документация. Я никогда не копирую, а все пропускаю через себя и только потом, спустя какое то время доношу к читателю уже из своего личного опыта (на написании этой статьи ушло много времени и не поверишь, не знаю как сейчас, а на то время лучшей русскоязычной статьи для начинающих не было. Потому, собственно, и решил написать).

    А на счет «западло написать о подключении» я скажу так — обучение происходит всегда шаг за шагом — если ученик не знает основ, то смысла идти дальше нету.
    Проще говоря, если человек не знает написать программу типа «Hello, world!», какой смысл учить парадигмы ООП? В данном случае подключение библиотеки, это уровень «Hello, world!» (а может и ниже), а сложность изучения Box2d (напротив этого) несравнимо выше. Потому я и написал, если не знаешь как это сделать, тогда бессмысленно читать дальше.

  • Stazis

    Не понимаю одной веши: .1 м = 30 пк
    1 м = 300 пк
    если Box2D оперирует метрами то делить по идеи надо на 300, а не на 30.

  • GoodWin

    Box2D оперирует метрами, где соотношение у него 1 метр = 30 px, какие еще 300 px??? Вообще пиксели в метры трудно перевести из-за разных размеров пикселей и разрешения на мониторе. Из-за этого здесь задали соотношение 1:30.

  • Справлюсь

    VirtualMaestro, я как понял вы пишете на Java’е где можно найти документацию для C++