Advertisement
Guest User

Pong

a guest
Jan 23rd, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module Main where
  2.  
  3.     import Graphics.Gloss
  4.     import Graphics.Gloss.Data.ViewPort
  5.     import Graphics.Gloss.Interface.Pure.Game
  6.  
  7.     --utility functions
  8.     updateSeed :: PongGame -> PongGame
  9.     updateSeed game = game {seed = seed'}
  10.        where
  11.            prev = seed game
  12.            seed' = (1103515245 * prev + 12345) `mod` (2^32)
  13.    
  14.     width, height :: Int
  15.     width = 300
  16.     height = 300
  17.    
  18.     playerWidth, playerHeight, moveOffset :: Int
  19.     playerWidth = 10
  20.     playerHeight = 80
  21.     moveOffset = 3
  22.    
  23.     window :: Display
  24.     window = InWindow "Pong" (width, height) (10,10)
  25.    
  26.     background :: Color
  27.     background = white
  28.    
  29.     data PongGame = Game{
  30.         ballLoc :: (Float, Float),
  31.         ballVel :: (Float, Float),
  32.         player1 :: Float,
  33.         player2 :: Float,
  34.    
  35.         stateUpClick :: !Bool,
  36.         stateDownClick :: !Bool,
  37.  
  38.         seed :: !Int
  39.     }deriving Show
  40.    
  41.     render :: PongGame -> Picture
  42.     render game =
  43.         pictures [ball, mkPaddle black (fromIntegral (width `div` 2 - playerWidth `div` 2)) $ player1 game,
  44.         mkPaddle red (fromIntegral (-width `div` 2 + playerWidth `div` 2)) $ player2 game]
  45.         where
  46.             ball = uncurry translate (ballLoc game) $ color ballColor $ rectangleSolid 10 10
  47.             ballColor = black
  48.    
  49.             mkPaddle :: Color -> Float -> Float -> Picture
  50.             mkPaddle col x y = translate x y $ color col $ rectangleSolid (fromIntegral playerWidth) (fromIntegral playerHeight)
  51.    
  52.     initialState :: PongGame
  53.     initialState = Game{
  54.         ballLoc = (-30, -60),
  55.         ballVel = (60, 60),
  56.         player1 = 40,
  57.         player2 = 80,
  58.         stateUpClick = False,
  59.         stateDownClick = False,
  60.         seed = 149327498
  61.     }
  62.    
  63.     moveBall :: Float -> PongGame -> PongGame
  64.     moveBall seconds game = game { ballLoc = (x', y')}
  65.         where
  66.             (x, y) = ballLoc game
  67.             (vx, vy) = ballVel game
  68.    
  69.             x' = x + vx * seconds
  70.            y' = y + vy * seconds
  71.    
  72.     fps :: Int
  73.     fps = 60
  74.    
  75.     type Radius = Float
  76.     type Position = (Float, Float)
  77.    
  78.     wallCollision :: Position -> Radius -> Bool
  79.     wallCollision (_, y) radius = topCollision || bottomCollision
  80.         where
  81.             topCollision = (y - radius) <= (-fromIntegral width/2)
  82.             bottomCollision = (y + radius) >= (fromIntegral width/2)
  83.    
  84.     paddleCollision :: Position -> Float -> Float -> Radius -> Bool
  85.     paddleCollision (x, y) p1 p2 radius = p1Collision || p2Collision
  86.         where
  87.             p1Collision = (x + radius) >= (fromIntegral(width `div` 2 - playerWidth)) && (y + radius) <= (p1 + fromIntegral playerHeight/2) && (y - radius) >= (p1 - fromIntegral playerHeight/2)
  88.    
  89.             p2Collision = (x - radius) <= (fromIntegral(-width `div` 2 + playerWidth)) && (y + radius) <= (p2 + fromIntegral playerHeight/2) && (y - radius) >= (p2 - fromIntegral playerHeight/2)
  90.    
  91.     ballBounce :: PongGame -> PongGame
  92.     ballBounce game = game { ballVel = (vx', vy') }
  93.         where
  94.             radius = 5
  95.             (vx, vy) = ballVel game
  96.             vy' = if wallCollision (ballLoc game) radius
  97.                then
  98.                    -vy
  99.                else
  100.                    vy
  101.            vx' = if paddleCollision (ballLoc game) (player1 game) (player2 game) radius
  102.                 then
  103.                     -vx
  104.                 else
  105.                     vx
  106.    
  107.     playerMovement :: PongGame -> Int -> PongGame
  108.     playerMovement game offset = game { player1 = y'}
  109.        where
  110.            y = player1 game
  111.            y' = if abs(y + fromIntegral offset + fromIntegral (signum offset * playerHeight `div` 2)) < fromIntegral height/2
  112.                     then y + fromIntegral offset
  113.                 else
  114.                     y
  115.    
  116.     computerMovement :: PongGame -> PongGame
  117.     computerMovement game = game { player2 = y'}
  118.        where
  119.            y = player2 game
  120.            (vx, vy) = ballVel game
  121.            (px, py) = ballLoc game
  122.            y' =
  123.                 if (not $ inrange py y)
  124.                     then if y > py
  125.                          then y - fromIntegral moveOffset
  126.                          else
  127.                             y + fromIntegral moveOffset
  128.                 else
  129.                      y
  130.  
  131.             inrange :: Float -> Float -> Bool
  132.             inrange y py = (y + radius) <= (py + fromIntegral playerHeight/2) && (y - radius) >= (py - fromIntegral playerHeight/2)
  133.                 where
  134.                     radius = 5
  135.    
  136.    
  137.     movePlayer :: PongGame -> PongGame
  138.     movePlayer game
  139.         | stateUpClick game = playerMovement game moveOffset
  140.         | stateDownClick game = playerMovement game (-moveOffset)
  141.         | otherwise = game
  142.    
  143.     resetBall :: PongGame -> PongGame
  144.     resetBall game = game { ballLoc = (x', y')}
  145.         where
  146.             randomX = (seed game `mod` 300) - 150
  147.             randomY = (seed game `mod` 300) - 150
  148.             (x, y) = ballLoc game
  149.             x' = if abs x > fromIntegral width/2 then fromIntegral randomX else x
  150.            y' = if abs y > fromIntegral height/2 then fromIntegral randomY else y
  151.                
  152.    
  153.     update :: Float -> PongGame -> PongGame
  154.     update seconds = movePlayer . computerMovement . moveBall seconds . ballBounce . resetBall
  155.    
  156.     handleKeys :: Event -> PongGame -> PongGame
  157.     handleKeys event game
  158.         | (EventKey (SpecialKey KeyUp) Down _ _) <- event
  159.         = game {stateUpClick = True}
  160.         | (EventKey (SpecialKey KeyUp) Up _ _) <- event
  161.         = game {stateUpClick = False}
  162.         | (EventKey (SpecialKey KeyDown) Down _ _) <- event
  163.         = game {stateDownClick = True}
  164.         | (EventKey (SpecialKey KeyDown) Up _ _) <- event
  165.         = game {stateDownClick = False}
  166.         | otherwise = game
  167.    
  168.     main :: IO ()
  169.     main = play window background fps initialState render handleKeys update
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement