Как я уже говорил ранее, к одному телу можно прицепить сразу несколько геометрий. Ну не всеже объекты так просты как круг или квадрат. Есть множество объектов, которые легко построить из простых. Допустим возьмем объект, из сэмпла к физ.движку. Это перекрещенные под прямым углом палки, на концах, которых 4 желтых шарика, и один шарик в центре. Вы удивитесь как легко это сделать, начнем.
Сделайте новый проект, и прицепите модуль farseer-а. Приинклудьте так же помощник рисования и описания цветов:
SuperStrict ' я всегда его использую ;)
Import aco.farseerphysics ' подключим физ.движок farseer
Include "DrawingSystem\Color.bmx"
Include "DrawingSystem\DrawingHelper.bmx"
Теперь опишем наш с вами тестовый объект переменными:
Global ObjectTexture:TImage
Global ObjectCrossBeamTexture:TImage
Global ObjectBody:TBody
Global ObjectGeom:TGeom[7]
Здесь все очевидно, одно тело (Tbody) и 7 геометрий(TGeom) к нему. 5 шариков +2 палки = 7. Соответственно и две текстуры, одна для палок и одна для изображения шарика.
Опишем сначала весь наш главный игровой цикл. По образу и подобию, которые я привдил в самом начале, как рекомендуемые автором. А потом разберем все по частям.
Global physics:TPhysicsSimulator ' это будет симулятор физики
physics = TPhysicsSimulator.Create( Vector2.Create(0, 100) )
Global deltaTime:Float = 0.016
Graphics(800, 600) ' включим оконный видеорежим 800х600
CreateObject()
SetClsColor( 255 , 128, 128 ) ' очищать экран бледно-розовым.
While Not(KeyDown(KEY_ESCAPE))
physics.Update( deltaTime )
Cls
DrawObject()
Flip
Wend
В основном должно быть все понятно. Единственное что я добавил , это цвет очистки экрана(фона), он будет бледно розовым. Нас сейчас интересуют две функции CreateObject() - которая создает объект и DrawObject() - которая этот объект рисует. Начнем по порядку, то есть с создания.
Function CreateObject()
' создать текстуры объекта: желтый(TColor.Yellow) круг с черной(TColor.Black) окантовкой
ObjectTexture = TDrawingHelper.CreateCircleTexture(16, TColor.Yellow, TColor.Black, 2)
' и темносерый(TColor.DarkGray) прямоугольник с черным периметром(TColor.Black)
ObjectCrossBeamTexture = TDrawingHelper.CreateRectangleTexture(16, 120, TColor.DarkGray, TColor.Black, 2)
' текстуры отцентровать
MidHandleImage(ObjectTexture)
MidHandleImage(ObjectCrossBeamTexture)
' создать тело для нашего обхекта
ObjectBody = TBodyFactory.CreateRectangleBody(physics, 80, 80, 5)
' задать начальную позицию
Objectbody.SetPosition(Vector2.Create(800 / 2, 110))
' создать 7 геометрий: два перекрещивающихся прямоугольника и пять шариков (5+2=7)
ObjectGeom = New TGeom[7]
' создаем геометрию круга, указываем ее параметры и привязываем к телу
ObjectGeom[0] = TGeomFactory.CreateCircleGeom(physics, ObjectBody, 16, 10, Vector2.Create(- 40, - 40), 0)
ObjectGeom[0].SetRestitutionCoefficient(.2)
ObjectGeom[0].SetFrictionCoefficient(.2)
' расставляем по периметру объекта используя ObjectGeom[0] как образец, а последний в центре и привязываем к телу
ObjectGeom[1] = TGeomFactory.CloneGeom(physics, ObjectBody, ObjectGeom[0], Vector2.Create(- 40, 40), 0)
ObjectGeom[2] = TGeomFactory.CloneGeom(physics, ObjectBody, ObjectGeom[0], Vector2.Create(40, - 40), 0)
ObjectGeom[3] = TGeomFactory.CloneGeom(physics, ObjectBody, ObjectGeom[0], Vector2.Create(40, 40), 0)
ObjectGeom[4] = TGeomFactory.CloneGeom(physics, ObjectBody, ObjectGeom[0], Vector2.Create(0, 0), 0)
' теперь перекрещиваем прямоугольники
ObjectGeom[5] = TGeomFactory.CreateRectangleGeom(physics, ObjectBody, 16, 130, Vector2.Zero(), MathHelper.PiOver4)
ObjectGeom[6] = TGeomFactory.CreateRectangleGeom(physics, ObjectBody, 16, 130, Vector2.Zero(), - MathHelper.PiOver4)
End Function
Я сделал комментарии как можно более подробно. Но большинство этих функций вам уже хорошо знакомы. Можно наблюдать как все геометрии (ObjectGeom[n]) присоединяются к одному телу (ObjectBody). Сначала сделали один шарик [0] и задали ему параметры трения и упругости. Остальные же шарики [1-4] были просто клонами первого.
TGeomFactory.CloneGeom:TGeom(physics:TPhysicsSimulator, body:TBody, geom:TGeom, offset:Vector2 = Null, rotationOffset:Float = 0)
вот функция: клонирования геометрии, которую мы использовали для клонирования шариков. Принимает: симулятор физики, тело, оригинал геометрии, сдвиг, поворот. Для прямоугольников совсем просто, создать геометрии и повернуть их, чтоб перекрестились.
Объект создан и должен быть нарисован!
Function DrawObject()
' сначала рисуем перекрестие прямоугольников
For Local i:Int = 5 To ObjectGeom.Length - 1
TDrawingHelper.DrawGeom( ObjectGeom[i] , ObjectCrossBeamTexture )
Next
' затем рисуем шарики на концах и один в середине
For Local i:Int = 0 To 4
TDrawingHelper.DrawGeom( ObjectGeom[i] , ObjectTexture )
Next
' вернем начало координат и поворот к стандартным значениям
SetOrigin(0, 0)
SetRotation(0)
End Function
К комментариям, мне даже нечего добавить.
Теперь было бы неплохо и поуправлять нашим объктом с клавиатуры к примеру и вращать его по часовой или против часовой стрелки. А для того чтобы сдвинуть физический объкт, в нашей поседневной жизни, к нему надо применить силу, как не удивительно это звучит, но метод который это делает в движке farseer, называется так ApplyForce(forceVector) (Apply - применить, Force - сила)и передается в него вектор. Конечно, это метод для тела (TBody).
Function UpdateObject()
Local force:Vector2 = Vector2.Zero()
Local speed:Float = 1000
If KeyDown(KEY_UP) Then
force.Y:-speed
End If
If KeyDown(KEY_DOWN) Then
force.Y:+speed
End If
If KeyDown(KEY_LEFT) Then
force.X:-speed
End If
If KeyDown(KEY_RIGHT) Then
force.X:+speed
End If
ObjectBody.ApplyForce(force)
Local torque:Float = 0
Local torqueAmount:Float = 1000
If KeyDown(KEY_A) Then torque :- torqueAmount
If KeyDown(KEY_D) Then torque :+ torqueAmount
ObjectBody.ApplyTorque(torque)
End Function
Тут дело такое. Сила - это вектор, который в первую очередь указывает направление, а во вторую очередь, можно приложить разного масштаба силу к объекту. Так же вот и вся функция. ApplyTorque - применяет к телу вращение(Крутящий момент), я повесил на кнопки A и D. Вставьте вызов этой функции, до CLS.
Категории коллизий.
Объектов на уровне может быть великое множество, и по правилам игры, возможно, некоторые из них не должны контактировать с другими, ну а с третьими просто обязаны. Вы понимаете к чему я клоню?
Каждая геометрия может быть отнесена к 32 категориям коллизий. И каждый объект может определить, с какими категориями он может столкнуться. Это довольно гибкая система определения столкновений между геометриями. Сам же автор признает, что этот метод он заимствовал в другом физ.движке ODE. И надо сказать, что метод действительно прост в использовании. По умолчанию все геометрии сталкиваются(коллизируют) между собой. Категории имеют тип int(32 бита), так что пользователь может указать произвольный характер взаимодействий для 32 объектов. Если есть более 32 объектов, то некоторые из них, безусловно, будут иметь ту же категорию.
Используйте методы геометрии
SetCollisionGroup( collisionGroup )
SetCollisionCategory( collisionCategories )
SetCollidesWith( collidesWith )
Например для некоей геометрии вы можете указать категорию коллизий 5, и указать обработку столкновений со своей категорией(5) с третьей(3) и первой(1) (объединяются категории знаком | (or) )
это будет выглядеть так:
Geom.SetCollisionGroup( 1 )
Geom.SetCollisionCategory( CollisionCategories.Cat5 )
Geom.SetCollidesWith( CollisionCategories.Cat5 | CollisionCategories.Cat3 | CollisionCategories.Ca1)
Если же вы хотите указать, только ту геометрию с которой сталкновений не будет, то следует писать так:
Geom.SetCollidesWith(CollisionCategories.All & ~CollisionCategories.Cat1)
Если хотите узнать об этом более подробно, то смотрите Демку номер 5. :)
ToDo: про joint-ы (суставы).
Выведение.
Как написано в единственном к Farseer-у оффициальном примере "The rest is really just details." Что на русском означает - "Остальное просто детали." Так что дальше ковыряйтесь сами!
Спасибо, за внимание! Удачи!