Small problem with Ball physics code...

Blitz3D Forums/Blitz3D Programming/Small problem with Ball physics code...

D_Town_Tony(Posted 2005) [#1]
Can someone please help me with this Ball physics code, I adapted it from the Ball rolling physics example by Jeppe Nielsen. I made it directional control using the arrow keys.

The problem is that at first pressing up,down,left,right works fine but after bouncing around the board for awhile the directions start to act as if the ball is turned, but I can't find in the code what does this, can someone please take a look and help me find whats causing this. Thanks in advance. Press space to jump, do this a few times while moving around and the problem surfaces when you try to roll around.


Graphics3D 800,600,32
SetBuffer BackBuffer()
WBuffer False
HidePointer
SeedRnd MilliSecs()

;frametweening
Global gameFPS = 60
Global framePeriod = 1000 / gameFPS
Global frameTime = MilliSecs () - framePeriod
framePeriod = 1000 / gameFPS
frameTime = MilliSecs () - framePeriod

Const gravity#=-0.06


arena=CreatePlane()
EntityColor arena,Rnd(0,200),Rnd(0,200),Rnd(0,200)
PositionEntity arena,0,-5,0
EntityType arena,world_col

obj_1=CreateCube()
EntityType obj_1,world_col
PositionEntity obj_1,-10,-10,15
ScaleEntity obj_1,10,10,10
RotateEntity obj_1,45,90,0
EntityColor obj_1,Rnd(0,200),Rnd(0,200),Rnd(0,200)

obj_2=CreateSphere()
EntityType obj_2,world_col
PositionEntity obj_2,25,-1,-17
ScaleEntity obj_2,15,5,15
EntityColor obj_2,Rnd(0,200),Rnd(0,200),Rnd(0,200)

obj_3=CreateCube();walls
EntityType obj_3,world_col
PositionEntity obj_3,0,-10,0
ScaleEntity obj_3,70,70,70
EntityColor obj_3,Rnd(0,200),Rnd(0,200),Rnd(0,200)
FlipMesh obj_3

light=CreateLight(1)
RotateEntity light,30,20,0


camera=CreateCamera()
CameraClsColor camera,0,100,155
PositionEntity camera,0,600,-420
RotateEntity camera,55,0,0
CameraZoom Camera,10

ball.ball=ballnew(0,4,-40,2,.8,1)
ball.ball=ballnew(-10,4,-40,2,.8,2)
ball.ball=ballnew(10,100,-30,1.75,.8,3)

Const ball_col=1
Const world_col=3

Collisions ball_col,world_col,2,2
Collisions ball_col,ball_col,1,2

Type ball
Field Ball_Type
Field e ;entity
Field sphere
Field pivot
Field x#,y#,z# ; position in 3d-space
Field vx#,vy#,vz# ; velocity
Field ax#,ay#,az# ; acceleration
Field size#
Field bounce# ; bounce factor
Field vel#
Field vx2#,vy2#,vz2# ; temp velocity
Field xSpd#,xSpdMax#,xSpdMin#
Field zSpd#,zSpdMax#,zSpdMin#
End Type

Function ballnew.ball(x#,y#,z#,size#=1,bounce#=0.9,Ball_Type)
c.ball=New ball
c\x#=x#
c\y#=y#
c\z#=z#
c\size=size
c\bounce#=bounce#
c\e=CreatePivot()
c\sphere=CreateSphere(16)
c\pivot=CreatePivot()
EntityType c\e,ball_col
EntityRadius c\e,c\size
PositionEntity c\e,c\x,c\y,c\z
ScaleEntity c\sphere,c\size,c\size,c\size
EntityColor c\sphere,Rnd(0,255),Rnd(0,255),Rnd(0,255)
c\Ball_Type=Ball_Type
c\xSpdMin#=-.02
c\xSpdMax#=.02
c\zSpdMin#=-.02
c\zSpdMax#=.02
Return c
End Function

Function ballupdate()
For c.ball=Each ball
c\vy#=c\vy#+gravity#

c\vx#=c\vx#+c\ax#
c\vy#=c\vy#+c\ay#
c\vz#=c\vz#+c\az#

c\x#=EntityX(c\e)
c\y#=EntityY(c\e)
c\z#=EntityZ(c\e)
TranslateEntity c\e,c\vx,c\vy,c\vz
Next
UpdateWorld()
For c.ball=Each ball
;correct velocity if collided
c\vx2=(EntityX(c\e)-c\x)
c\vy2=(EntityY(c\e)-c\y)
c\vz2=(EntityZ(c\e)-c\z)
c\x#=EntityX(c\e)
c\y#=EntityY(c\e)
c\z#=EntityZ(c\e)
PositionEntity c\sphere,c\x,c\y,c\z
PositionEntity c\pivot,c\x,c\y,c\z
If EntityCollided(c\e,world_col)
For i = 1 To CountCollisions(c\e)

Ent=CollisionEntity (c\e, i)
; Get the normal of the surface which the entity collided with.
Nx# = CollisionNX(c\e, i)
Ny# = CollisionNY(c\e, i)
Nz# = CollisionNZ(c\e, i)
; Compute the dot product of the entity's motion vector and the normal of the surface collided with.
VdotN# = c\vx#*Nx# + c\vy#*Ny# + c\vz#*Nz#
; Calculate the normal force.
NFx# = -2.0 * Nx# * VdotN#
NFy# = -2.0 * Ny# * VdotN#
NFz# = -2.0 * Nz# * VdotN#
; Add the normal force to the direction vector.
c\vx# = c\vx# + NFx# * c\bounce#
c\vy# = c\vy# + NFy# * c\bounce#
c\vz# = c\vz# + NFz# * c\bounce#
avx#=EntityPitch(c\sphere)
avy#=EntityYaw(c\sphere)
avz#=EntityRoll(c\sphere)
;Rotate stuff
;Get vector from center to collision
dx1#=(CollisionX(c\e,i)-c\x)
dy1#=(CollisionY(c\e,i)-c\y)
dz1#=(CollisionZ(c\e,i)-c\z)
dx2#=c\vx
dy2#=c\vy
dz2#=c\vz
;Cross product
cx# = ( dy1 * dz2 ) - ( dz1 * dy2 )
cy# = ( dz1 * dx2 ) - ( dx1 * dz2 )
cz# = ( dx1 * dy2 ) - ( dy1 * dx2 )
AlignToVector c\pivot,cx,cy,cz,1

;Add Force to other Ball
For Hit.Ball = Each Ball
If Hit\E = Ent Then
If Hit\Ball_Type=2 div=2
If Hit\Ball_Type=3 div=1.5
Hit\vx# = Hit\vx# - NFx#/div
Hit\vy# = Hit\vy# - NFy#/div ;Force /2 assumes balls equal in mass
Hit\vz# = Hit\vz# - NFz#/div
End If
Next
Next

Nx# = CollisionNX(c\e, 1)
Ny# = CollisionNY(c\e, 1)
Nz# = CollisionNZ(c\e, 1)
AlignToVector c\e,Nx#,Ny#,Nz#,2,0.5
c\vel#=Sqr(c\vx2*c\vx2+c\vy2*c\vy2+c\vz2*c\vz2)
;slow down due to friction
c\vx#=c\vx*0.99
c\vy#=c\vy*0.99
c\vz#=c\vz*0.99
EndIf
EntityParent c\sphere,c\pivot
TurnEntity c\pivot,-c\vel#*(180/Pi)/c\size#,0,0
EntityParent c\sphere,0
c\ax#=0
c\ay#=0
c\az#=0
Next
End Function

Function ballcontrol(Ball_Type)
For c.ball=Each ball
If Ball_Type=c\Ball_Type
;**** Add Directional Speed ****
If KeyDown(203) And c\xSpd#>c\xSpdMin#
c\xSpd#=c\xSpd#-.001;Left
EndIf
If KeyDown(205) And c\xSpd#<c\xSpdMax#
c\xSpd#=c\xSpd#+.001;Right
EndIf
If KeyDown(200) And c\zSpd#>c\zSpdMin#
c\zSpd#=c\zSpd#+.001;Up
EndIf
If KeyDown(208) And c\zSpd#<c\zSpdMax#
c\zSpd#=c\zSpd#-.001;Down
EndIf

;**** Subtract Directional Speed ****
If Not KeyDown(203) And KeyDown(205)
If c\xSpd#<0 c\xSpd#=c\xSpd#*.96
If c\xSpd#>0 c\xSpd#=c\xSpd#*.96
If c\xSpd#<.0001 And c\xSpd#>-.0001 Then c\xSpd#=0
EndIf

If Not KeyDown(200) And KeyDown(208)
If c\zSpd#<0c\zSpd#=c\zSpd#*.96
If c\zSpd#>0 c\zSpd#=c\zSpd#*.96
If c\zSpd#<.0001 And c\zSpd#>-.0001 Then c\zSpd#=0
EndIf

TFormVector c\xSpd#,0,c\zSpd#,c\e,0
c\ax#=TFormedX()
c\ay#=TFormedY()
c\az#=TFormedZ()

If KeyHit(57);jump
TFormVector 0,2,0,c\e,0
c\ax#=c\ax+TFormedX()
c\ay#=c\ay+TFormedY()
c\az#=c\az+TFormedZ()
EndIf
EndIf
Next
End Function

Function In_Action()
While Not KeyDown(1)
; Frame limiting
Repeat
frameElapsed = MilliSecs () - frameTime
Until frameElapsed
frameTicks = frameElapsed / framePeriod
frameTween# = Float (frameElapsed Mod framePeriod) / Float (framePeriod)
; Update game and world state
For frameLimit = 1 To frameTicks
If frameLimit = frameTicks Then CaptureWorld
frameTime = frameTime + framePeriod
; ----------------------------------

ballcontrol(1)
ballupdate()

Next

RenderWorld frameTween
Text 10,10,"Rendered Tris : "+ TrisRendered()
Text 10,30,"Use the Arrow Keys to Move"
Text 10,40,"Use the Spacebar to jump"
Flip
Wend
End Function

While Not KeyDown(1)
In_Action()
Wend


DJWoodgate(Posted 2005) [#2]
Well I think I know why it is doing it. You are tforming a vector from the entity to the world. All well and good but you are also aligning this entity to the normals of the collision with another ball. The two combined are causing the problem.

Now I am not sure you need that aligntovector at all, and as for the ball control impulses I would apply them based on the camera yaw, which may be more useful. (Tform from a pivot which just yaws the camera).

Something else to bear in mind with colliding balls is that you can from memory get anywhere from 1 to 3 collisions per impact. (There is some code posted somewhere that demonstrates this - here it is http://www.blitzbasic.co.nz/Community/posts.php?topic=27138 ). You might want to account for this, but at the end of the day as long as the thing behaves as you want I would not worry too much.


D_Town_Tony(Posted 2005) [#3]
YOU ARE MY NEW FAVORITE PERSON.


D_Town_Tony(Posted 2005) [#4]
Taking out the aligntovector worked great


Barliesque(Posted 2005) [#5]
I'm afraid I've found a problem. I tried pushing the system a little further by creating several objects. Try this in place of the three lines to create the balls...

For MakinBalls = 1 To 40
	ball.ball=ballnew(10+Rnd(0,5),100+Rnd(0,5),-30-Rnd(0,20), Rnd(1,2), 0.8, (MakinBalls Mod 3)+1) 
Next


I find that they gradually get stuck in space. Looks to me like they're getting caught up in a perpetual loop reacting to collisions-- except that they aren't vibrating at all. So I don't know. I'll keep looking.


DJWoodgate(Posted 2005) [#6]
Well as it stands it's only processing collisions when there is a world contact. But it is a work in progress.


D_Town_Tony(Posted 2005) [#7]
Barliesque-Thanks for pointing that out, fortunatly for me I don't need that many balls on the screen during the game.


Barliesque(Posted 2005) [#8]
Well it's a great little piece of code. Would be nice to sort out that problem so it's usable for other projects as well---either new projects of your own, or others in the community.

Actually... I don't think it's the number of balls that causes the problem. It's just that having so many in there at once makes it more likely for the problem to occur. If that's true, then it could happen infrequently even with only three balls.