Here's Bram's adapted to include the correct maths as mentioned above. It seems to work well for every angle.
Stevie
;setup graphics
Graphics3D 800, 600, 0, 2
SetBuffer BackBuffer()
;create ball image
o = CreateImage(25, 25)
Oval 0, 0, 25, 25
GrabImage o, 0, 0
MidHandle o
;create background image
b = CreateImage(800, 600)
Color 0, 255, 0
Rect 0, 0, 800, 600
Color 0, 0, 0
Rect 10, 10, 779, 579
Color 0, 255, 0
For i = 0 To 25
Oval Rand(800), Rand(600), 25, 25
Rect Rand(800), Rand(600), 25, 25
Next
GrabImage b, 0, 0
Cls
;safety, check what value black has on the screen
Global nulcolor
nulcolor = ReadPixel(10, 10)
;global speed
Global sp#
Const setspeed# = 10
Global snd
;position ball
x# = 0
y# = 0
;velocities
vx# = 1.0
vy# = 1.0
;radius
Radius# = 12.0
;-----------------------------------------------------------------------------------------------------
; Main Loop
;-----------------------------------------------------------------------------------------------------
Repeat
;draw background
DrawBlock b, 0, 0
;get mousehit
mh = MouseHit(1)
;mousehit = release ball
If mh Then
;stop connecting ball to mouse
init = 1
;choose random angle
newd# = Rand(0, 360)
;set velocities (direction ball)
vx = Cos(newd)
vy = Sin(newd)
End If
;during initialization
If (Not init) Or mh Then
;stick ball to mouse
x = MouseX()
y = MouseY()
Else
;check every angle
For CheckAngle# = 0 To 330 Step 30
;get coordinates for check pixel
tx# = Cos( CheckAngle )
ty# = Sin( CheckAngle )
;check if pixel has background color, if so, this is a collision
If test( x + tx * Radius, y + ty * Radius ) Then
;get normal
Nx# = -tx : Ny# = - ty
;move ball 1 pixel away from contact
x = x + Nx : y = y + Ny
;project velocity onto collision normal vector
VdotN# = Vx * Nx + Vy * Ny
;calculate normal force
Nfx# = -2.0 * Nx * VdotN
Nfy# = -2.0 * Ny * VdotN
;add normal force to velocity vector
Vx = Vx + Nfx
Vy = Vy + Nfy
End If
Next
;move ball
x = x + vx
y = y + vy
End If
;draw ball
DrawImage o, x, y
Color 255, 0, 0
Line x, y, x + vx * 5, y + vy * 5
Flip
;esc = exit
Until KeyHit(1)
WaitKey()
End
;-----------------------------------------------------------------------------------------------------
; Test()
;-----------------------------------------------------------------------------------------------------
;checks if a pixel has the background color (protected for screen bounds)
Function test(mx#, my#)
If mx < 1 Then Return 1
If my < 1 Then Return 1
If mx > 798 Then Return 1
If my > 598 Then Return 1
Return (ReadPixel(mx, my) <> nulcolor)
End Function