EDIT : Actually - that does the same as your code - e.g. no reflection and jittery as hell. Seems to be a collision issue which is resolved by moving the orb slightly away from contact.
I made some other changes. Note that there is no need to store the x,y,z position as this is what entityx,y,& z are for. You can then use translateentity based on your velocity vector.
; ID: 415
; Author: Phish
; Modified by F.L.Taylor
; Date: 2002-09-03 11:43:20
; Title: Billiards Style Collision Physics
; Description: 2D circle collision response which can be used for almost anything where 2 objects collide in 2 dimensions
;------------------------------------------
;2D COLLISION DEMO CODE
;------------------------------------------
; By Joseph 'Phish' Humfrey
; This type of collision response isn't
; just useful for pool and billiard style
; games, and in fact, I didn't write it for
; that reason at all. I wrote it because I
; needed to have collision for the space
; ships in my game 'Unity'. When their
; shields are up, they use this relatively
; simple method. It can be used for almost
; anything - player character bouncing off
; enemies in a platform game, to space
; ship collision, to a game which does
; actually involve balls. The basic
; algorithm which I used would work for
; both 2d and 3d, so if you would like to
; see it, email me at <a href="mailto:phish@aelius.com">phish@...;
;------------------------------------------
; The actual code which works out what
; happens after a collision is in the
; HP_OrbPhysicsUpdate() function.
;------------------------------------------
; Enjoy!
;------------------------------------------
;------------------------------------------
Graphics3D 800, 600, 16, 2
SetBuffer BackBuffer()
SeedRnd MilliSecs()
;Collision
Const HP_COLLISIONTYPE_NONE = 0
Const HP_COLLISIONTYPE_ARENA = 1
Const HP_COLLISIONTYPE_PLAYER = 2
Const HP_COLLISIONTYPE_ORB = 3
Const HP_COLLISIONTYPE_POWERUP = 4
Const HP_COLLISIONMETHOD_ELLIPSOID = 1
Const HP_COLLISIONMETHOD_POLYGON = 2
Const HP_COLLISIONMETHOD_BOX = 3
Const HP_COLLISIONRESPONSE_STOP = 1
Const HP_COLLISIONRESPONSE_SLIDE = 2
Const HP_COLLISIONRESPONSE_SLIDENOSLOPE = 3
Collisions(HP_COLLISIONTYPE_ORB,HP_COLLISIONTYPE_PLAYER,HP_COLLISIONMETHOD_BOX,HP_COLLISIONRESPONSE_SLIDE)
Collisions(HP_COLLISIONTYPE_ORB,HP_COLLISIONTYPE_POWERUP,HP_COLLISIONMETHOD_ELLIPSOID,HP_COLLISIONRESPONSE_STOP)
Collisions(HP_COLLISIONTYPE_ORB,HP_COLLISIONTYPE_ARENA,HP_COLLISIONMETHOD_POLYGON,HP_COLLISIONRESPONSE_SLIDE)
Collisions(HP_COLLISIONTYPE_PLAYER,HP_COLLISIONTYPE_ARENA,HP_COLLISIONMETHOD_POLYGON,HP_COLLISIONRESPONSE_SLIDE)
;------------------------------------------
; MAIN DATA TYPE
;------------------------------------------
; This exact type isn't supposed to be used
; Instead, you should use some of the fields
; in your own type, or just use this one
; for reference, to see what each field does
Type HP_orb
Field netid%
; Field x#
; Field y#
; Field z#
Field entity%
Field velx#
Field vely# ;x and y speeds
Field velz#
Field radius# ;radius of circle
Field mass# ;mass of circle
Field state%
End Type
Type HP_PlayerCamera
Field entity%
End Type
Type HP_GameArena
Field entity%
End Type
;------------------------------------------
; SET UP BALLS INTO A POOL STYLE ARRANGEMENT
; FOR DEMO
;------------------------------------------
.Setup
;HP_OrbQ
HP_OrbQ.HP_Orb = New HP_Orb
HP_OrbQ\entity = CreateSphere(64)
EntityShininess(HP_OrbQ\entity,.8)
;HP_OrbQ\x = 20
;HP_OrbQ\y = 20
;HP_OrbQ\velx = -Rnd(4)*.1
;HP_OrbQ\vely = Rnd(4)-2*.1
HP_OrbQ\radius = 1
HP_OrbQ\mass = 50
EntityType(HP_OrbQ\entity%,HP_COLLISIONTYPE_ORB)
EntityRadius(HP_OrbQ\entity%,HP_OrbQ\radius)
;HP_Orbs
For xloop = 1 To 3
For yloop = 1 To 3
HP_Orb.HP_Orb = New HP_Orb
HP_Orb\entity = CopyEntity(HP_OrbQ\entity)
EntityShininess(HP_Orb\entity,.8)
EntityColor(HP_Orb\entity,255,0,0)
PositionEntity HP_Orb\entity, xloop*3, yloop*3, 0
HP_Orb\velx=0
HP_Orb\vely=0
HP_Orb\radius = 1
HP_Orb\mass = 50
; EntityType(HP_Orb\entity%,HP_COLLISIONTYPE_ORB)
EntityRadius(HP_Orb\entity%,HP_Orb\radius)
Next
Next
;Arena
HP_GameArena.HP_GameArena = New HP_GameArena
HP_GameArena\entity=CreateCube()
FlipMesh(HP_GameArena\entity)
PositionEntity(HP_GameArena\entity,15,15,0)
EntityAlpha(HP_GameArena\entity,.5)
ScaleEntity(HP_GameArena\entity,20,20,20)
EntityType(HP_GameArena\entity,HP_COLLISIONTYPE_ARENA)
;Camera
Global HP_PlayerCamera.HP_PlayerCamera = New HP_PlayerCamera
HP_PlayerCamera\entity=CreateCamera()
PositionEntity(HP_PlayerCamera\entity,15,15,-45)
HP_PlayerCameraLight=CreateLight()
RotateEntity(HP_PlayerCameraLight,90,0,0,0)
EntityParent(HP_PlayerCameraLight,HP_PlayerCamera\entity)
;------------------------------------------
;MAIN LOOP
;------------------------------------------
; This is the main While..Wend game loop
While Not KeyDown(1)
If KeyDown(200) TranslateEntity(HP_PlayerCamera\entity,0,0,1);up forward
If KeyDown(201) TranslateEntity(HP_PlayerCamera\entity,0,-1,0);pgup up
If KeyDown(203) TranslateEntity(HP_PlayerCamera\entity,-1,0,0);left
If KeyDown(208) TranslateEntity(HP_PlayerCamera\entity,0,0,-1);down backward
If KeyDown(209) TranslateEntity(HP_PlayerCamera\entity,0,1,0);pgdown down
If KeyDown(205) TranslateEntity(HP_PlayerCamera\entity,1,0,0);right
HP_OrbPhysicsUpdate2()
HP_OrbRender()
UpdateWorld()
RenderWorld()
;------------
; Reset button
Text 10, 10, "Press a LMB Launch Orb, RMB reset."
Text 10, 25, "Press Esc to exit."
If MouseHit(2) Then
ClearWorld()
For HP_Orb.HP_Orb = Each HP_Orb
Delete HP_Orb
Next
Goto setup
End If
If MouseHit(1) Then
HP_OrbQ.HP_Orb = First HP_Orb
HP_OrbQ\velx = -Rnd(4)*.1
HP_OrbQ\vely = Rnd(4)-2*.1
End If
;------------
VWait()
Flip
Wend
;------------------------------------------
;------------------------------------------
End
Function HP_OrbPhysicsUpdate2()
For HP_Orb.HP_Orb = Each HP_Orb
If HP_Orb = First HP_Orb DebugLog(EntityX(HP_Orb\entity)+""+EntityY(HP_Orb\entity)+""+EntityZ(HP_Orb\entity))
;gradually slow down
HP_Orb\velx=HP_Orb\velx*0.99
HP_Orb\vely=HP_Orb\vely*0.99
HP_Orb\velz=HP_Orb\velz*0.99
HP_OrbPhysicsOn=True
If HP_OrbPhysicsOn
For HP_OrbCountCollisions = 1 To CountCollisions(HP_Orb\entity)
; Calculate bounce:
DebugLog("HIT")
; Get the normal of the surface collided with.
HP_OrbPhysicsNx# = CollisionNX#(HP_Orb\entity, HP_OrbCountCollisions)
HP_OrbPhysicsNy# = CollisionNY#(HP_Orb\entity, HP_OrbCountCollisions)
HP_OrbPhysicsNz# = CollisionNZ#(HP_Orb\entity, HP_OrbCountCollisions)
;move it slightly away from collision
TranslateEntity HP_Orb\entity, .01 * HP_OrbPhysicsNx , .01 * HP_OrbPhysicsNy , .01 * HP_OrbPhysicsNz
; Compute the dot product of the ball's motion vector and the normal of the surface collided with.
HP_OrbPhysicsVdotN# = HP_Orb\velx#*HP_OrbPhysicsNx# + HP_Orb\vely#*HP_OrbPhysicsNy# + HP_Orb\velz#*HP_OrbPhysicsNz#
;set coeficient of restitution
COR# = .987654321
;COR# = 0.0 ;inelastic collision
;COR# = 1.0 ;elastic collision
; Calculate the normal force.
HP_OrbPhysicsNFx# = -( 1.0 + COR ) * HP_OrbPhysicsNx# * HP_OrbPhysicsVdotN#
HP_OrbPhysicsNFy# = -( 1.0 + COR ) * HP_OrbPhysicsNy# * HP_OrbPhysicsVdotN#
HP_OrbPhysicsNFz# = -( 1.0 + COR ) * HP_OrbPhysicsNz# * HP_OrbPhysicsVdotN#
HP_Orb\velx# = HP_Orb\velx# + HP_OrbPhysicsNFx#
HP_Orb\vely# = HP_Orb\vely# + HP_OrbPhysicsNFy#
HP_Orb\velz# = HP_Orb\velz# + HP_OrbPhysicsNFz#
Next
EndIf
Next
End Function
;------------------------------------------
Function HP_OrbRender()
;------------------------------------------
; Simple function draws all the circles
; on the screen.
;------------------------------------------
For HP_Orb.HP_Orb = Each HP_Orb
TranslateEntity HP_Orb\entity, HP_Orb\velx, HP_Orb\vely, HP_Orb\velz
Next
End Function