'dr_grav.bas
'2d bounce test
'relsoft & Dr. D
'htp://rel.betterwebber.com
'Added by Dr. D
'Gravity and simplified the bouncing by using the
'general reflection vector equation. :*)
defint a-z
option explicit
const PI as single= 3.141593
type point_type
x as single
y as single
end type
type vector2d
x as single
y as single
mag as single
end type
type segment_type
x1 as single
y1 as single
x2 as single
y2 as single
normal as vector2d
end type
type screen_dimension
wid as integer
hei as integer
end type
declare function get_magnitude ( v as vector2d ) as single
declare function get_length ( seg as segment_type ) as single
declare sub normalize (v as vector2d)
declare sub get_2dnormal (seg as segment_type, s as integer)
declare function midpoint (seg as segment_type) as point_type
declare function closest_point_on_line(a as vector2d, b as vector2d, p as vector2d) as vector2d
declare function dot(a as vector2d, b as vector2d) as Single
declare function dist(a as vector2d, b as vector2d) as Single
declare function collide_on_line ( l as segment_type, ball as point_type, v as vector2d,_
radius as integer ) as integer
const MAX_LINES = 9 'max number of line segments
const BALL_SPEED = 4 'speed of ball
screen 18,32,2,0
'vars to hold screen dimensions
dim as screen_dimension sdim
screeninfo sdim.wid, sdim.hei
cls
randomize timer
dim as segment_type ls(0 to MAX_LINES) 'big polygon
dim as segment_type rot_ls(0 to MAX_LINES) 'small polygon
dim as segment_type new_rot_ls(0 to MAX_LINES) 'rotated small polygon
dim p as point_type
dim radius as integer 'radius of big poly
radius = sdim.hei \ 2 - 10
dim as integer scr_mid_x 'center of screen
dim as integer scr_mid_y
scr_mid_x = sdim.wid \ 2
scr_mid_y = sdim.hei \ 2
'init the big poly
dim i as integer
for i = 0 to MAX_LINES - 1
ls(i).x1 = scr_mid_x + cos( 360 * (i/MAX_LINES) * PI /180 ) * (radius)
ls(i).y1 = scr_mid_y + sin( 360 * (i/MAX_LINES) * PI /180 ) * (radius)
ls(i).x2 = scr_mid_x + cos( 360 * ((i + 1)/MAX_LINES) * PI /180 ) * (radius)
ls(i).y2 = scr_mid_y + sin( 360 * ((i + 1)/MAX_LINES) * PI /180 ) * (radius)
get_2dnormal (ls(i), 1)
next i
'Smaller polygon
for i = 0 to MAX_LINES - 1
rot_ls(i).x1 = cos( 360 * (i/MAX_LINES) * PI /180 ) * (radius/2 )
rot_ls(i).y1 = sin( 360 * (i/MAX_LINES) * PI /180 ) * (radius/2 )
rot_ls(i).x2 = cos( 360 * ((i + 1)/MAX_LINES) * PI /180 ) * (radius/2 )
rot_ls(i).y2 = sin( 360 * ((i + 1)/MAX_LINES) * PI /180 ) * (radius/2 )
'get the outside normal
get_2dnormal (rot_ls(i), 0)
next i
'init ball
dim ball as point_type
dim veloc as vector2d 'ball velocity
dim as integer bradius = 10 'radius of ball
ball.x = scr_mid_x + 160 'starting ball coords
ball.y = scr_mid_y + 10
'ball direction
dim as integer angle
angle = rnd * (360)
veloc.x = cos(angle*PI/180) * BALL_SPEED
veloc.y = sin(angle*PI/180) * BALL_SPEED
dim as integer msx, msy, mbutton
dim as single theta 'polygon rotation
screenset 1, 0
do
getmouse msx, msy,,mbutton
'clear the screen
line(0,0)-(sdim.wid-1,sdim.hei-1),0,bf
If mbutton= 1 Then
dim as vector2d targ, position
dim as single vdist
targ.x = msx
targ.y = msy
position.x = ball.x
position.y = ball.y
vdist = dist( targ, position )
veloc.x = ((targ.x-position.x)/vdist)*bradius
veloc.y = ((targ.y-position.y)/vdist)*bradius
End If
'rotate then small poly and save it to another array
theta += 0.03
'theta = 0.0
for i = 0 to MAX_LINES
new_rot_ls(i).x1 = rot_ls(i).x1*cos(Theta) - rot_ls(i).y1*sin(Theta)
new_rot_ls(i).y1 = rot_ls(i).y1*cos(Theta) + rot_ls(i).x1*sin(Theta)
new_rot_ls(i).x2 = rot_ls(i).x2*cos(Theta) - rot_ls(i).y2*sin(Theta)
new_rot_ls(i).y2 = rot_ls(i).y2*cos(Theta) + rot_ls(i).x2*sin(Theta)
'center it
new_rot_ls(i).x1 += scr_mid_x
new_rot_ls(i).y1 += scr_mid_y
new_rot_ls(i).x2 += scr_mid_x
new_rot_ls(i).y2 += scr_mid_y
get_2dnormal (new_rot_ls(i), 0)
next i
'draw the lines
dim as integer sameside = 1
for i = 0 to MAX_LINES - 1
'draw the lines
dim as point_type midpnt
dim as vector2d head
'big poly
line (ls(i).x1, ls(i).y1) - (ls(i).x2, ls(i).y2), rgb(0,0,255)
'draw the normal
midpnt = midpoint (ls(i))
head.x = midpnt.x + ls(i).normal.x * bradius
head.y = midpnt.y + ls(i).normal.y * bradius
line (midpnt.x,midpnt.y)-(head.x,head.y), rgb(255,255,255)
'small rotating poly
line (new_rot_ls(i).x1, new_rot_ls(i).y1) - (new_rot_ls(i).x2, new_rot_ls(i).y2), rgb(138,255,155)
midpnt = midpoint (new_rot_ls(i))
head.x = midpnt.x + new_rot_ls(i).normal.x * bradius
head.y = midpnt.y + new_rot_ls(i).normal.y * bradius
line (midpnt.x,midpnt.y)-(head.x,head.y), rgb(255,255,255)
'check if point is inside the poly
dim as single dota
dim as vector2d v
v.x = new_rot_ls(i).x1 - msx
v.y = new_rot_ls(i).y1 - msy
'draw normal
'add the normals of this line and the previous line...
head.x = new_rot_ls(i).normal.x + new_rot_ls((i+Max_Lines-1) MOD Max_Lines).normal.x
head.y = new_rot_ls(i).normal.y + new_rot_ls((i+Max_Lines-1) MOD Max_Lines).normal.y
'normalize the result
Normalize(Head)
'multiply the normalized vector with the ball radius and add the point of the line
Head.X = new_rot_ls(i).x1 + (Head.X*bradius)
Head.Y = new_rot_ls(i).y1 + (Head.Y*bradius)
line (new_rot_ls(i).x1,new_rot_ls(i).y1)-(head.x,head.y), rgb(255,255,0)
dota = dot(v, new_rot_ls(i).normal)
dim as integer p_side = 0
if dota >=0 then p_side = 1
sameside = sameside and p_side
next i
locate 1,1
if sameside <> 0 then print "inside" else print "outside"
'check for collision
'get out of loop if collided
dim as integer collide = 0 'no collision
'smaller rotating polygon
for i = 0 to MAX_LINES - 1
'check collision on big poly
collide = collide_on_line ( ls(i), ball, veloc, bradius )
'if collide then exit for
'check collision on small poly
collide = collide_on_line ( new_rot_ls(i), ball, veloc, bradius )
'if collide then exit for
next i
'set response
veloc.x*=.99
veloc.y+=.075
ball.x = ball.x + veloc.x
ball.y = ball.y + veloc.y
dim temp as vector2d
temp.x = ball.x
temp.y = ball.y
dim vtemp as vector2d
vtemp.x = veloc.x
vtemp.y = veloc.y
normalize (vtemp)
circle(ball.x,ball.y), bradius, rgb(255,0,255)
pset(msx, msy), rgb(255,255,255)
screensync
sleep 1
screencopy
Loop until inkey$<>""
end
'******************************************************************************
'******************************************************************************
'subs funks
'******************************************************************************
'******************************************************************************
private function get_magnitude ( v as vector2d ) as single
return sqr( ( v.x * v.x ) + ( v.y * v.y ) )
end function
'******************************************************************************
private function get_length ( seg as segment_type ) as single
dim as single a
dim as single b
a = seg.x2 - seg.x1
b = seg.y2 - seg.y1
return sqr( (a * a) + (b * b) )
end function
private sub normalize (v as vector2d)
dim leng as single
leng = sqr(v.x * v.x + v.y * v.y )
v.x = v.x / leng
v.y = v.y / leng
end sub
private sub get_2dnormal (seg as segment_type, s as integer)
if s then
seg.normal.x = -(seg.y2-seg.y1) 'negate to get the other normal
seg.normal.y = (seg.x2-seg.x1) 'erase negatio here if you want the other
'normal
else
seg.normal.x = (seg.y2-seg.y1) 'negate to get the other normal
seg.normal.y = -(seg.x2-seg.x1) 'erase negatio here if you want the other
'normal
end if
normalize (seg.normal)
end sub
private function midpoint (seg as segment_type) as point_type
dim leng as single
dim v as vector2d
dim half_leng as integer
dim p as point_type
leng = get_length ( seg )
v.x = seg.x2 - seg.x1
v.y = seg.y2 - seg.y1
normalize (v)
half_leng = leng / 2
p.x = seg.x1 + ( v.x * half_leng)
p.y = seg.y1 + ( v.y * half_leng)
return p
end function
function closest_point_on_line(a as vector2d, b as vector2d, p as vector2d) as vector2d
dim d as single
dim t as single
dim as vector2d v1, v2, vreturn
v1.x = p.x - a.x
v1.y = p.y - a.y
v2.x = b.x - a.x
v2.y = b.y - a.y
normalize v2
'calculate distance between 2 points a and b
d = dist(a, b)
' p
' /|
' / |
' / |
' / |
' a-------------b
' |----| -> dist "t"
'get the distance of the projected vector from va by dropping a
'perpendicular from v1 to a point in v2
t = dot(v2, v1)
'if our projected distance is less than or equal to 0 then
If t<=0 Then Return a
'if it is >= to the magnitude of the line segment v2 - v1 then
'it's closest to b.
If t>=d Then Return b
'otherwise the point is n betweent the 2 endpoints so we
'create a vector with length "t" and ad it to our original point va
'to trace a line.
vreturn.x = a.x + (v2.x * t)
vreturn.y = a.y + (v2.y * t)
return vreturn
end function
function dot(a as vector2d, b as vector2d) as Single
return (a.x*b.x + a.y*b.y )
end function
function dist(a as vector2d, b as vector2d) as Single
Dim as single dx, dy, ret_dist
dx = a.x - b.x
dy = a.y - b.y
return SQR((dx*dx)+(dy*dy))
end function
function collide_on_line ( l as segment_type, ball as point_type, v as vector2d,_
radius as integer ) as integer
dim as vector2d a,b,xpoint,pnt
a.x = l.x1
a.y = l.y1
b.x = l.x2
b.y = l.y2
pnt.x = ball.x
pnt.y = ball.y
xpoint = closest_point_on_line(a, b, pnt)
dim as single d
d = dist(pnt,xpoint)
if d