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
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