First, the main lib:

physics.bi:

Code: Select all

`#Include "fbgfx.bi"`

#Include Once "ext/math/line2.bi"

#Include Once "ext/math/projections.bi"

#Include Once "ext/math/vector2.bi"

Using fb

Type vector2d As ext.math.fbext_Vector2( ((Single)) )

Type line2d As ext.math.fbext_Line2( ((Single)) )

Type circle2d

posi As vector2d

vel As vector2d

radius As Integer

ccolor As Integer

maxvelocity As Integer

Declare Function bounce (ByRef ball As circle2d) As Integer

Declare Function bounce Overload (ByRef wall As line2d) As Integer

Declare Sub halt()

Declare Sub display(ByVal xx_ As single, ByVal yy_ As Single)

Declare Constructor(x As Single, y As Single, rad As Integer, colr As Integer, maxvel As Integer)

Declare Constructor()

End Type

Declare Function lineNormal(ByVal l As line2d, ByVal num As Integer) As vector2d

function circle2d.bounce (byref wall as line2d) as integer

dim as vector2d impulse,impact,xpoint,normal,normal1,normal2,blah1,blah2

xpoint = ext.math.ClampProjectedPoint(wall, this.posi)

dim as single d

d = this.posi.distance(xpoint)

if d < this.radius Then

normal1 = lineNormal(wall, 1)

normal2 = lineNormal(wall, 2)

blah1 = xpoint + normal1

blah2 = xpoint + normal2

if this.posi.distance(blah1) < this.posi.distance(blah2) then normal = normal1

if this.posi.distance(blah1) > this.posi.distance(blah2) then normal = normal2

impact.x = -this.vel.x - this.vel.x

impact.y = -this.vel.y - this.vel.y

impulse = normal

dim as single comp, leng, s

comp = impact.dot(impulse)

leng = impulse.magnitude()

s = (comp)/leng

impulse = impulse * s

this.vel = this.vel + impulse

this.posi = this.posi + normal * (this.radius - d)

return 1

end if

return 0

end function

function circle2d.bounce(byref ball as circle2d) As Integer

if this.posi.distance(ball.posi) <= this.radius + ball.radius then

dim as vector2d impact, impulse

dim impactspeed as double

impact = this.vel - ball.vel

impulse = this.posi - ball.posi

impulse.normalize

impactspeed = impulse.dot(impact)

impulse = impulse * impactspeed

this.vel = this.vel + -(impulse)

ball.vel = ball.vel + impulse

return 1

end if

return 0

end Function

Sub circle2d.halt()

this.vel.x = 0

this.vel.y = 0

End Sub

Sub circle2d.display(ByVal xx_ As single, ByVal yy_ As Single)

Circle(xx_, yy_), this.radius, this.ccolor,,,,f

End Sub

Constructor circle2d(x_ As Single, y_ As Single, rad_ As Integer, colr_ As Integer, maxvel_ As Integer)

this.posi.x = x_

this.posi.y = y_

this.radius = rad_

this.ccolor = colr_

this.maxvelocity = maxvel_

End Constructor

Constructor circle2d()

this.posi.x = 0

this.posi.y = 0

this.radius = 0

this.ccolor = 0

this.maxvelocity = 0

End Constructor

Function lineNormal(ByVal l As line2d, ByVal num As Integer) As vector2d

Dim As vector2d normal1, normal2

normal1.x = -(l.b.y-l.a.y)

normal1.y = (l.b.x-l.a.x)

normal2.x = (l.b.y-l.a.y)

normal2.y = -(l.b.x-l.a.x)

normal1.normalize

normal2.normalize

If num = 1 Then Return normal1

If num = 2 Then Return normal2

End Function

A simple program to test angled line collisions:

Controls:

Arrow keys move the blue circle,

Insert stops the blue circle,

space for new random line

test.bas:

Code: Select all

`#Include "fbgfx.bi"`

#Include "physics.bi"

Using fb

Const accel = .5

Const friction = .02

Dim ball(1 To 6) As circle2d

Dim As vector2d screenmax, blahx, blahy

Dim As line2d l, wall(1 To 4)

Dim As Integer i, j, x, y

Screen 19

Screeninfo x, y

Randomize Timer, 3

screenmax.x = x:screenmax.y = y

With wall(1)

.a.x = 0

.a.y = 0

.b.x = screenmax.x

.b.y = 0

End With

With wall(2)

.a.x = screenmax.x

.a.y = 0

.b.x = screenmax.x

.b.y = screenmax.y

End With

With wall(3)

.a.x = screenmax.x

.a.y = screenmax.y

.b.x = 0

.b.y = screenmax.y

End With

With wall(4)

.a.x = 0

.a.y = screenmax.y

.b.x = 0

.b.y = 0

End With

For i = 1 To 6

With ball(i)

.posi.x = CInt(Rnd * screenmax.x)

.posi.y = CInt(Rnd * screenmax.y)

.radius = CInt(Rnd * 20) + 10

.ccolor = i

End With

Next

Do

With l

.a.x = Rnd * screenmax.x

.a.y = Rnd * screenmax.y

.b.x = Rnd * screenmax.x

.b.y = Rnd * screenmax.y

End With

Do

Screenlock

Cls

With l

Line (.a.x, .a.y)-(.b.x, .b.y), 15

End With

For i = 1 To 6

ball(i).display(ball(i).posi.x, ball(i).posi.y)

Next i

ScreenSync

Screenunlock

If Multikey(SC_UP) Then ball(1).vel.y = ball(1).vel.y - accel

If Multikey(SC_RIGHT) Then ball(1).vel.x = ball(1).vel.x + accel

If Multikey(SC_DOWN) Then ball(1).vel.y = ball(1).vel.y + accel

If Multikey(SC_LEFT) Then ball(1).vel.x = ball(1).vel.x - accel

If Multikey(SC_INSERT) Then ball(1).halt

For i = 1 To 6

ball(i).posi.x += ball(i).vel.x

ball(i).posi.y += ball(i).vel.y

ball(i).vel.x *= (1-friction)

ball(i).vel.y *= (1-friction)

ball(i).bounce(l)

For j = 1 To 4

ball(i).bounce(wall(j))

Next

For j = 1 To 6

ball(i).bounce(ball(j))

Next j

Next

Loop Until Multikey(SC_ESCAPE) Or Multikey(SC_SPACE)

Loop Until Multikey(SC_ESCAPE)

This libby does not deal with mass, so the ball to ball collision is kinda weird. I would have added it, but I wanted to keep the code as simple as possible. If you need mass, it should be simple enough to add.

**Edit:**

The lib is mostly finished. The code has been updated. If there are any bugs, just post them here.

**Edit:**

Finished. Code updated.