ProЗрениЕ
Физика в Blitz3D
------ ФИЗИКА на Блитц3Д ---------
----- ЧАСТЬ 1 Введение ------------

И так, как мы представляем себе физику ? это набор правил и законов, по которым действует наш физический мир. Поэтому будем использовать кое-где реальные физические законы из нашего мира smile .

Наша физика будет основана на частицах и связях между ними. Частица это просто сфера(шар), которая взаимодействует с полигональными объектами (так как в блитце нам не предоставили инструмент по обработке столконвений между полигональными моделями, то мы будем использовать конструкцию "шар-полигон"). Связи будут удерживать наши частицы связанными между собой, чтобы при движении они не смогли "убежать" от своих собратьев)) . То есть мы просто ограничиваем дистанцию между шарами.

-------- Часть 2 Первые шаги -------------
И так, приступим. Создадим тип для наших частиц :
Type Phys
End Type

Теперь нужно добавить параметры частице. Какие же свойства должна иметь частица ? Во-первых указатель на объект-частицу, чтобы нам знать что перемещать. Дальше позицию, скорость и ускорение. Позицию можно не записывать, так как мы всегда сможем достать ее из объекта-частицы через наш указатель smile , но нам понадобится знать предыдущую позицию, поэтому всеже запишем . Также понадобятся еще два важных свойства - это размер и масса. Вот он наш тип для частиц:

Code
Type Phys
  Field entity ; указатель
  Field x#, y#, z# ; позиция
  Field vx#, vy#, vz# ; вектор скорости
  Field ax#, ay#, az# ; вектор ускорения
  Field size# ; размер
  Field mass# ; масса
End Type

Чтож, раз тип у нас есть пора написать первую функцию - функцию создания частицы:

Code
Function AddPhys(x#=0, y#=0, z#=0, size#=1.0, mass#=1.0)
  Local p.Phys = New Phys
   
  p\x=x : p\y=y : p\z=z
  p\size = size
  p\mass = mass
   
  p\entity = CreateSphere(16)
  ScaleEntity p\entity, p\size, p\size, p\size
  PositionEntity p\entity, x, y, z
  EntityType p\entity, PhysCol
  EntityRadius p\entity, p\size
  NameEntity p\entity, Handle(p)

  Return p\entity
End Function

В ней мы создаем частицу, записываем параметры, устанавливаем коллизионный тип, записываем указатель на тип в имя частицы и возвращает указатель на частицу, чтобы потом можно было к ней обратиться.

Теперь напишем функцию обновления физики. Для начала заметим, что обновление физики мы разделим на 2 части: присвоение импульсов (сил) и обсчет реакции. И так, рассмотрим функцию добавления сил. Какие силы мы будем присваивать? во первых импульс ускорения, а во-вторых гравитацию, у нас же все таки приземленные взгляды на физику) так что притяним частицы к земле. Помимо константы с типом коллизии добавим туда константу гравитации :

Const PhysCol=1, LevelCol=2
Const Gravity# = -0.04

Теперь можно браться за саму функцию :

Code
Function PhysAddedForce()
  Local p.Phys
  For p.Phys = Each Phys
  ;-- добавляем гравитацию
  p\vy = p\vy + Gravity
  ;-- добавляем ускорения
  p\vx = p\vx + p\ax
  p\vy = p\vy + p\ay
  p\vz = p\vz + p\az
  ;-- записываем текущую позицию
  p\x = EntityX(p\entity,1)
  p\y = EntityY(p\entity,1)
  p\z = EntityZ(p\entity,1)
  ;-- изменяем позицию
  TranslateEntity p\entity, p\vx, p\vy, p\vz
  ;-- обнуление вектора ускорения
  p\ax = 0
  p\ay = 0
  p\az = 0
  Next
End Function

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

Code
Const f_air# = 0.98, f_ground# = 0.8

Function PhysUpdate()
  Local Nx#, Ny#, Nz#, VdotN#
  Local NFx#, NFy#, NFz#
  Local count, i
  Local p.Phys
   
  For p.Phys = Each Phys
  ; проверка столкновения
  count = CountCollisions(p\entity)
  If count > 0 Then
  For i = 1 To count
  ; получение нормали от поверхности, с которой столкнулись.
  Nx# = CollisionNX(p\entity, i)
  Ny# = CollisionNY(p\entity, i)
  Nz# = CollisionNZ(p\entity, i)
   
  ; перемножение вектора скорости с нормалью поверхности
  VdotN = p\vx*Nx + p\vy*Ny + p\vz*Nz
   
  ; просчет нормали силы
  ; цифра (-2) значит, что мы отзеркаливаем силу
  NFx = -2 * Nx * VdotN
  NFy = -2 * Ny * VdotN
  NFz = -2 * Nz * VdotN
   
  ; добавляем силу в вектор движения
  p\vx = p\vx + NFx
  p\vy = p\vy + NFy
  p\vz = p\vz + NFz
  Next
  ; добавляем трение с землей, чтобы тормозить частицы
  p\vx = p\vx * f_ground
  p\vy = p\vy * f_ground
  p\vz = p\vz * f_ground
  EndIf
  ; трение с воздухом
  p\vx = p\vx * f_air
  p\vy = p\vy * f_air
  p\vz = p\vz * f_air
  Next
End Function

В ней мы стали считать отскок шарика от поверхности. Сначало получили нормаль поверхности, ведь нам надо знать ее ориентацию в мире, чтобы отзеркалить движение частицы smile Более подробно расчет отскока рассмотрен на рисунке ниже :

Вот и готов первый этап нашей физики, чтобы посмотреть конечный результат смотрите пример TutorPhys1.bb .

-------- Часть 3 Манипулирование и связи -------------
Раз уж у нас есть физические объекты, то нужно ими как-то манипулировать, например придавать импульс движения. Вот как будет выглядеть функция добавления импульса :

Code
Function AddForce(phys, ax#, ay#, az#)
  Local p.Phys = Object.Phys(EntityName(phys))
  If p = Null Then Return False
  p\ax = p\ax + ax
  p\ay = p\ay + ay
  p\az = p\az + az
  Return True
End Function

Все что она делает, так это добавляет силу в вектор ускорения частицы, который затем будет обсчитываться. Пример с использованием этой функции называется TutorPhys2.bb .

Чтож, теперь приступим к связыванию наших частиц между собой. Создадим тип для свя-зей.

Code
Type Link
  Field p1.Phys ; первая частица
  Field p2.Phys ; вторая частица
  Field dist# ; требуемое расстояние между частицами
End Type

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

Code
Function AddLink(p1, p2, dist#=-1)
  Local l.Link = New Link
  l\p1 = Object.Phys(EntityName(p1))
  l\p2 = Object.Phys(EntityName(p2))
  ;-- если параметр меньше 0,
  ;-- то рассчитать автоматически,
  ;-- иначе присвоить значение.
  If dist < 0 Then
  l\dist = EntityDistance(p1, p2)
  Else
  l\dist = dist
  EndIf
   
  Return Handle(l)
End Function

Тут все просто, мы заносим в тип две частицы и записываем расстояние между ними.

Теперь нам нужно притягивать связанные частицы друг к другу на определенное расстояние:

Code
Function LinkUpdate()
  Local dx#, dy#, dz#
  Local diff#
  Local deltalength#
  Local l.Link
  For l.Link = Each Link
  ;-- разность позиций
  dx = EntityX(l\p1\entity,1)-EntityX(l\p2\entity,1)
  dy = EntityY(l\p1\entity,1)-EntityY(l\p2\entity,1)
  dz = EntityZ(l\p1\entity,1)-EntityZ(l\p2\entity,1)
  ;-- текущая дистанция
  deltalength# = EntityDistance(l\p1\entity, l\p2\entity)
;-- смещения частиц по направлению друг к другу, или наоборот, друг от друга
  ;-- в зависимости от текущей и требуемых дистанций. Также учитывается масса
  diff# = (deltalength - l\dist) / (deltalength * (l\p1\mass+l\p2\mass))
  ;-- раздвигаем частицы
  TranslateEntity l\p1\entity, -l\p2\mass*dx*diff, -l\p2\mass*dy*diff, -l\p2\mass*dz*diff
  TranslateEntity l\p2\entity, l\p1\mass*dx*diff, l\p1\mass*dy*diff, l\p1\mass*dz*diff
  ;-- записываем смещения в вектор движения
  l\p1\vx = l\p1\vx - l\p2\mass*dx*diff
  l\p1\vy = l\p1\vy - l\p2\mass*dy*diff
  l\p1\vz = l\p1\vz - l\p2\mass*dz*diff
   
  l\p2\vx = l\p2\vx + l\p1\mass*dx*diff
  l\p2\vy = l\p2\vy + l\p1\mass*dy*diff
  l\p2\vz = l\p2\vz + l\p1\mass*dz*diff
  Next
End Function

Выглядит сложно, но разобрать думаю не составит труда smile Эта функция распределяет между частицами силу притяжения/отталкивания друг к другу, также тут учитывается их масса, поэтому более тяжелая частица будет перемещаться на меньшее расстояние, чем ее связь – легкая частица. Пример можете посмотреть, запустив файл TutorPhys3.bb .

Внизу приведен полный код выполненных нами программ.

TutorPhys1.bb

Code
;====================================================================
; Project: Physic Sample
; Version: 0.0.1
; Author: H@non
; Email: hanon90@gmail.com
; Description: Tutorial
;  
;  
;====================================================================

Global GraphW = 800
Global GraphH = 600
Global GraphBits = 32
Global GraphMode = 2

Graphics3D GraphW, GraphH, GraphBits, GraphMode
SetBuffer BackBuffer()
SeedRnd MilliSecs()

;========== Global Variables ===========
;--- Main ---------
Global GraphWmid = GraphW Shr 1
Global GraphHmid = GraphH Shr 1
Global Quit=False, Vsync=False

Const PhysCol=1, LevelCol=2
Const Gravity# = -0.04

Type Phys
  Field entity ; указатель
  Field x#, y#, z# ; позиция
  Field vx#, vy#, vz# ; вектор скорости
  Field ax#, ay#, az# ; вектор ускорения
  Field size# ; размер
  Field mass# ; масса
  Field vel# ; скорость (скалярное значение)
End Type

;------ СОЗДАНИЕ МИРА ---------

;-- свет
Local lit = CreateLight()
RotateEntity lit, 45, 45, 0

;-- камера
Local camera = CreateCamera()
PositionEntity camera, 0, 5, -5
RotateEntity camera, 30, 0, 0

;-- земля
Local plane = CreatePlane()
Local texplane = CreateTexture( 128, 128 )
SetBuffer TextureBuffer(texplane)
For Y = 0 To 128
  For X = 0 To 128
  WritePixel X, Y, (Rand(96,160) * $010101) Or $FF000000
  Next
Next
SetBuffer BackBuffer()
ScaleTexture texplane, 5, 5
EntityTexture plane, texplane
EntityColor plane, 0, 255, 0
EntityType plane, LevelCol

;-- физическая частица
Local phys = AddPhys(0, 5, 0)

Collisions PhysCol, LevelCol, 2, 3
;=========== ГЛАВНЫЙ ЦИКЛ =======================
While KeyDown(1)=0
   
  PhysAddedForce()
  UpdateWorld()
  PhysUpdate()

  RenderWorld()
   
  Flip
Wend

End

;=========================================================
;================== ФУНКЦИИ ==============================

Function AddPhys(x#=0, y#=0, z#=0, size#=1.0, mass#=1.0)
  Local p.Phys = New Phys
   
  p\x=x : p\y=y : p\z=z
  p\size = size
  p\mass = mass
   
  p\entity = CreateSphere(16)
  ScaleEntity p\entity, p\size, p\size, p\size
  PositionEntity p\entity, x, y, z
  EntityType p\entity, PhysCol
  EntityRadius p\entity, p\size
  NameEntity p\entity, Handle(p)
   
  Return p\entity
End Function

Function PhysAddedForce()
  Local p.Phys
  For p.Phys = Each Phys
  ;-- добавляем гравитацию
  p\vy = p\vy + Gravity
  ;-- добавляем ускорения
  p\vx = p\vx + p\ax
  p\vy = p\vy + p\ay
  p\vz = p\vz + p\az
  ;-- записываем текущую позицию
  p\x = EntityX(p\entity,1)
  p\y = EntityY(p\entity,1)
  p\z = EntityZ(p\entity,1)
  ;-- изменяем позицию
  TranslateEntity p\entity, p\vx, p\vy, p\vz
  ;-- обнуление вектора ускорения
  p\ax = 0
  p\ay = 0
  p\az = 0
  Next
End Function

Function PhysUpdate()
  Local vx2#, vy2#, vz2#
  Local Nx#, Ny#, Nz#, VdotN#
  Local NFx#, NFy#, NFz#
  Local count, i
  Local p.Phys
   
  For p.Phys = Each Phys
  ; обсчет скорости после коллизии
  vx2 = EntityX(p\entity,1) - p\x
  vy2 = EntityY(p\entity,1) - p\y
  vz2 = EntityZ(p\entity,1) - p\z
   
  p\x = EntityX(p\entity,1)
  p\y = EntityY(p\entity,1)
  p\z = EntityZ(p\entity,1)
   
  p\vel = 0.0
  ; проверка столкновения
  count = CountCollisions(p\entity)
  If count > 0 Then
  ; считаем линейную скорость
  p\vel = Sqr(vx2*vx2 + vy2*vy2 + vz2*vz2)
   
  For i = 1 To count
  ; получение нормали от поверхности, с которой столкнулись.
  Nx# = CollisionNX(p\entity, i)
  Ny# = CollisionNY(p\entity, i)
  Nz# = CollisionNZ(p\entity, i)
   
  ; перемножение вектора скорости с нормалью поверхности
  VdotN = p\vx*Nx + p\vy*Ny + p\vz*Nz
   
  ; просчет нормали силы
  ; цифра (-2) значит, что мы отзеркаливаем силу
  NFx = -2 * Nx * VdotN
  NFy = -2 * Ny * VdotN
  NFz = -2 * Nz * VdotN
   
  ; добавляем силу в вектор движения
  p\vx = p\vx + NFx
  p\vy = p\vy + NFy
  p\vz = p\vz + NFz
  Next
  ; добавляем трения, чтобы тормозить частицы
  p\vx = p\vx * 0.8
  p\vy = p\vy * 0.8
  p\vz = p\vz * 0.8
  EndIf
  Next
End Function

TutorPhys2.bb

Code
;====================================================================
; Project: Physic Sample
; Version: 0.0.2
; Author: H@non
; Email: hanon90@gmail.com
; Description: Tutorial
;  
;  
;====================================================================

Global GraphW = 800
Global GraphH = 600
Global GraphBits = 32
Global GraphMode = 2

Graphics3D GraphW, GraphH, GraphBits, GraphMode
SetBuffer BackBuffer()
SeedRnd MilliSecs()

;========== Global Variables ===========
;--- Main ---------
Global GraphWmid = GraphW Shr 1
Global GraphHmid = GraphH Shr 1
Global Quit=False, Vsync=False

Const PhysCol=1, LevelCol=2
Const Gravity# = -0.04
Const f_air# = 0.98, f_ground# = 0.8

Type Phys
  Field entity ; указатель
  Field x#, y#, z# ; позиция
  Field vx#, vy#, vz# ; вектор скорости
  Field ax#, ay#, az# ; вектор ускорения
  Field size# ; размер
  Field mass# ; масса
End Type

;------ СОЗДАНИЕ МИРА ---------
Local font = LoadFont("arial cyr", 20)
SetFont font

;-- свет
Local lit = CreateLight()
RotateEntity lit, 45, 45, 0

;-- камера
Local camera = CreateCamera()
PositionEntity camera, 0, 5, -15
RotateEntity camera, 30, 0, 0

;-- земля
Local plane = CreatePlane()
Local texplane = CreateTexture( 128, 128 )
SetBuffer TextureBuffer(texplane)
For Y = 0 To 128
  For X = 0 To 128
  WritePixel X, Y, (Rand(96,160) * $010101) Or $FF000000
  Next
Next
SetBuffer BackBuffer()
ScaleTexture texplane, 5, 5
EntityTexture plane, texplane
EntityColor plane, 0, 255, 0
EntityType plane, LevelCol

;-- физическая частица
Local phys = AddPhys(0, 5, 0)

Collisions PhysCol, LevelCol, 2, 3
;=========== ГЛАВНЫЙ ЦИКЛ =======================
While KeyDown(1)=0
  AddForce(phys, 0, (KeyDown(200)-KeyDown(208))*0.1, 0)
   
  PhysAddedForce()
  UpdateWorld()
  PhysUpdate()
   
  PointEntity camera, phys

  RenderWorld()
   
  Text 10, 10, "управление : стрелки вверх / вниз"
   
  Flip
Wend

End

;=========================================================
;================== ФУНКЦИИ ==============================

Function AddPhys(x#=0, y#=0, z#=0, size#=1.0, mass#=1.0)
  Local p.Phys = New Phys
   
  p\x=x : p\y=y : p\z=z
  p\size = size
  p\mass = mass
   
  p\entity = CreateSphere(16)
  ScaleEntity p\entity, p\size, p\size, p\size
  PositionEntity p\entity, x, y, z
  EntityType p\entity, PhysCol
  EntityRadius p\entity, p\size
  NameEntity p\entity, Handle(p)
   
  Return p\entity
End Function

Function AddForce(phys, ax#, ay#, az#)
  Local p.Phys = Object.Phys(EntityName(phys))
  If p = Null Then Return False
  p\ax = p\ax + ax
  p\ay = p\ay + ay
  p\az = p\az + az
  Return True
End Function

Function PhysAddedForce()
  Local p.Phys
  For p.Phys = Each Phys
  ;-- добавляем гравитацию
  p\vy = p\vy + Gravity
  ;-- добавляем ускорения
  p\vx = p\vx + p\ax
  p\vy = p\vy + p\ay
  p\vz = p\vz + p\az
  ;-- записываем текущую позицию
  p\x = EntityX(p\entity,1)
  p\y = EntityY(p\entity,1)
  p\z = EntityZ(p\entity,1)
  ;-- изменяем позицию
  TranslateEntity p\entity, p\vx, p\vy, p\vz
  ;-- обнуление вектора ускорения
  p\ax = 0
  p\ay = 0
  p\az = 0
  Next
End Function

Function PhysUpdate()
  Local Nx#, Ny#, Nz#, VdotN#
  Local NFx#, NFy#, NFz#
  Local count, i
  Local p.Phys
   
  For p.Phys = Each Phys
  ; проверка столкновения
  count = CountCollisions(p\entity)
  If count > 0 Then
  For i = 1 To count
  ; получение нормали от поверхности, с которой столкнулись.
  Nx# = CollisionNX(p\entity, i)
  Ny# = CollisionNY(p\entity, i)
  Nz# = CollisionNZ(p\entity, i)
   
  ; перемножение вектора скорости с нормалью поверхности
  VdotN = p\vx*Nx + p\vy*Ny + p\vz*Nz
   
  ; просчет нормали силы
  ; цифра (-2) значит, что мы отзеркаливаем силу
  NFx = -2 * Nx * VdotN
  NFy = -2 * Ny * VdotN
  NFz = -2 * Nz * VdotN
   
  ; добавляем силу в вектор движения
  p\vx = p\vx + NFx
  p\vy = p\vy + NFy
  p\vz = p\vz + NFz
  Next
  ; добавляем трение с землей, чтобы тормозить частицы
  p\vx = p\vx * f_ground
  p\vy = p\vy * f_ground
  p\vz = p\vz * f_ground
  EndIf
  ; трение с воздухом
  p\vx = p\vx * f_air
  p\vy = p\vy * f_air
  p\vz = p\vz * f_air
  Next
End Function

TutorPhys3.bb

Code
;====================================================================
; Project: Physic Sample
; Version: 0.0.3
; Author: H@non
; Email: hanon90@gmail.com
; Description: Tutorial
;  
;  
;====================================================================

Global GraphW = 800
Global GraphH = 600
Global GraphBits = 32
Global GraphMode = 2

Graphics3D GraphW, GraphH, GraphBits, GraphMode
SetBuffer BackBuffer()
SeedRnd MilliSecs()

;========== Global Variables ===========
;--- Main ---------
Global GraphWmid = GraphW Shr 1
Global GraphHmid = GraphH Shr 1
Global Quit=False, Vsync=False

Const PhysCol=1, LevelCol=2
Const Gravity# = -0.04
Const f_air# = 0.98, f_ground# = 0.8

Type Phys
  Field entity ; указатель
  Field x#, y#, z# ; позиция
  Field vx#, vy#, vz# ; вектор скорости
  Field ax#, ay#, az# ; вектор ускорения
  Field size# ; размер
  Field mass# ; масса
End Type

Type Link
  Field p1.Phys ; первая частица
  Field p2.Phys ; вторая частица
  Field dist# ; требуемое расстояние между частицами
End Type

;------ СОЗДАНИЕ МИРА ---------
Local font = LoadFont("arial cyr", 20)
SetFont font

;-- свет
Local lit = CreateLight()
RotateEntity lit, 45, 45, 0

;-- камера
Local camera = CreateCamera()
PositionEntity camera, 0, 5, -15
RotateEntity camera, 30, 0, 0

;-- земля
Local plane = CreatePlane()
Local texplane = CreateTexture( 128, 128 )
SetBuffer TextureBuffer(texplane)
For Y = 0 To 128
  For X = 0 To 128
  WritePixel X, Y, (Rand(96,160) * $010101) Or $FF000000
  Next
Next
SetBuffer BackBuffer()
ScaleTexture texplane, 5, 5
EntityTexture plane, texplane
EntityColor plane, 0, 255, 0
EntityType plane, LevelCol

;-- физическая частица
Local phys = AddPhys(0, 5, 0)
Local phys2 = AddPhys(3, 5, 0, 2, 4)

;-- соединяем частицы
AddLink(phys, phys2)

Collisions PhysCol, LevelCol, 2, 3
;=========== ГЛАВНЫЙ ЦИКЛ =======================
While KeyDown(1)=0
  AddForce(phys, (KeyDown(205)-KeyDown(203))*0.2, KeyDown(57)*0.2, (KeyDown(200)-KeyDown(208))*0.2)
   
  PhysAddedForce()
  UpdateWorld()
  PhysUpdate()
  LinkUpdate()
   
  PointEntity camera, phys

  RenderWorld()
   
  Text 10, 10, "управление : стрелки + пробел"
   
  Flip
Wend

End

;=========================================================
;================== ФУНКЦИИ ==============================

;--------- Функции создания ----------------

Function AddPhys(x#=0, y#=0, z#=0, size#=1.0, mass#=1.0)
  Local p.Phys = New Phys
   
  p\x=x : p\y=y : p\z=z
  p\size = size
  p\mass = mass
   
  p\entity = CreateSphere(16)
  ScaleEntity p\entity, p\size, p\size, p\size
  PositionEntity p\entity, x, y, z
  EntityType p\entity, PhysCol
  EntityRadius p\entity, p\size
  NameEntity p\entity, Handle(p)
   
  Return p\entity
End Function

Function AddLink(p1, p2, dist#=-1)
  Local l.Link = New Link
  l\p1 = Object.Phys(EntityName(p1))
  l\p2 = Object.Phys(EntityName(p2))
  ;-- если параметр меньше 0,
  ;-- то рассчитать автоматически,
  ;-- иначе присвоить значение.
  If dist < 0 Then
  l\dist = EntityDistance(p1, p2)
  Else
  l\dist = dist
  EndIf
   
  Return Handle(l)
End Function

;--------- Функции манипуляции ---------------

Function AddForce(phys, ax#, ay#, az#)
  Local p.Phys = Object.Phys(EntityName(phys))
  If p = Null Then Return False
  p\ax = p\ax + ax
  p\ay = p\ay + ay
  p\az = p\az + az
  Return True
End Function

;--------- Функции обновления состояния -----------

Function PhysAddedForce()
  Local p.Phys
  For p.Phys = Each Phys
  ;-- добавляем гравитацию
  p\vy = p\vy + Gravity
  ;-- добавляем ускорения
  p\vx = p\vx + p\ax
  p\vy = p\vy + p\ay
  p\vz = p\vz + p\az
  ;-- записываем текущую позицию
  p\x = EntityX(p\entity,1)
  p\y = EntityY(p\entity,1)
  p\z = EntityZ(p\entity,1)
  ;-- изменяем позицию
  TranslateEntity p\entity, p\vx, p\vy, p\vz
  ;-- обнуление вектора ускорения
  p\ax = 0
  p\ay = 0
  p\az = 0
  Next
End Function

Function PhysUpdate()
  Local Nx#, Ny#, Nz#, VdotN#
  Local NFx#, NFy#, NFz#
  Local count, i
  Local p.Phys
   
  For p.Phys = Each Phys
  ; проверка столкновения
  count = CountCollisions(p\entity)
  If count > 0 Then
  For i = 1 To count
  ; получение нормали от поверхности, с которой столкнулись.
  Nx# = CollisionNX(p\entity, i)
  Ny# = CollisionNY(p\entity, i)
  Nz# = CollisionNZ(p\entity, i)
   
  ; перемножение вектора скорости с нормалью поверхности
  VdotN = p\vx*Nx + p\vy*Ny + p\vz*Nz
   
  ; просчет нормали силы
  ; цифра (-2) значит, что мы отзеркаливаем силу
  NFx = -2 * Nx * VdotN
  NFy = -2 * Ny * VdotN
  NFz = -2 * Nz * VdotN
   
  ; добавляем силу в вектор движения
  p\vx = p\vx + NFx
  p\vy = p\vy + NFy
  p\vz = p\vz + NFz
  Next
  ; добавляем трение с землей, чтобы тормозить частицы
  p\vx = p\vx * f_ground
  p\vy = p\vy * f_ground
  p\vz = p\vz * f_ground
  EndIf
  ; трение с воздухом
  p\vx = p\vx * f_air
  p\vy = p\vy * f_air
  p\vz = p\vz * f_air
  Next
End Function

Function LinkUpdate()
  Local dx#, dy#, dz#
  Local diff#
  Local deltalength#
  Local l.Link
  For l.Link = Each Link
  ;-- разность позиций
  dx = EntityX(l\p1\entity,1)-EntityX(l\p2\entity,1)
  dy = EntityY(l\p1\entity,1)-EntityY(l\p2\entity,1)
  dz = EntityZ(l\p1\entity,1)-EntityZ(l\p2\entity,1)
  ;-- текущая дистанция
  deltalength# = EntityDistance(l\p1\entity, l\p2\entity)
  ;-- смещения частиц по направлению друг к другу, или наоборот, друг от друга
  ;-- в зависимости от текущей и требуемых дистанций. Также учитывается масса
  diff# = (deltalength - l\dist) / (deltalength * (l\p1\mass+l\p2\mass))
  ;-- раздвигаем частицы
  TranslateEntity l\p1\entity, -l\p2\mass*dx*diff, -l\p2\mass*dy*diff, -l\p2\mass*dz*diff
  TranslateEntity l\p2\entity, l\p1\mass*dx*diff, l\p1\mass*dy*diff, l\p1\mass*dz*diff
  ;-- записываем смещения в вектор движения
  l\p1\vx = l\p1\vx - l\p2\mass*dx*diff
  l\p1\vy = l\p1\vy - l\p2\mass*dy*diff
  l\p1\vz = l\p1\vz - l\p2\mass*dz*diff
   
  l\p2\vx = l\p2\vx + l\p1\mass*dx*diff
  l\p2\vy = l\p2\vy + l\p1\mass*dy*diff
  l\p2\vz = l\p2\vz + l\p1\mass*dz*diff
  Next
End Function
Категория: программирование | Добавил: H@NON (23.11.2009) | Автор: H@non
Просмотров: 817 | Теги: физика, Программирование, Blitz, б3д, Blitz3D | Рейтинг: 5.0/2
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

Copyright ProЗрение © 2024
All Right reserved







общее [1]
программирование [1]
дизайн [1]


  форма входа
Логин:
Пароль:
 



Рейтинг@Mail.ru



Rambler's Top100