Показать сообщение отдельно
Старый 01.02.2009, 03:59   #9
ABTOMAT
Ференька
 
Аватар для ABTOMAT
 
Регистрация: 26.01.2007
Адрес: улица Пушкина дом Колотушкина
Сообщений: 10,741
Написано 5,461 полезных сообщений
(для 15,675 пользователей)
Ответ: Учебник по PhysX Wrapper для Blitz3D

Теперь последнее и самое интересное
pxBodyAddForceAtPos(body%,vx#,vy#,vz#,px#,py#,pz#, mode%)
Прилагает к телу глобальную силу в глобальных координатах в точку в глобальных координатах. Все параметры аналогичны параметрам вышерассмотренных функций:

body - тело, на которое применяется сила, vx, vy, vz - глобальный вектор силы, px,py,pz - глобальные координаты точки куда прилагать силу, mode - режим.

А чем же эта функция так интересна? А тем, что позволяет вытворять очень интересные вещи.

Вернёмся к первому посту. В нём я упомянул, что во многих экшенах можно стрелять по физическим объектам и они отскакивают от пуль, да вы, наверное, и сами не раз замечали и на первых похар баловались эжтой возможностью. Так вот, это всё делается при помощи команды pxBodyAddForceAtPos.

Но всё по порядку. Для начала опять уберём всё что связано с созданием кубика, движением кубика силами, его подпрыгиванием и масштабированием, то есть вернём его в исходное состояние. Проще взять обратно пример №2.

Теперь дадим возможность игроку свободно летать по сцене. Далеко ходить не надо, уже давно существуют удобные функции управления движением камеры и её поворотом, вам, наверное, они хорошо известны:

Function control(ent) ; Функция управления WASD
        If KeyDown(17) MoveEntity ent,0,0,1
        If KeyDown(31) MoveEntity ent,0,0,-1
        If KeyDown(30) MoveEntity ent,-1,0,0
        If KeyDown(32) MoveEntity ent,1,0,0
End Function

Function mouselook(ent) ; Функция обзора мышью

	mxspd#=MouseXSpeed()*0.25
	myspd#=MouseYSpeed()*0.25

	MoveMouse GraphicsWidth()/2,GraphicsHeight()/2	
	
	campitch#=EntityPitch(ent)+myspd#
	
	If campitch#<-85 Then campitch#=-85 ; ограничения поворота, чтобы камера не крутилась до бесконечности вверх и вниз, а останавливалася глядя вниз
	If campitch#>85 Then campitch#=85

	RotateEntity ent,campitch#,EntityYaw(ent)-mxspd#,EntityRoll(ent)
End Function
Пусть игрок свободно перемещается по сцене:
control cam : mouselook cam
Ну, и стрелочку мыши уберём заодно
HidePointer()
Так, окей. Теперь подумаем, что мы ходим сделать. Выстрелы, как, например, в HL2 (с физической точки зрения). Значит пуля будет лететь в центр экрана (или близко к тому). Как же применять филы? План таков:
  • Пикаем из камеры то, что находится перед ней
  • На пикнутый объект применяем силу в координатах, где пикнуло и по направлению куда смотрит камера.

Как пикать? Конечно, первое, что приходит в голову - это CameraPick. Но это надо выставлять всем кубикам пикмоды по полигонам (а это тормоз), потом получив меш - перебирать все типы (от полного перебора тоже можно уйти, но это опять же гемор) пока не найдём пикнутый и затем наконец применять силу.

Но ведь в физиксе уже есть встроенный пик по лучу! Давайте ознакомимся с ним поближе.

Для начала надо создать луч. Это делает команда:
pxCreateRay()
Она создаёт луч. Возвращает его хендл.
Создадим тоже луч, пусть он будет глобальный:
Global ray = pxCreateRay()
Теперь надо сделать функцию выстрела, где как раз и будет пикаться всё что нам надо и применяться сила. Пусть эта функция будет называться Shoot.
Итак, сначала пикаем. Для этого нужно переместить луч в позицию камеры. Это просто:
pxRaySetPosition(ray%, x#, y#, z#)
Команда устанавливает луч в указанные координаты.
Аргументы:
ray - хендл луча
x,y,z - координаты для него.

Итак, я устанавливаю луч в позицию камеры:
	pxRaySetPosition(ray, EntityX(cam,1), EntityY(cam,1),EntityZ(cam,1))
Теперь надо повернуть луч так же как камера. А вот с этим сложнее. Ведь мы располагаем только командой:
pxRaySetDir(ray%, nx#, ny#, nz#)
Устанавливает направлекние лучу.
Аргументы:
ray - луч
nx,ny,nz - нормализованный вектор направления (т.е. длина вектора = 1)

Итак, как же получить нужный нам вектор, имея только поворот камеры?
Нам поможет блитзовский TFormVector:

TFormVector 0,0,1,cam, 0
Многие про эту функцию не знают вовсе, поэтому постараюсь объяснить тоже чтоб было понятно.
Она трансформирует вектор из одной матрицы в другую, т.е. например как в данном случае у камеры был локальный вектор 0,0,1, но камера повёрнута, и нам нужно узнать глобальное направление того вектора. Тогда помогает эта функция. четвёртый и пятый её аргументы - это исходный ентити и конечный ентити, чтобы указывать, что относительно чего трансформировать. Если выставить 0 - то будет считаться за мировую систему координат (т.е. глобальные значения).
Короче благодаря ей мы нашли направление куда смотрит камера. Значения снимаются при помощи TFormedX()#,TFormedY()#,TFormedZ()#. Для порядку а также чтоб легче было дебажить запишем их в паременные:

DirX# = TFormedX()
DirY# = TFormedY()
DirZ# = TFormedZ()
Теперь вернёмся опять к лучу. Теперь, трансформировав вектор камеры т получив оттуда значения, мы можем указать ему и направление:

pxRaySetDir(ray,DirX,DirY,DirZ)
Вот, луч повёрнут куда надо, но прежде чем выполнять дальнейшие действия, проверим, тыкает ли луч вообще во что-то. Для этого посмотрим, что из себя представляет пикнутое тело:

pxRayGetBody(ray%, mode%)
Возвращает тыкнутый объект. Если ничего не тыкнулось, возвращает 0.
Аргументы:
ray - луч
mode - режим:
0 - тыкать все объекты
1 - тыкать только динамические объекты
2 - тыкать только статику

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

Body = pxRayGetBody(ray,1)
if Body Then
Нам нужно получить координаты, куда луч ткнул. Вот это нам пригодится:

pxRayGetPickX [Y,Z] (ray%, mode%)
Возвращает координату X [Y,Z] того места, куда ткнул ray.
Аргументы:
ray - луч
mode - режим:
0 - тыкать все объекты
1 - тыкать только динамические объекты
2 - тыкать только статику

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

Получим значения в переменные:
PosX# = pxRayGetPickX(ray, 1)
PosY# = pxRayGetPickY(ray, 1)
PosZ# = pxRayGetPickZ(ray, 1)
Итак, теперь у нас теперь есть все необходимые параметры, чтобы применить импульс! Делаем это:

pxBodyAddForceAtPos body, DirX*10,DirY*10,DirZ*10, PosX, PosY,PosZ,2
Обратите внимание: я умножил передаваемый вектор на 10 - т.к. он выходит нормализованным и очень маленьким, так что его надо непременно усилять.

Дадим возможность игроку стрелять по левой кнопке мыши:

If MouseHit(1) Then Shoot()
Готово! Запускаем, кидаем кубики и расстреливаем их

Чего-то не хватает. Ну что ж, последний штрих: прицел.

Color 200,0,0
Line (GraphicsWidth() Shr 1) - 15, (GraphicsHeight() Shr 1), (GraphicsWidth() Shr 1) + 15, (GraphicsHeight() Shr 1)
Line (GraphicsWidth() Shr 1), (GraphicsHeight() Shr 1) - 15, (GraphicsWidth() Shr 1), (GraphicsHeight() Shr 1) +15
Oval (GraphicsWidth() Shr 1) - 10, (GraphicsHeight() Shr 1)-10, 20,20,0


Извините что картинок маловато, но тут уже скринами ничего не покажешь: нужно видеть в динамике.

Ну что ж, рассказ о силах и импульсах закончен! У лучей есть ещё некоторые фичи, о них я буду рассказывать далее по ходу.
Полный код примера вы найдёте в аттаче "PhysXExample12.zip"
У меня всё, надеюсь, материал оказался вам полезен. У меня на сегодня всё

З.Ы. Полез опечатки исправлять - при сохранении пишет что пост слишком короткий, увеличьте до 4 символов. Пришлось разрезать на 2 поста, тогда глюк прошёл. СабЗиро, где ты?..
Вложения
Тип файла: zip PhysXExample12.zip (1.1 Кб, 1838 просмотров)
__________________
Мои проекты:
Анальное Рабство
Зелёный Слоник
Дмитрий Маслов*
Различие**
Клюква**

* — в стадии разработки
** — в стадии проектирования
Для проектов в стадии проектирования приведены кодовые имена

(Offline)
 
Ответить с цитированием
Эти 28 пользователя(ей) сказали Спасибо ABTOMAT за это полезное сообщение:
3dr1aN (01.02.2009), baton4ik (02.02.2010), Blender (17.01.2010), Brain (15.01.2010), Buraki (02.02.2009), CRASHER (10.02.2009), den (27.07.2010), Diablomania (14.08.2009), h1dd3n (01.02.2009), H@NON (01.02.2009), HolyDel (01.02.2009), Hurrit (16.05.2010), Iv-FeliS (03.04.2009), Main Cry (23.04.2009), m_512 (13.02.2009), Nex (23.06.2009), PackegerX (03.02.2010), Randomize (10.02.2009), Slavik (24.06.2009), St.AnGer (09.06.2009), strayhnd (30.06.2010), Tadeus (01.02.2009), tirarex (01.03.2012), tormoz (01.02.2009), TxN (15.08.2009), viper86 (08.02.2009), WhiteBlack (27.07.2010), ІГРОГРАЙКО (02.07.2009)