implementation module bounceTypes import StdInt, StdBool, StdReal, StdList, StdFunc, StdTuple import StdPicture, StdIOCommon :: Barrel = { bBase :: Point2 // the base point of the barrel , bWalls :: [Wall] // the walls of the barrel , bDomain :: BarrelDomain // the enclosing rectangular area of the barrel } :: Wall :== ( !Vector2 // the displacement of the wall (a la Polygon) , !Interior // the sign at what side the wall faces the interior ) :: SingleWall :== ( !Line // the exact pixel position of the wall , !Interior ) :: Line :== (!Point2,!Point2) :: BarrelDomain :== Rectangle :: Interior :== Int :: Scale :== (!Real,!Real) // (horizontal scale, vertical scale) :: Radius :== Int :: Ball = { bCenter :: Point2 // the center of the ball , bRadius :: Radius // the radius of the ball , bSpeed :: Vector2 // the direction and speed of the ball , bColour :: Colour // the colour of the ball } leftBarrelSetUp :: (Barrel,[Ball]) leftBarrelSetUp = ( { bBase = {x=600,y=100} , bWalls = [ ({vx = -400,vy = 0 }, 1) , ({vx = 0, vy = -99}, -1) , ({vx = -199,vy = 0 }, 1) , ({vx = 0, vy = 299}, 1) , ({vx = 199, vy = 0 }, -1) , ({vx = 0, vy = -100}, -1) , ({vx = 400, vy = 0 }, -1) ] , bDomain = {corner1={x=(-10),y=(-10)},corner2={x=600,y=310}} } , [ {bCenter={x=30,y=150},bRadius=15,bSpeed={vx=10,vy=3}, bColour=Red } , {bCenter={x=60,y=150},bRadius=10,bSpeed={vx=5, vy=(-9)},bColour=Yellow} ] ) rightBarrelSetUp :: (Barrel,[Ball]) rightBarrelSetUp = ( { bBase = {x=600,y=100} , bWalls = [ ({vx = 400, vy = 0 }, 1) , ({vx = 0, vy = -99 }, 1) , ({vx = 200, vy = 0 }, 1) , ({vx = 0, vy = 299 },-1) , ({vx = -200,vy = 0 },-1) , ({vx = 0, vy = -100}, 1) , ({vx = -400,vy = 0 },-1) ] , bDomain = {corner1={x=600,y=(-10)},corner2={x=1210,y=310}} } , [ {bCenter={x=750,y=150},bRadius=8,bSpeed={vx=6,vy=(-9)},bColour=Magenta} , {bCenter={x=800,y=140},bRadius=9,bSpeed={vx=(-2),vy=3},bColour=Blue } ] ) BarrelToPolygon :: !Scale !Barrel -> (!Point2,!Polygon) BarrelToPolygon scale {bBase,bWalls,bDomain} = (scalebase scale bBase bDomain,{polygon_shape=map (scalewall scale) bWalls}) where scalebase :: !Scale !Point2 !BarrelDomain -> Point2 scalebase (kx,ky) base {corner1} = {x=toInt (kx*(toReal offset.x)),y=toInt (ky*(toReal offset.y))} where offset = base-corner1 scalewall :: !Scale !Wall -> Vector2 scalewall (kx,ky) ({vx,vy},_) = {vx=toInt (kx*(toReal vx)),vy=toInt (ky*(toReal vy))} splitWallsInBarrel :: !Barrel -> (![SingleWall],![SingleWall]) splitWallsInBarrel {bBase,bWalls} = (horizontal,vertical) where (_,horizontal,vertical) = seq (map splitwall bWalls) (bBase,[],[]) splitwall :: !Wall !(!Point2,![SingleWall],![SingleWall]) -> (!Point2,![SingleWall],![SingleWall]) splitwall wall=:(v,interior) (base,horizontal,vertical) | v.vx==0 = (base1,horizontal,[wall1:vertical]) | otherwise = (base1,[wall1:horizontal],vertical) where base1 = movePoint v base wall1 = (orientLine (base,base1),interior) orientLine :: !Line -> Line orientLine (a=:{x=aX,y=aY},b=:{x=bX,y=bY}) | aX==bX # (minY,maxY) = minmax aY bY = ({a & y=minY},{b & y=maxY}) | otherwise # (minX,maxX) = minmax aX bX = ({a & x=minX},{b & x=maxX}) // Common functions: between :: !a !a !a -> Bool | Ord a between x low high | x<=high = x>=low | otherwise = False minmax :: !a !a -> (!a,!a) | Ord a minmax x y | x Real dist {x=x1,y=y1} {x=x2,y=y2} = sqrt (dX*dX+dY*dY) where dX = toReal (x2-x1) dY = toReal (y2-y1) scaleSize :: !Size !Size -> Scale scaleSize size1 size2 = ((toReal size1.w)/(toReal size2.w),(toReal size1.h)/(toReal size2.h))