Обработка столкновений в D3D:RM
Привет тебе читатель!
Эта статья посвящена просчитыванию столкновений в d3drm средствами DirectX7
под VB6. Оговорюсь сразу: написать действующий пример, пользуясь только этой
статьей, не выйдет, а чтобы понять о чем идет речь и посмотреть все в действии
надо скачать этот
проект. Названия функций не претендуют на лексическую верность с точки зрения
английского языка. А кое-где я находил оплошности походу написания статьи, но
тратить время на испревление не стал, проект ведь работает 8-). Ну вот и все
предостережения. Начнем…
Теория
Столкновения в d3drm происходят следующим образом: объявляется объект D3DRMRAY,
устанавливаются две координаты Dir и Pos. Pos - это координаты начала луча,
Dir - направление вектора, относительно Pos в котором нужно "щупать".
Далее посредствам функции RayPick производится само щупанье, с указанием режима.
Этих режимов всего пять. Чаще всего используется режим D3DRMRAYPICK_ONLYBOUNDINGBOXES,
при его использовании метод RayPick считает проткнутыми все объекты, у которых
оказались проткнутыми габаритные контейнеры (Box). Но для нашего случая, когда
необходимо, чтобы человечек бегал по неровной поверхности, являющейся одним
объектом (Direct3dRMFrame, или Direct3dRMeshBuilder), нам необходимо воспользоваться
другим режимом.
Я воспользовался режимом D3DRMRAYPICK_IGNOREFURTHERPRIMITIVES. Честно говоря
могу только догадываться, чем он отличается от остальных, но он позволяет сделать
то что нам надо, и это главное! Далее необходимо получить список проткнутых
объектов при помощи финкции GetPickFrame (или GetPickVisual, взависимости от
того какие объекты мы хотим рассматривать: Direct3dRMFrame, или Direct3dRMeshBuilder).
Далее я воспользовался методом GetName, для идентификации объектов. Ну вот и
вся теория. Я думаю, что практика внесет больше ясности.
Практика
Итак посмотрим на код. Падение разных объектов у меня сделано следующим образом:
Каждый объект, способный падать, снабжен функцией Turn, которая вызывается по-очереди
для каждого объекта в функции earth главного окна:
Public Sub earth()
.
Arr.Turn
Kubb.Turn
Xlam.Turn
.
.
.
End Sub
сама функция earth вызывается при каждом обороте основного цикла "While
Runing = True", находящегося в функции Run главного окна.
Функция Turn каждого объекта предназначена для создания одновременного движения
всех объектов, то есть каждый объект, получив управление на себя, должени сделать
свои чрезвычайно коротковременные задачи (такие как падение на один метр) и
отдать управление дальше.
Класс NPCBody - это класс неуправляемых человечков (тех, что появляются при
нажатии кнопки "u"), и функция Turn очень сложна в этом классе, потому
что в нее вставлены мозги челвечков. Но нас интересует в ней только строка Call
Falien - эта строка вызывает функцию того самого падения на один метр. Давайте
посмотрим ее:
Public Function Falien()
Dim TempVector1 As D3DVECTOR
Call Tors.GetPosition(Scene, TempVector1)
H = GetPickedLen(TempVector1.x, TempVector1.y, TempVector1.z,
0, -1, 0, "World")
If H + 13 > TempVector1.y Then
GoTo 40
Else
Call Tors.SetPosition(Tors, 0, -1, 0)
End If
Call Tors.SetPosition(Tors, 0, -1, 0)
40
End Function
Далее следует рассмотреть функцию GetPickedLen, находящуюся в модуле Functions.
Она является еще одним упрощением, для работы с классом RayPic1. Ее можно использовать
в ваших собственных программах если вы сталкиваетесь с той же задачей, что и
я - с необходимостью определять только координату Y столкновения. (Но для этого
надо еще добавить в ваш проект класс RayPic1, и добавить в начало функции строку
"Dim SP as Direct3DRMFrame3")
Public Function GetPickedLen(x0 As Single, y0 As Single, z0
As Single, x As Single, y As Single, z As Single, FrameName As String) As
Single
Dim k As New RayPic1
Dim A13 As D3DVECTOR
Dim B13 As D3DVECTOR
A13.x = x0
A13.y = y0
A13.z = z0
Call k.SetPos(A13)
B13.x = x
B13.y = y
B13.z = z
Call k.SetDir(B13)
Set SP = k.FindFrame(Scene, FrameName)
If k.NonZero Then
If SP.GetName = FrameName Then
GetPickedLen = k.VpositionY: GoTo 40
End If
End If
GetPickedLen = -1
40
End Function
Итак возрадуйтесь!! Нам осталось рассмотреть только одну функцию - FindFrame,
это функция класса RayPick1.
Public Function FindFrame(ref As Direct3DRMFrame3, Name As String)
As Direct3DRMFrame3
Dim i18 As Long
Dim tt As Long
Dim TF1 As Long
ra.Dir = Dir2SetDir и SetPos, ra.pos = Pos2
NonZero = False
Set arry = ref.RayPick(ref, ra, D3DRMRAYPICK_IGNOREFURTHERPRIMITIVES)
If arry.GetSize > 0 Then
For TF1 = 0 To arry.GetSize - 1
Set TempFrame1 = arry.GetPickFrame(TF1, Picc )
tt = TempFrame1.GetSize - 1
' Prin = ""
For i18 = 0 To tt
If TempFrame1.GetElement(i18).GetName = Name Then
VpositionX = Picc.vPostion.x
VpositionY = Picc.vPostion.y
VpositionZ = Picc.vPostion.z
Set FindFrame = TempFrame1.GetElement(i18)
NonZero = True
GoTo 50
End If
Next i18
Next TF1
End If
50
End Function
Ну вот и все.
Для тех, кто не бросил на полпути
Господа, я согласен с вами: примерчик получился сложноват для понимания, но
я старался как мог, расписывая его, и меня оправдывает тот факт, что когда я
писал прогу, я не знал, что придется ее кому-то показывать.
Небольшое отступление
Все вышеизложенное касается только того момента, когда человечек свободно падает,
а если он решил подобрать какой-нибудь кубик, он всегда будет находться на поверхности
земли. Это достигается те ми же методами. Основная мысль при этом заключается
в том, что вектор Pos устанавливается в заведомо более высокое, чем земля, положение,
а вектор Dir направляется вниз, потом получается координата "протыкания"
лучом земли, и человечик устанавливается на нужную высоту. Весь этот процесс
происходит в функции LeftBedro_Turn класса NpcBody:
<…>
StepLen = GetPickedLen(TempVector.x, TempVector.y, TempVector.z, 0, -1, 0,
"World")
If StepLen <> -1 Then
Call Tors.SetPosition(Scene, TempVector.x, StepLen + 13, TempVector.z)
Call Tors.SetPosition(Tors, 0, 0, -5)
End If
<…>
Ну вот теперь точно конец!
Тем, кому ОЧЕНЬ надо, могу предложить свою помощь в понимании написанного,
или просто в понимании данного вопроса. Пишите! Помогу, чем смогу.
and@profits.com.ru
Скачать проект:
collide_s.zip (172k)
PS: Смотрите инструкции в файле readme.txt после распаковки!
Posted: 18.03.2k1
Autor: Volodin Andrey
<and@profits.com.ru>
|
 |
 |
|