« FOAM: физика и actionscript 3. Часть 2 | Velocity Фильтр » |
FOAM: физика и actionscript 3. Часть 1
FOAM: физика & actionscript 3. Часть 1Почти год назад я написал серию из трех статей посвященных основным физическим законам и их практическому применению при разработке flash-приложений. Тогда фокус внимания был посвящен flash 8, а код писался на actionscript2. Несколько раз я порывался написать статью, посвященную физике и flash, но использующую не “собственные поделки”, а flade (известный и, по сути, единственный качественный) физический движок для flash 8. В flade уже предусмотрены типовые операции: обнаружение коллизий объектов, расчет движения тел после столкновений, действие сил и ограничений. Но не сложилось: находились более интересные темы для статей. Затем прошло время, и actionscript 2 ушел в прошлое.
Теперь, если вы начинаете новый flash проект, то в расчет следует брать только actionscript3. Здесь же ситуация с движками (не только физика, но 3d-графика) гораздо лучше: навскидку можно назвать несколько проектов заслуживающих внимание: box2dflash.sourceforge.net/, www.cove.org/ape/, blog.generalrelativity.org/?cat=12 , fisixengine.com/, lab.polygonal.de/motor_physics/. В практике я сталкивался только с движками под номером 2, 3, 4. Первый из них (ape) был разработан Aleс Cove - это автор также и единственного толкового физического движка для flash 8 - flade. К сожалению, развитие flade было прекращено несколько лет назад, хотя была попытка переписать данный движок на haxe (язык программирования, для которого есть компилятор, формирующий исполняемый на flash player файл). Развитие же ape продолжается и по настоящий момент (также есть результаты переноса данного движка на c++ и java). Если почитать отзывы на сайтах, “погонять” демки (посматривая одним глазом загрузку процессора) и попробовать сделать несколько приложений, то впечатление будет самое положительное.
Fisix … отношение к данному движку двойственное: с одной стороны, если оценить функциональность движка по количеству готовых для использования функций, то fisix превосходит и ape и foam. С другой стороны fisix не доступен в виде исходных кодов – есть только скомпилированная версия библиотеки в виде swc-файла. Чем это плохо? Если вы хотите серьезно заниматься разработкой “физических” игр или приложений для flash, то будьте готовы, что выбор движка нельзя делать только по сложной и красивой “демке”. Традиционно демку делают так: на сцене размещается набор объектов (прямоугольники, круги, возможно, кривые), некоторые из этих частей образуют более сложные объекты (четыре круга плюс прямоугольник – вот вам машинка). Добавим к объектам ограничение в виде рычага или “резинки”, “намешаем” немного сил трения и гравитации – вот и готова демка. После ее запуска объекты на экране двигаются, сталкиваются, скатываются по наклонным поверхностям – казалось бы, вот она – симуляция. Но нет. В реальности для построения качественного геймплея вам потребуется в движке развитые средства извещения о происходящих событиях. Например, столкнулись два объекта (машинка со столбом) – тут же должна вызваться специальная функция, которая посчитает степень повреждений для обоих объектов и уменьшит у машинки количество жизней или вообще прекратит игру: мол, авария, машинка уничтожена. Нужна возможность гибко менять характеристики объектов и некоторые физические законы или константы: вот машинка сталкивается со стенами, отскакивает от них, а через минуту правила игры меняются и машинка становится “настоящим приведением”, проходя через все игровые объекты без повреждений и учета коллизий. Пригодится и функция управления временем: так чтобы можно было “откатить” время назад. Почти всегда нужны средства гибкого управления силами, действующими на моделируемые объекты: они могут быть постоянными, временными, действующими в рамках определенной области, изменяющимися во времени или действующими избирательно (в рамках определенной области, в течении некоторого интервала). Собственно, список таких требований можно продолжать и пополнять по мере создания качественной flash-игры и все эти возможности вам придется добавлять к “чужому” движку самостоятельно. Когда я интересуюсь у знакомых профессионально занятых в flash gamedev: “Ну, как оно, какой движок самый, самый ?”. Они в ответ смеются: “в качестве основы мы когда-то взяли движок X, но спустя время от него уже ничего не осталось, все переделано и улучшено”. Еще негативным моментом в fisix оказалось то, что развитие проекта то ли продолжается, то ли заморожено … не понятно. Одним словом, последняя выложенная версия почти двухгодичной давности и это не радует. Что касается FOAM, то с ним я столкнулся несколько месяцев назад, когда мне нужно было сделать небольшой проект. Времени было достаточно, и я решил поэкспериментировать с новым для себя физическим движком, покопался в его “внутренностях”, добавил несколько полезных функций и решил оформить свои “путевые заметки” как статью.
Для того чтобы получить самую свежую версию библиотеки вам нужно загрузить ее из svn-хранилища foam-as3.googlecode.com/svn/trunk. Исходные коды библиотеки неплохо документированы, плюс, вместе с библиотекой идет и пример ее использования. Весь дальнейший код я пишу в flashdevelop и компилирую с помощью flex sdk, хотя с равной долей успеха я мог бы писать код и в flash cs3 или flex builder. Не забудьте подключить к проекту путь к каталогу, где находятся исходники библиотеки, и давайте начнем с самого простого. Физический движок не может быть оторван от подсистемы визуализации хода симуляции. FOAM использует подход с тем, что необходимо на сцене разместить объект типа org.generalrelativity.foam.Foam (этот класс производен от Sprite). Далее я привожу пример заготовки, которая будет развиваться по ходу статьи. Конструктор главного класса приложения создает объект FOAM, размещает на сцене и устанавливает обработчик события “начало очередного кадра” в виде функции run.
import org.generalrelativity.foam.*;
[SWF(width="800", height="662", backgroundColor="#334433")]
public class MainCode extends Sprite {
private var foam:Foam = null;
public function MainCode() {
добавляем обработчик события начало нового кадра
addEventListener(Event.ENTER_FRAME, run);
foam = addChild( new Foam() ) as Foam;
} end of -- constructor --
private function run(evt:Event):void {
}
} end of – class --
Вторая строка в примере устанавливает количество итераций (Foam в рамках одного шага симуляции на самом деле выполняет несколько шагов, результаты которых комбинируются для более точного расчета движения тела). Последняя строка устанавливает “то, что отвечает за обнаружение столкновений”. Объект AABRDetector проводит “широкое обнаружение” и затем вызывает “то, что обнаруживает точные столкновения” (в примере это не показано).
foam.defaultSolver = RK4;
foam.solverIterations = 2;
foam.setCoarseCollisionDetector (new AABRDetector ());
public function addElement( element:ISimulatable, collide:Boolean = true,
render:Boolean = true, renderData:* = null, solver:IODESolver = null ) : void
На рис 1. я привел иерархию встроенных в FOAM примитивов. В основе всего лежит интерфейс ISimulatable. Любой объект, поддерживающий его, (вообще-то это абсолютно все физические объекты на сцене) будут иметь такие характеристики как:
Свойство | Комментарий |
Поля | |
x,y | координаты объекты (точнее центр его локальной системы координат). |
vx,vy | скорость движения тела по оси OX и OY, соответственно |
mass | масса тела |
force | вектор (две компоненты x,y) задающие силу, действующую на данный объект вот в этот, именно этот, момент времени. |
elasticity | степень эластичности материала, из которого изготовлен объект. Этот параметр влияет на поведение тел при столкновение. Действительно, ведь если столкнутся два шарика из ваты, то их поведение будет отличным от столкновения двух шариков из каучука. Значение должно быть между 0 и 1. |
friction | коэффициент трения (значение от 0 до 1). |
Методы | |
addForce | В качестве параметра методу передается объект Vector задающий значение силы оказавшей разовое действие на объект (например выстрел из пушки). Из второго закона Ньютона F = a*m следует, что фактическая величина ускорения объекта будет обратно пропорциональна его массе (также, свойство ISimulatable). |
addForceGenerator | В отличие от addForce оказывавшей разовое воздействие на объект, генератор силы влияет на объект все время симуляции (например, двигатель у ракеты). |
removeForceGenerator | А этот метод служит для удаления привязанного к объекту генератора силы (у нашей ракеты выгорело все топливо). |
Свойство | Комментарий |
q | Величина вращения объекта в радианах. |
av | Угловая скорость объекта. |
vertices | Список вершин объекта. |
edges | Массив граней объекта. |
addTorque | Этот метод добавляет к телу вращательный момент. |
addForceAtPoint | Первым параметром метода задается значение силы действующей на тело, второй же параметр – точка приложения силы. |
создаем два объекта круга
var circ_1 : ISimulatable = new Circle (100, 100, 50, 100, 0, 1);
var circ_2 : ISimulatable = new Circle (100, 300, 50, 100, 0, 0);
добавляем их на сцену
foam.addElement (circ_1);
но при добавлении второго я говорю, что не нужно учитывать действие
foam.addElement (circ_2, false);
задаем набор координат для произвольного полигона
var points_local : Array = [
new Vector (-30 , -10),
new Vector (-20, - 25),
new Vector (20, - 35),
new Vector (60, - 35),
new Vector (60, -5),
new Vector (40, 5),
new Vector (20, 25),
new Vector (20, 35),
new Vector (10, 35),
new Vector (-50, 35),
new Vector (-60, 5)
];
теперь на основании списка вершин создаем это тело
var ri : RigidBody = new RigidBody(200,100,10, points_local);
foam.addElement (ri);
создаем прямоугольник
var ri2 : IBody = new RigidBody (200, 300, 10, ShapeUtil.createRectangle (200, 50));
foam.addElement (ri2);
создаем шестиугольник
var ri3 : IBody = new RigidBody (200, 400, 10, ShapeUtil.createSymmetricPolygon (6, 50, 0.3));
foam.addElement (ri3);
Обратите внимание, что круг помеченный “звездочкой” заполз на другую фигуру, в то время как первый круг аккуратно огибает полигон по краю. Это происходит потому, что второй круг был исключен из списка “способных к коллизии” объектов.
Теперь попробуем оказать воздействие на любой из объектов, для этого нужно вызвать метод addForce с указанием значения силы разложенной по осям OX,OY.
ri3.addForce (new Vector (100, 0));
внимание, координаты задаются в локальной системе координат самого объекта
ri2.addForceAtPoint (new Vector (-90, 20), new Vector (100,50));
« Семантическая сеть. Часть 4 | FOAM: физика и actionscript 3. Часть 2 » |