-- A framework for a Tetris program. -- It allows an ellipse to be moved left and right, rotated, and dropped -- using keyboard keys. Thus it demonstrates animation. -- by Scot Drysdale on 11/7/07, based on a verson by Chris Bailey-Kellogg import Random import DrawX import Graphics.SOE.Gtk hiding (Region) import qualified Graphics.SOE.Gtk as G (Region) import PictureEX dx = 1 -- Distance to move left or right when hit 'j' or 'l' key columns = 10 -- Columns in the board rows = 15 -- number of rows in the board squareSize = 30 -- Square side length in pixels winX = round (columns * squareSize) -- Width of drawing window in pixels winY = round (rows * squareSize) -- Height of drawing window in pixels speed = 500 -- speed/1000 is the number of seconds to move 1 unit in y. -- Opens a buffered user window for animation using user coordinates. -- Coordinates are min and max X, min and max Y in user coordinates -- and width and height of the window in pixels. Also widow title. openUserWindowEx :: Float -> Float -> Float -> Float -> Int -> Int -> String -> IO UserWindow openUserWindowEx uXmin uXmax uYmin uYmax winX winY title = do w <- openWindowEx title (Just (0,0)) (Just (winX,winY)) drawBufferedGraphic return (WinData w uXmin (uXmax - uXmin) uYmax (uYmax - uYmin) winX winY) main = runGraphics $ do uw <- openUserWindowEx 0.5 (columns + 0.5) 0.5 (rows + 0.5) winX winY "Tetris" stime <- timeGetTime let new = do x <- randomRIO (1, columns) let xRound = roundF x stime <- timeGetTime loop xRound stime (Shape (Ellipse 1 0.5)) -- Loop to control the piece as it drops. -- x is the current x coordinate, stime the starting time when piece -- was dropped. Motion controlled by the time loop :: Float -> Word32 -> Region -> IO () loop x stime piece = do clearWindow (win uw) time <- timeGetTime -- Gets system time in milliseconds let y = rows + 1 - (intToFloat (time - stime))/speed drawPic uw (Region Blue (Translate (x, y) piece)) e <- maybeGetWindowEvent (win uw) case e of Just Closed -> return () Just (Key 'q' True) -> closeWindow (win uw) Just (Key 'j' True) -> loop (left x) stime piece Just (Key 'k' True) -> loop x stime (rotateL piece) Just (Key 'l' True) -> loop (right x) stime piece Just (Key ' ' True) -> new -- Drop the piece _ -> if y < 0 -- Off the bottom? then new else loop x stime piece in new -- Round to integer, then convert back to float roundF = (intToFloat . round) -- Move left if there is space left x = if x-dx<1 then 1 else x-dx -- Move right if there is space right x = if x+dx>columns then columns else x+dx -- Rotate 90 degrees (so to the left) rotateL (Shape (Ellipse r1 r2)) = Shape (Ellipse r2 r1)