[bb] Simple 3D sphere-to-sphere physics by Ken Lynch [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:39

Previous topic - Next topic

BlitzBot

Title : Simple 3D sphere-to-sphere physics
Author : Ken Lynch
Posted : 1+ years ago

Description : This is an example of how to do simple physics using sphere-to-sphere type collisions. It uses LinePick instead of the standard collision method as it offers more control and encapsulates everything you need in simple functions that you can use in your own code with little or no modification.

Hope you find it useful.


Code :
Code (blitzbasic) Select
;
; Simple 3D collision with physics
;

;
; Data types
;

Type PhysicsEntity
Field entity%
Field radius#, mass#, bounce#, friction#
Field x#, y#, z#
Field xv#, yv#, zv#
End Type

;
; The usual stuff
;

Graphics3D 800, 600

light = CreateLight()

camera = CreateCamera()
PositionEntity camera, 0, 0, -25

;
; Create our entities
;
For i = -8 To 8 Step 2
For j = -8 To 8 Step 2
ent = CreateSphere()
ScaleEntity ent, 0.5, 0.5, 0.5
PositionEntity ent, i, j, 0
SetEntityPhysics ent, 0.5, 1, 0.90, 0.0005
ApplyForce ent, Rnd(-0.2, 0.2), Rnd(-0.2, 0.2), 0
Next
Next

;
; Main loop
;
Repeat
UpdatePhysics
RenderWorld
Flip
Until KeyHit(1)

;
; Physics handling functions
;

;
; FindPhysicsEntity(entity)
;
; Quickly find PhysicsEntity data type from entity using the Handle stored in EntityName
;
Function FindPhysicsEntity.PhysicsEntity(entity)
name = EntityName(entity)
Return Object.PhysicsEntity(name)
End Function

;
; SetEntityPhysics entity,radius#,mass#
;
; Sets an entity's phisics properties
;
Function SetEntityPhysics(entity, radius#=1, mass#=1, bounce#=1, friction#=0)
pe.PhysicsEntity = New PhysicsEntity
peentity = entity
peadius = radius
pemass = mass
peounce = bounce
pefriction = friction
EntityRadius entity, radius
EntityPickMode entity, 1
;
; Magic to store the Handle of pe in the entity's name
;
NameEntity entity, Handle(pe)
End Function

;
; RemoveEntityPhysics entity
;
; Removes an entity's physics properties
;
Function RemoveEntityPhysics(entity)
pe.PhysicsEntity = FindPhysicsEntity(entity)
If pe <> Null Then
NameEntity entity, ""
Delete pe
Else
RuntimeError "Entity has no physics"
End If
End Function

;
; ApplyForce entity,x#,y#,z#
;
; Applies an impulse force to physics entity
;
Function ApplyForce(entity, x#, y#, z#)
pe.PhysicsEntity = FindPhysicsEntity(entity)
If pe <> Null Then
pexv = pexv + x
peyv = peyv + y
pezv = pezv + z
Else
RuntimeError "Entity has no physics"
End If
End Function

;
; UpdatePhysics
;
; This will update all entities with physics
;

Function UpdatePhysics()
For e1.PhysicsEntity = Each PhysicsEntity
;
; Check if the entity is moving
;
If e1xv <> 0 Or e1yv <> 0 Or e1zv <> 0 Then

;
; Record current entity position
;
x# = EntityX(e1entity, True)
y# = EntityY(e1entity, True)
z# = EntityZ(e1entity, True)

;
; Reduce velocity due to friction
;
If e1friction > 0 Then
speed# = Sqr(e1xv ^ 2 + e1yv ^ 2 + e1zv ^ 2)
new_speed# = speed - e1friction
If new_speed <= 0 Then
e1xv = 0
e1yv = 0
e1zv = 0
Else
e1xv = e1xv / speed * new_speed
e1yv = e1yv / speed * new_speed
e1zv = e1zv / speed * new_speed
End If
End If

;
; Do a line pick to check for collisions
;
ent = LinePick(x, y, z, e1xv, e1yv, e1zv, e1adius)
If ent > 0 Then e2.PhysicsEntity = FindPhysicsEntity(ent)
If ent = 0 Or e2 = Null
;
; Add velocity vector to current position
;
x = x + e1xv
y = y + e1yv
z = z + e1zv
Else
;
; Get the point of collision
;
Px# = PickedX()
Py# = PickedY()
Pz# = PickedZ()

;
; Get the collision normal vector
;
Nx# = PickedNX()
Ny# = PickedNY()
Nz# = PickedNZ()

;
; Back up a little to prevent collision errors
;
TFormNormal e1xv, e1yv, e1zv, 0, 0
dx# = TFormedX() * 0.05
dy# = TFormedY() * 0.05
dz# = TFormedZ() * 0.05

;
; Calculate the new position
;
x = Px + (e1adius) * Nx - dx
y = Py + (e1adius) * Ny - dy
z = Pz + (e1adius) * Nz - dz

;
; Conservation of momentum
;
a1# = e1xv * Nx + e1yv * Ny + e1zv * Nz
a2# = e2xv * Nx + e2yv * Ny + e2zv * Nz
OptP# = 2 * (a1 - a2) / (e1mass + e2mass)

e1xv = (e1xv - (OptP * e2mass * Nx)) * e1ounce
e1yv = (e1yv - (OptP * e2mass * Ny)) * e1ounce
e1zv = (e1zv - (OptP * e2mass * Nz)) * e1ounce

e2xv = (e2xv + (OptP * e1mass * Nx)) * e2ounce
e2yv = (e2yv + (OptP * e1mass * Ny)) * e2ounce
e2zv = (e2zv + (OptP * e1mass * Nz)) * e2ounce
End If
;
; Reposition entity
;
PositionEntity e1entity, x, y, z, True
End If
Next
End Function


Comments : none...