Показать сообщение отдельно
Старый 18.02.2009, 17:37   #12
viper86
Нуждающийся
 
Аватар для viper86
 
Регистрация: 19.11.2008
Адрес: Украина, Луганск
Сообщений: 72
Написано 34 полезных сообщений
(для 123 пользователей)
Сообщение Ответ: Учебник по PhysX Wrapper для Blitz3D

Магниты

Итак, продолжим нашу экскурсию в удивительный мир PhysX Сегодня тема пойдёт о магнитах. Штука эта намного полезнее, чем пожет показаться на первый взгляд. Почти в любой игре, в которой используется физика используются и магниты. Любые эффекты, типа телекинеза, гравипушки, чёрной дыры и даже взрывов - это всё дело рук магнитов Так что постараемся подробнее разобраться в принципах их действия.

Функций для работы с магнитами не много, но все полезные и часто используемые. Для начала научимся создавать магнит:

pxCreateMagnet(minforce#, middleforce#, maxforce#)

где:
minforce# - минимальное усилие
middleforce# - среднее усилие
maxforce# - максимальное усилие
Эта функция создаёт магнит с тремя значениями силы. Сила считается по формуле : Force = minforce + middleforce/distance + maxforce/(distance*distance). Установка одного из значений в ноль убирает соответствующее слагаемое. Сила считается между центром магнита и центром тела. Может быть направлена как к магниту(притягивает), так и от него(отталкивает), в зависимости от знака силы. Действует на все тела в сцене.

pxMagnetActivate(mdata%, mmode%, fmode%)

где:
mdata% - магнит
mmode% - тип магнита
fmode% - тип силы

mmode - тип магнита. 
1 - магнит не имеющий области остановки 
2 - с областью остановки
3 - тела притягиваются не по силе, а по скоросте (формула для скорости аналогична формуле по силе) 
fmode - тип силы (как в pxBodyAddForce и подобных)
Данная функция активирует магнит. Её необходимо запускать в каждом цикле программы, если нужен постоянный магнит (более подробно мы рассмотрим дальше).

И собсно функция для позиционирования магнита:

pxMagnetSetPosition(mdata%, pos_x#, pos_y#, pos_z#)

где:
mdata% - магнит
pos_x#, pos_y#, pos_z# - координаты
Тут я думаю все понятно. Итак, попробуем создать обычный магнит. Делаем свет, камеру, физический мир, функции для создания, обновления кубика и тд. :

Graphics3D 800,600,32,2
SetBuffer BackBuffer()

SeedRnd MilliSecs()

SetFont LoadFont(Arial,12)

; Инициализация физики
pxCreateWorld(1,"")
pxSetGravity(0,-10,0)

; Камера
cam=CreateCamera()
PositionEntity cam,15,10,-25
RotateEntity cam,20,35,0

; Свет
light=CreateLight()
PositionEntity light,10,10,-10

; Плоскость
plane=CreatePlane()
EntityAlpha plane,0.8
EntityColor plane,150,255,255
CreateMirror()


While Not KeyDown(1)
	
	pxRenderPhysic(60,0)
	UpdatepxCubes()
	RenderWorld
	
	Flip
Wend
End

Type pxCube
	Field mesh
	Field body	
End Type

Function CreatepxCube(x#,y#,z#)
	pxC.pxCube = New pxCube
	pxC\mesh = CreateCube()
	pxC\body = pxBodyCreateCube(1,1,1,1)	
	pxBodySetPosition pxC\body,x,y,z	
End Function

Function UpdatepxCubes()
	For pxC.pxCube = Each pxCube
		pxBodySetEntity pxC\mesh, pxC\body
	Next
End Function

Function DeletepxCubes()
	For pxC.pxCube = Each pxCube
	FreeEntity pxC\mesh 
	pxDeleteBody pxC\body 
	Delete pxC		
	Next
End Function
Теперь давайте накидаем несколько кубиков и создадим управляемый магнит. Первое - накидываем кучку кубиков (перед циклом):

For i=0 To 15
	CreatepxCube(Rnd(-10,10),15,Rnd(-10,10))
Next
А теперь создаём магнит (тоже до цикла):

mag1=pxCreateMagnet(1,5,10)   	     ; создаём магнит
pxMagnetSetMaxRadius(mag1, 15)    ; устанавливаем макс радиус действия
pxMagnetSetPosition(mag1,-10,0,0)  ; устанавливаем позицию
И в цикле активируем магнит:

pxMagnetActivate(mag1,0,0)
Запускаем и любуемся :



Теперь сделаем, чтобы магнит можно было двигать стрелочками на клаве и чтоб он активировался только когда держим пробел. Это пишем до цикла (создаём синий шар, чтоб мы могли видеть перемещение магнита):

sp =CreateSphere ()
ScaleEntity sp,0.5,0.5,0.5
EntityColor sp,0,0,255

x#=-10
z#=0
А это уже в цикле (управление магнитом)

If KeyDown (205) x# = x#+0.2
If KeyDown (203) x# = x#-0.2
If KeyDown (200) z# = z#+0.2
If KeyDown (20 z# = z#-0.2
If KeyDown(57) pxMagnetActivate(mag1,0,0)
pxMagnetSetPosition(mag1, x, y, z)
PositionEntity sp, x,y,z
[/code]

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

x#=-10
z#=0
p%=1

While Not KeyDown(1)	
	
	If KeyDown (205) x# = x#+0.2
	If KeyDown (203) x# = x#-0.2
	If KeyDown (200) z# = z#+0.2
	If KeyDown (208) z# = z#-0.2
		
	If KeyDown(57) pxMagnetActivate(mag1,0,0)
	
	If KeyHit(28) p=-p
	
	pxMagnetSetMinForce(mag1, 1*p)
	pxMagnetSetMidForce(mag1, 5*p)
	pxMagnetSetMaxForce(mag1, 10*p)
	pxMagnetSetPosition(mag1, x, y, z)
	
	PositionEntity sp, x,y,z
	If p=1
		EntityColor sp,0,0,255
		Else
		EntityColor sp,255,0,0
	EndIf
	                    
	
	pxRenderPhysic(60,0)
	UpdatepxCubes()
	RenderWorld
	
	Flip
Wend
Теперь давайте сделаем взрыв. Создадим новый магнит (ниже первого):

explode=pxCreateMagnet(0,-20,-50)   
pxMagnetSetMaxRadius(mag1, 15)
и сферу для его обозначения:

explode_sp=CreateSphere()
EntityColor explode_sp,250,200,100
В цикле пропишем активацию взрыва по кнопке "e" и анимацию сферы:

If KeyHit(18) And boom=0 
	pxMagnetActivate(explode,0,1)
	boom=1
EndIf
		
If boom=1
	rad=rad+2
	ScaleEntity explode_sp,rad,rad,rad
	If rad>200 boom=0
Else
	rad=Abs(Sin(MilliSecs()*0.2))+0.5
	ScaleEntity explode_sp,rad,rad,rad    
EndIf
Естественно, переменные boom и rad лучше обьявить в начале программы (boom%=0 rad#=0). Добавим рестарт появления кубиков по кнопке Tab:

If KeyHit(15) 
	DeletepxCubes() 
	For i=0 To 15
		CreatepxCube(Rnd(-10,10),15,Rnd(-10,10))
	Next
EndIf
И теперь мы сможем управлять и взрывом, и магнитом плюс это наглядно видно:



Ниже приведу список функций, которые интуитивно понятны и не требуют разьяснения:

pxMagnetSetMinRadius(mdata%,minradius#)
pxMagnetSetMaxForce(mdata%,maxforce#)
pxMagnetSetMidForce(mdata%,middleforce#)
pxMagnetSetMinForce(mdata%,minforce#)
Функции для получения (возврата) значений:

pxMagnetGetPositionX(x#)
pxMagnetGetPositionY(y#)
pxMagnetGetPositionZ(z#)
pxMagnetGetMaxRadius(maxradius#)
pxMagnetGetMinRadius(minradius#)
pxMagnetGetMaxForce(maxforce#)
pxMagnetGetMidForce(middleforce#)
pxMagnetGetMinForce(minforce#)
И собсно функция удаления магнита:

pxMagnetDelete(mdata%)
Внимание! Функция удаления физического мира pxDestroyWorld() не удаляет магниты.


И последнее, что я хотел рассказать. Те, кто уже в уме представляет себе, как он будет делать в своей игре взрывы и телекинез , спросит у меня - а как же быть, если в игре не нужно притягивать/отталкивать все предметы, а наоборот - лишь единичные? А с помощью pxBodySetFlagMagniteble(body%, stat%) и масок, отвечу я вам. Остановимся поподробнее. Итак, функция pxBodySetFlagMagniteble() позволяет нам ставить любому телу флаг (stat), т.е. если stat=0 - магниты не влияют на тело и stat=1 - соответственно влияют. Но такой способ не всегда удобен. Потому существуют так называемые маски:
pxMagnetSetMask(mdata%,mask%)
pxBodySetMagnetMask(body%,mask%)
Как работают маски? Мы задаём маску любому телу и любому магниту. Если маски тела и магнита равны - магнит действует на тела с этой маской. Если маска тела и мегнита не равны - магнит действует на тела с меньшей маской.
Изменим немного функцию создания кубиков, добавим случайное разделение на металл(белый с маской 2) и неметалл(красный с маской 1):

Function CreatepxCube(x#,y#,z#)
	pxC.pxCube = New pxCube
	pxC\mesh = CreateCube()
	pxC\body = pxBodyCreateCube(1,1,1,1)	
	pxBodySetPosition pxC\body,x,y,z
	
	Metall=Rand(0,1)
	If Metall
		EntityColor pxC\mesh,230,232,215
		pxBodySetMagnetMask(pxC\body, 2) ;bin(10)
	Else
		EntityColor pxC\mesh,128,64,64
		pxBodySetMagnetMask(pxC\body, 1) ;bin(01)
	EndIf
		
End Function
Теперь поставим маски нашим магнитам:

pxMagnetSetMask(mag1,2)
pxMagnetSetMask(explode,3)
И наблюдаем. Получаеться у нас магнитом притягиваются только белые кубики (т.к. маски одинако=2), а взрыв берёт всех (т.к. маска взрыва 3 не равна не 2, ни 1 и больше их).

Полный код как обычно в аттаче
Вложения
Тип файла: zip magnets.zip (1.3 Кб, 1616 просмотров)
__________________
Лечим заражение... одна пуля - один больной.
(Offline)
 
Ответить с цитированием
Эти 25 пользователя(ей) сказали Спасибо viper86 за это полезное сообщение:
3dr1aN (19.02.2009), ABTOMAT (18.02.2009), baton4ik (02.02.2010), Blender (17.01.2010), Brain (15.01.2010), den (27.07.2010), Diablomania (14.08.2009), Ичигорь (01.03.2009), h1dd3n (18.02.2009), Harter (08.10.2009), HolyDel (18.02.2009), Hurrit (12.06.2009), Мик Данди (21.11.2009), indri (05.06.2009), ISKATEL (27.05.2009), Main Cry (23.04.2009), Nex (23.06.2009), PackegerX (03.02.2010), Randomize (27.02.2009), Slavik (24.06.2009), strayhnd (30.06.2010), Tadeus (18.02.2009), tormoz (18.02.2009), WhiteBlack (27.07.2010), ІГРОГРАЙКО (02.07.2009)