this past couple of days I had some free time and I decided to take my time and try to look at vectors. I googled and got a load of sites to search. I ran in to this site:
http://tonypa.pri.ee/vectors/start.htmlit is a vector tutorial website for flash. I noticed that most of the language is similar to blitzmax. So I started looking deep in to it and discovered it is a good site for vectors. I have learned a bit from it so far. I went through all of the tutorials and managed to convert most of them to blitzmax. and also managed to make a demo. And Here it is:
demo:
SuperStrict
Framework BRL.GLMax2D
Import BRL.Random
Import BRL.DXGraphics
SetGraphicsDriver GLMax2DDriver()
Include "lib.bmx"
Type point
Field x#
Field y#
End Type
Type tgame
Field stageW%
Field stageH%
Field maxV#
Field gravity#
Field bounce:vector2d
Field t#
Field LastTime#
Global walllist:TList
Global ballList:TList
Global objlist:TList
Method Create(W%,H%,V#,G#)
walllist = CreateList()
balllist = CreateList()
objlist = CreateList()
stageW = W
stageH = H
maxV = V
gravity = G
'myOb = New vector2d
End Method
Method createObjects(n%)
For Local i% = 1 To n
Local bn:vector2d = New vector2d
bn.p0 = New point
bn.p1 = New point
objlist.addlast(bn)
bn.r=5+Rand(4)*5
bn.m=1
'attach mc
Local x#=i*65;
Local y#=80;
bn.p0.x=x
bn.p0.y=y
x:+i*20
y:+Rand(6)-1
bn.p1.x=x
bn.p1.y=y
bn.updateVector(True);
bn.airf = 1
bn.b = 1
bn.f = 1
bn.r = 20
bn.lastTime = MilliSecs()
Next
End Method
Method createWall(x1#,y1#,x2#,y2#,b#,f#)
Local v:vector2d = New vector2d
walllist.addlast(v)
v.p0 = New point
v.p0.x = x1
v.p0.y = y1
v.p1 =New point
v.p1.x = x2
v.p1.y = y2
v.b = b
v.f = f
v.updatevector(True)
End Method
Method CreateBall(x1#,y1#,R#)
Local B:vector2d = New vector2d
balllist.addlast(B)
b.p0 = New point
b.p0.x = x1
b.p0.y = y1
b.r = R
b.updatevector(True)
End Method
Method speedlimit(ob:vector2d)
If (ob.vx>game.maxV)
ob.vx = game.maxV;
Else If (ob.vx<-game.maxV)
ob.vx = -game.maxV;
EndIf
If (ob.vy>game.maxV)
ob.vy = game.maxV
ElseIf (ob.vy<-game.maxV)
ob.vy = -game.maxV;
EndIf
End Method
Method collitionball2wall(ob:vector2d)
For Local w:vector2d = EachIn game.BallList
Local v:vector2d = ob.ball2ball(w);
Local pen# = ob.r+w.r-v.Length;
' If we have hit the ball
If pen>=0
' move Object away from the ball
ob.p1.x :+ v.dx*pen;
ob.p1.y :+ v.dy*pen;
' change movement, bounce off from the normal of v
Local vbounce:vector2d = New vector2d
vbounce.dx = v.dy
vbounce.dy =-v.dx
vbounce.lx = v.dx
vbounce.ly = v.dy
Local vb:vector2d = ob.bounced(vbounce)
ob.vx = vb.vx
ob.vy = vb.vy
EndIf
Next
End Method
Method collitionball2ball(ob:vector2d)
End Method
Method collitionwall(ob:vector2d)
For Local w:vector2d = EachIn game.walllist
Local v:vector2d = Ob.findIntersection(w);
v = v.updateVector(False);
Local pen# = Ob.r-v.Length;
' If we have hit the wall
If (pen>=0)
' move Object away from the wall
Ob.p1.x :+ v.dx*pen;
Ob.p1.y :+ v.dy*pen;
' change movement, bounce off from the normal of v
Local vbounce:vector2d = New vector2d
vbounce.dx = v.lx
vbounce.dy = v.ly
vbounce.lx = v.dx
vbounce.ly = v.dy
vbounce.b = 1
vbounce.f = 1
Local vb:vector2d = Ob.bounced(vbounce);
Ob.vx = vb.vx;
Ob.vy = vb.vy;
EndIf
Next
End Method
'wrap balls to opoisite side of screen
Method wrap(ob:vector2d)
If (ob.p1.x>game.stageW+ob.r)
ob.p1.x = -ob.r
Else If (ob.p1.x<-ob.r)
ob.p1.x = game.stageW+ob.r
EndIf
If (ob.p1.y>game.stageH+ob.r)
ob.p1.y = -ob.r;
Else If (ob.p1.y<-ob.r)
ob.p1.y = game.stageH+ob.r
EndIf
End Method
Method ball2wall (ob:vector2d)
' start To calculate movement
' dont let it go over Max speed
' update the vector parameters
ob.vx:*ob.airf
ob.vy:*ob.airf
speedlimit(ob)
ob.updateObject();
' check the balls For collisions
collitionball2wall(ob)
collitionwall(ob)
' reset Object To other side If gone out of stage
wrap(ob)
' make End point equal To starting point For Next cycle
ob.p0 = ob.p1
' save the movement without time
ob.vx :/ ob.timeFrame
ob.vy :/ ob.timeFrame
End Method
Method drawall()
SetColor 255,0,0
For Local v:vector2d = EachIn game.BallList
Drawcircle v.p0.x,v.p0.y,v.r
Next
SetColor 0,255,0
For Local v:vector2d = EachIn game.walllist
DrawLineaa v.p0.x,v.p0.y,v.p1.x,v.p1.y
Next
EndMethod ' main Function
Method ball2ball()
Local vc:vector2d = New vector2d
Local vn:vector2d = New vector2d
Local v3:vector2d = New vector2d
Local v4:vector2d = New vector2d
Local p2:point = New point
Local p3:point = New point
Local totalradius#
Local remaining:TList = objlist.copy()
For Local ob:vector2d = EachIn objlist
Local newv:vector2d = New vector2d
remaining.removefirst()
For Local ob2:vector2d = EachIn remaining
'vector between center points of ball
vc.p0 = ob.p0
vc.p1 = ob2.p0
vc.updateVector(True)
'sum of radius
totalRadius=ob.r+ob2.r
Local pen#=totalRadius-vc.length
'check If balls collide at start
If(pen>=0)
'move Object away from the ball
ob.p1.x:-vc.dx*pen
ob.p1.y:-vc.dy*pen
'change movement, bounce off from the normal of v
newv=ob.bounceBalls(ob2, vc)
ob.vx=newv.vx1
ob.vy=newv.vy1
ob2.vx=newv.vx2
ob2.vy=newv.vy2
Else
'reduce movement vector from ball2 from movement vector of ball1
v3.p0 = ob.p0
v3.vx=ob.vx-ob2.vx
v3.vy=ob.vy-ob2.vy
v3.updateVector()
'use v3 as New movement vector For collision calculation
'projection of vc on v3
Local vp:vector2d=vc.projectVector(v3.dx, v3.dy)
'vector To center of ball2 in direction of movement vectors normal
p2.x=ob.p0.x+vp.vx
p2.y=ob.p0.y+vp.vy
vn.p0 = p2
vn.p1 = ob2.p0
vn.updateVector(True)
'check If vn is shorter Then combined radiuses
Local diff#=totalRadius-vn.length;
Local collision%=False
If(diff>0)
'collision
'amount To move back moving ball
Local moveBack#=Sqr(totalRadius*totalRadius-vn.length*vn.length);
p3.x=vn.p0.x-moveBack*v3.dx
p3.y=vn.p0.y-moveBack*v3.dy
'vector from ball1 starting point To its coordinates when collision happens
v4.p0 = ob.p0
v4.p1 = ob.p1
v4.updateVector(True)
'check If p3 is on the movement vector
If(v4.length<=v3.length And v4.dotP(ob)>0)
'collision
Local t#=v4.length/v3.length
collision=True
ob.p1.x=ob.p0.x+t*ob.vx
ob.p1.y=ob.p0.y+t*ob.vy
ob2.p1.x=ob2.p0.x+t*ob2.vx
ob2.p1.y=ob2.p0.y+t*ob2.vy
'vector between centers of ball in the moment of collision
vc.p0 = ob.p1
vc.p1 = ob2.p1
vc.updateVector(True)
newv:vector2d=ob.bounceBalls(ob2, vc)
ob.vx=newv.vx1
ob.vy=newv.vy1
ob2.vx=newv.vx2
ob2.vy=newv.vy2
ob2.makeVector()
ob.makeVector()
EndIf
EndIf
EndIf
Next
Next
End Method
End Type
Type vector2d
Field p0:point
Field p1:point
Field vx#,vy#
Field dx#,dy#
Field rx#,ry#
Field lx#,ly#
Field r#,m#
Field vx1#,vy1#
Field vx2#,vy2#
Field Length#
Field timeFrame#
Field lastTime#
Global airf#
Global b#
Global f#
Method updateObject ()
' find time passed from last update
Local thisTime# = MilliSecs()
Local time# = (thisTime - lastTime)/60
' we use time, Not frames To move so multiply movement vector with time passed
vx :* time
vy :* time
' add gravity, also based on time
vy = vy+time*game.gravity
p1 = New point
' find End point coordinates
p1.x = p0.x+vx;
p1.y = p0.y+vy;
' length of vector
Length = Sqr(vx*vx+vy*vy);
' normalized unti-sized components
dx = vx/Length;
dy = vy/Length;
' Right hand normal
rx = -vy;
ry = vx;
' Left hand normal
lx = vy;
ly = -vx;
' save the current time
lastTime = thisTime;
' save time passed
timeFrame = time;
EndMethod
Method updateVector:vector2d (frompoints:Int = False)
' x And y components
If frompoints
vx = p1.x-p0.x;
vy = p1.y-p0.y;
Else
p0 = New point
p1 = New point
p1.x = p0.x+vx;
p1.y = p0.y+vy;
EndIf
makeVector()
holdvector()
Return Self
End Method
Method makeVector()
'lengthgth of vector
length=Sqr(vx*vx+vy*vy);
'normalized unti-sized components
If(length>0)
dx=vx/length;
dy=vy/length;
Else
dx=0
dy=0
EndIf
'Right hand normal
rx = -dy;
ry = dx;
'Left hand normal
lx = dy;
ly = -dx;
End Method
'Function To hold balls inside stage
Method holdVector()
'reset Object To other side If gone out of stage
If(p1.x>game.stageW-r)
p1.x=game.stageW-r;
vx=-Abs(vx);
ElseIf(p1.x<r)
p1.x=r;
vx=Abs(vx);
EndIf
If(p1.y>game.stageH-r)
p1.y=game.stageH-r;
vy=-Abs(vy);
ElseIf(p1.y<r)
p1.y=r;
vy=Abs(vy);
EndIf
End Method
'calculate dot product of 2 vectors
Method dotP#(v2:vector2d)
Local dp# = vx*v2.vx + vy*v2.vy;
Return dp
End Method
Method findIntersection:vector2d (v2:vector2d)
' vector between center of ball And starting point of wall
Local v3:vector2d = New vector2d
Local v:vector2d
v3.vx = p1.x-v2.p0.x;
v3.vy = p1.y-v2.p0.y;
' check If we have hit starting point
Local dp# = v3.dotP(v2)
If (dp<0)
' hits starting point
v = v3;
Else
Local v4:vector2d = New vector2d
v4.vx = p1.x-v2.p1.x;
v4.vy = p1.y-v2.p1.y;
' check If we have hit side Or endpoint
dp = v4.vx*v2.dx+v4.vy*v2.dy;
If (dp>0)
' hits ending point
v = v4;
Else
' it hits the wall
' project this vector on the normal of the wall
v = v3.projectVector(v2.lx, v2.ly);
EndIf
EndIf
Return v;
EndMethod
' find collision of 2 balls
Method ball2ball:vector2d (b2:vector2d)
' vector between centers of balls
Local v3:vector2d = New vector2d
v3.vx = p1.x-b2.p0.x;
v3.vy = p1.y-b2.p0.y;
v3.Length = Sqr(v3.vx*v3.vx+v3.vy*v3.vy);
v3.dx = v3.vx/v3.Length;
v3.dy = v3.vy/v3.Length;
Return v3;
EndMethod
' find New vector bouncing from v2
Method bounced:vector2d (v2:vector2d)
' projection of v1 on v2
Local proj1:vector2d = projectVector(v2.dx, v2.dy);
' projection of v1 on v2 normal
Local proj2:vector2d = projectVector(v2.lx, v2.ly);
Local proj:vector2d = New vector2d
' reverse projection on v2 normal
proj2.Length = Sqr(proj2.vx*proj2.vx+proj2.vy*proj2.vy);
proj2.vx = v2.lx*proj2.Length
proj2.vy = v2.ly*proj2.Length
' add the projections
proj.vx = proj1.vx+proj2.vx;
proj.vy = proj1.vy+proj2.vy;
Return proj;
EndMethod
Method bounceBalls:vector2d(v2:vector2d, v:vector2d)
Local proj11:vector2d=projectVector(v.dx, v.dy) 'projection of v1 on v
Local proj12:vector2d=projectVector(v.lx, v.ly) 'projection of v1 on v normal
Local proj21:vector2d=v2.projectVector(v.dx, v.dy) 'projection of v2 on v
Local proj22:vector2d=v2.projectVector(v.lx, v.ly) 'projection of v2 on v normal
Local P#= m * proj11.vx + v2.m * proj21.vx;
Local Vn#=proj11.vx-proj21.vx;
Local v2fx#=(P+Vn*m)/(m+v2.m);
Local v1fx#=v2fx-Vn;
P#=m*proj11.vy+v2.m*proj21.vy;
Vn#=proj11.vy-proj21.vy;
Local v2fy#=(P+Vn*m)/(m+v2.m);
Local v1fy#=v2fy-Vn;
Local proj:vector2d = New vector2d
'add the projections For v1
proj.vx1=proj12.vx+v1fx;
proj.vy1=proj12.vy+v1fy;
'add the projections For v2
proj.vx2=proj22.vx+v2fx;
proj.vy2=proj22.vy+v2fy;
Return proj
End Method
' project vector v1 on unit-sized vector dx/dy
Method projectVector:vector2d (dx#, dy#)
' find dot product
Local dp# = vx*dx+vy*dy;
Local proj:vector2d = New vector2d
' projection components
proj.vx = dp*dx;
proj.vy = dp*dy;
Return proj;
EndMethod
End Type
Global game:tgame = New tgame
game.Create(640,640,40,0.4)
game.Createobjects(4)
game.createBall(100,100,30)
game.createBall(400,100,40)
game.createBall(250,250,20)
game.createBall(100,300,15)
game.createball(500,350,25)
game.createwall(0,0,game.stageW-1,0,1,1)
game.createwall(0,game.stageH-1,game.stageW-1,game.stageH-1,1,1)
game.createwall(0,0,0,game.stageH-1,1,1)
game.createwall(game.stageW-1,0,game.stageW-1,game.stageH-1,1,1)
game.createWall(250,110,50,250,1,1)
game.createwall(250,150,250,110,1,1)
game.createWall(50,150,250,150,1,1)
game.createWall(50,250,50,150, 1,1)
game.createWall(250,300,400,280,1,1)
game.createWall(250,300,250,350,1,1)
game.createWall(400,280,400,330,1,1)
game.createWall(250,350,400,330,1,1)
game.createWall(250,620,500,600,1,1)
game.createWall(200,620,200,500,1,1)
Graphics game.stageW,game.stageH
Global mycaps:TG_D3DDEVICEDESC7
If _max2dDriver.ToString() = "DirectX7"
mycaps = New TG_D3DDEVICEDESC7
D3D7GraphicsDriver().Direct3DDevice7().getcaps mycaps
EndIf
Repeat
Cls
game.ball2ball()
game.drawall()
For Local g:vector2d = EachIn game.objlist
game.ball2wall(g)
SetColor 0,0,255
Drawcircle g.p0.x, g.p0.y,g.r
Next
Flip()
Until KeyDown(key_escape)
lib.bmx:
Function DRAWLINEAA(from_x:Float,from_y:Float,to_x:Float,to_y:Float)
If _max2dDriver.ToString() = "DirectX7"
If mycaps.dwRasterCaps_LINE & 4096
Local D3DRS_EDGEANTIALIAS:Int=40
D3D7GraphicsDriver().Direct3DDevice7().setRenderState D3DRS_EDGEANTIALIAS,True
DrawLine from_x,from_y,to_x,to_y
D3D7GraphicsDriver().Direct3DDevice7().setRenderState D3DRS_EDGEANTIALIAS,False
Else
DebugLog "AA not supported"
DrawLine from_x,from_y,to_x,to_y
EndIf
Else
Local saveblend:Int=GetBlend()
SetBlend alphablend
glEnable(GL_LINE_SMOOTH)
DrawLine from_x,from_y,to_x,to_y
SetBlend saveblend
glDisable(GL_LINE_SMOOTH)
EndIf
End Function
Type TG_D3DDeviceDesc7
Field dwDevCaps:Int
Field dwSize_LINE:Int 'Size of structure
Field dwMiscCaps_LINE:Int 'Miscellaneous capabilities
Field dwRasterCaps_LINE:Int 'Raster capabilities
Field dwZCmpCaps_LINE:Int 'Z-comparison capabilities
Field dwSrcBlendCaps_LINE:Int 'Source-blending capabilities
Field dwDestBlendCaps_LINE:Int 'Destination-blending capa bilities
Field dwAlphaCmpCaps_LINE:Int 'Alpha-test-comparison capabilities
Field dwShadeCaps_LINE:Int 'Shading capabilities
Field dwTextureCaps_LINE:Int 'Texture capabilities
Field dwTextureFilterCaps_LINE:Int 'Texture-filtering capabilities
Field dwTextureBlendCaps_LINE:Int 'Texture-blending capabilities
Field dwTextureAddressCaps_LINE:Int 'Texture-addressing capabilities
Field dwStippleWidth_LINE:Int 'Stipple width
Field dwStippleHeight_LINE:Int 'Stipple height
Field dwSize_TRI:Int 'Size of structure
Field dwMiscCaps_TRI:Int 'Miscellaneous capabilities
Field dwRasterCaps_TRI:Int 'Raster capabilities
Field dwZCmpCaps_TRI:Int 'Z-comparison capabilities
Field dwSrcBlendCaps_TRI:Int 'Source-blending capabilities
Field dwDestBlendCaps_TRI:Int 'Destination-blending capa bilities
Field dwAlphaCmpCaps_TRI:Int 'Alpha-test-comparison capabilities
Field dwShadeCaps_TRI:Int 'Shading capabilities
Field dwTextureCaps_TRI:Int 'Texture capabilities
Field dwTextureFilterCaps_TRI:Int 'Texture-filtering capabilities
Field dwTextureBlendCaps_TRI:Int 'Texture-blending capabilities
Field dwTextureAddressCaps_TRI:Int 'Texture-addressing capabilities
Field dwStippleWidth_TRI:Int 'Stipple width
Field dwStippleHeight_TRI:Int 'Stipple height
Field dwDeviceRenderBitDepth:Int
Field dwDeviceZBufferBitDepth:Int
Field dwMinTextureWidth:Int
Field dwMinTextureHeight:Int
Field dwMaxTextureWidth:Int
Field dwMaxTextureHeight:Int
Field dwMaxTextureRepeat:Int
Field dwMaxTextureAspectRatio:Int
Field dwMaxAnisotropy:Float
Field dvGuardBandLeft:Float
Field dvGuardBandTop:Float
Field dvGuardBandRight:Float
Field dvGuardBandBottom:Float
Field dvExtentsAdjust:Float
Field dwStencilCaps:Int
Field dwFVFCaps:Int
Field dwTextureOpCaps:Int
Field wMaxTextureBlendStages:Short
Field wMaxSimultaneousTextures:Short
Field dwMaxActiveLights:Int
Field dvMaxVertexW:Float
Field GUID_Interface_type:Int
Field GUID_1:Short
Field GUID_2:Short
Field GUID_3:Byte
Field GUID_4:Byte
Field GUID_5:Byte
Field GUID_6:Byte
Field GUID_7:Byte
Field GUID_8:Byte
Field GUID_9:Byte
Field GUID_10:Byte
Field wMaxUserClipPlanes:Short
Field wMaxVertexBlendMatrices:Short
Field dwVertexProcessingCaps:Int
Field dwReserved1:Int
Field dwReserved2:Int
Field dwReserved3:Int
Field dwReserved4:Int
End Type
Type Tdrag
Field x% 'object x
Field y% 'object y
Field msx% 'mouse x
Field msy% 'mouse y
Field Width% 'object width
Field Height% 'object height
Field inuse% 'object selected flag
Field dragging% 'mouse dragging object flag
Field Oldmx% ' old mouse x
Field Oldmy% ' old mouse y
Global selected% ' object selected
' create a box(square) object
Function Create:tdrag(x%,y%,Width%,Height%)
Local box:Tdrag = New Tdrag
box.x = x
box.y = y
box.Width = width
box.Height = Height
box.dragging = False
box.inuse = False
Return box
End Function
' test to see if mouse is width in the box/squre object
Method mouseinbox%()
If msx < Self.x Return False
If msx > (Self.x+Self.Width) Return False
If msy < Self.y Return False
If msy > (Self.y+Self.Height) Return False
Return True
End Method
' move object to new position
Method shift()
Self.x :+(msx-oldmx)
Self.y :+(msy-oldmy)
End Method
' check to see if mouse was moved
Method mousemove%()
If oldmx <> msx Return True
If oldmy <> msy Return True
Return False
End Method
' draw Object
Method getxy(x% Var,y% Var)
x = Self.x
y = Self.y
End Method
Method getcenter(x% Var,y% Var)
x = Self.x+width/2
y = Self.y+height/2
End Method
' animate box
Method animate()
msx = MouseX() 'assign to variable to avoid continuous mouse function calls
msy = MouseY() ' '' ''
If MouseDown(1)
If dragging = True
If mousemove() shift() ' set new position of object
Else
If mouseinbox()
If inuse = False
If selected = False
dragging = True ' find box and allow dragging'
selected = True
EndIf
EndIf
Else
inuse = True 'prevent any more selection of object/s
EndIf
EndIf
Else
dragging = False ' if mouse is not pressed stop moving object
inuse = False ' allow selection of object/s
selected = False
End If
oldmx = msx ' store mouse current position for futere use
oldmy = msy ' '' '' ''
End Method
End Type
Function drawcircle (xC%,yC%,radius%)
If (xC-radius) > GraphicsWidth() Return
If (yC-radius) > GraphicsHeight() Return
If (xC+radius) < 0 Then Return
If (yC+radius) < 0 Then Return
Local x:Int = 0
Local d:Int = (2*Radius)
Local y:Int=Radius
While x<y
If d < 0 Then
d = d + (4 * x) + 6
Else
d = d + 4 * (x - y) + 10
y = y - 1
End If
Plot(xC + X, yC + Y)
Plot(xC + X, yC - Y)
Plot(xC - X, yC + Y)
Plot(xC - X, yC - Y)
Plot(xC + Y, yC + X)
Plot(xC + Y, yC - X)
Plot(xC - Y, yC + X)
Plot(xC - Y, yC - X)
x=x+1
Wend
so far the only problem I have is that the balls slow down even with out any friction or gravity.
the source coude is mostly a straight copy from the flash files so keep in mind that the code is copyright and is limited to the conditions here:
http://www.tonypa.pri.ee/vectors/index.htmlother than that you are free to use as you please with this code.
if anybody is interested in some of the original demos( I managed to convert most of them with limitations of mouse control but other than that they are straight copy),I can post them here.



