'2d bounce test 'relsoft 'htp://rel.betterwebber.com 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 single theta 'polygon rotation screenset 1, 0 do 'clear the screen line(0,0)-(sdim.wid-1,sdim.hei-1),0,bf 'rotate then small poly and save it to another array theta += 0.03 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 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 * 20 head.y = midpnt.y + ls(i).normal.y * 20 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 * 10 head.y = midpnt.y + new_rot_ls(i).normal.y * 10 line (midpnt.x,midpnt.y)-(head.x,head.y), rgb(255,255,255) next i '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 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) 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 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,impulse,impact,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<=radius then a.x = v.x a.y = v.y b.x = -a.x b.y = -a.y impact.x = b.x - a.x impact.y = b.y - a.y impulse.x = l.normal.x impulse.y = l.normal.y 'new = (impact dot impulse)/|impulse| * impulse dim as single comp, leng,s comp = dot(impact, impulse) leng = get_magnitude(impulse) s = (comp)/leng impulse.x = impulse.x * s impulse.y = impulse.y * s v.x = v.x + impulse.x v.y = v.y + impulse.y 'snap it back ball.x = ball.x + l.normal.x * (radius - d ) ball.y = ball.y + l.normal.y * (radius - d ) return 1 end if return 0 end function