というわけでなんか書いてみた。

module Main
    where

import Graphics.HGL
import Graphics.HGL.Utils
import Int

wid::Int
wid = 640
ht::Int
ht = 480
widf = 640.0
htf = 480.0


data BallState = BallState { speedx, speedy :: Float, posx,posy :: Float }

type CursorPoint = (Float,Float)

topos::BallState->Point
topos b = ( round $ posx b, round $ posy b )

type State = ([BallState],CursorPoint)

black = RGB 0 0 0
yellow = RGB 255 255 0
red = RGB 255 0 0 

drawball:: Point->Graphic
drawball (x,y) = do withRGB black $ ellipse (x-10,y-10) (x+10,y+10)
		    withRGB yellow $ ellipse (x-9,y-9) (x+9,y+9)

drawcursor:: Point->Graphic
drawcursor (x,y) = withRGB black $ do line (x,y-4) (x,y+4)
				      line (x-4,y) (x+4,y)

draw::State->Graphic
draw (balls,(cursorx,cursory)) = do mapM_ drawball $ map topos balls
				    drawcursor ((round cursorx),(round cursory))


gravity:: CursorPoint -> BallState -> BallState
gravity (x2,y2) ball =
    let dx = x2- posx ball
	dy = y2- posy ball
	d = 4/(sqrt $ dx^2 + dy^2)
	a = atan2 dy dx
	sx = speedx ball
	sy = speedy ball
    in  BallState { speedx= sx + ((cos a)*d), speedy= sy + ((sin a)*d), posx=(posx ball)+(sx), posy=(posy ball)+(sy) }

updateState::State->State
updateState (balls,cursor) = (map (gravity cursor) balls,cursor)

clear = withRGB (RGB 255 255 255) $ polygon [(0,0), (wid,0), (wid,ht), (0,ht)]

initialSpeed = 0.8
levelFrame l =
    case l of
	   1 -> (30)*10
	   2 -> (30)*15
	   3 -> (30)*20
	   4 -> (30)*40

levelBalls=
    [ BallState{speedx=initialSpeed, speedy=initialSpeed, posx=0, posy=0},
      BallState{speedx= -initialSpeed, speedy=initialSpeed, posx=widf, posy=0},
      BallState{speedx= -initialSpeed, speedy= -initialSpeed, posx=widf, posy=htf},
      BallState{speedx=initialSpeed, speedy= -initialSpeed, posx=0, posy=htf} ]

checkBall::BallState -> Bool
checkBall b =
    let x = posx b
	y = posy b
	in
	if (x < -3) || (x>widf+3) || (y < -3) ||  (y > htf+3)
	      then False
	      else True

checkBalls::[BallState]->Bool

checkBalls (hd:tl) =
     if checkBall hd then
        checkBalls tl
        else
           False

checkBalls [] = True

nextLevel::Int->Window->IO()
nextLevel l w=
    if l > 4 then
       closeWindow w
    else
       loop (l+1) w (take (l+1) levelBalls,(320,240)) (levelFrame (l+1))
       
			 
loop::Int -> Window -> State -> Int -> IO()
loop level w ( balls, cursorpos ) restFrame =
    do e <- maybeGetWindowEvent w
       case e of
	      Just( MouseMove {pt=(x,y)} ) -> loop level w (balls,(fromIntegral x,fromIntegral y)) restFrame
	      Just( Char {char=c} ) ->
		  if c == '\ESC' then closeWindow w else loop level w (balls,cursorpos) restFrame
	      Nothing ->
		  do setGraphic w $ do { clear; draw (balls,cursorpos) }
		     getWindowTick w
		     if checkBalls balls
			then
			if restFrame == 0
			   then nextLevel level w
			   else loop level w (updateState (balls,cursorpos)) (restFrame-1)

			else
			   closeWindow w
	      _ -> loop level w (balls,cursorpos) restFrame




main::IO()
main = runGraphics $ do w <- openWindowEx "grav" Nothing (wid,ht)
			                  DoubleBuffered (Just 33)
			loop 1 w (take 1 levelBalls, (320.0,240.0)) (levelFrame 1)

マウスカーソルに向かってボールが飛んでくる。ボールを外に出してしまうと終了