loop (n-
1) space ballshowPosition :: Body -> IO
()showPosition ball = do
pos <-
get $ position ballprint pos
initWalls :: Space -> IO
()initWalls space =
mapM_ (uncurry $ initWall space) wallPointsinitWall :: Space -> Position -> Position -> IO
()initWall space a b = do
body
<-
newBody infinity infinityshape
<-
newShape body (LineSegment a b wallThickness) 0elasticity shape $=
nearOnespaceAdd space body
spaceAdd space shape
initBall :: Space -> Position -> Velocity -> IO Body
initBall space pos vel = do
body
<-
newBody ballMass ballMomentshape
<-
newShape body (Circle ballRadius) 0Основные библиотеки | 295
position body $=
posvelocity body $=
velelasticity shape $=
nearOnespaceAdd space body
spaceAdd space shape
return body
----------------------------
-- inits
nearOne =
0.9999ballMass =
20ballMoment =
momentForCircle ballMass (0, ballRadius) 0ballRadius =
10initPos = Vector
0 0initVel = Vector
10 5wallThickness =
1wallPoints =
fmap (uncurry f) [((-
w2, -h2), (-w2, h2)),((-
w2, h2),(w2, h2)),
((w2, h2),
(w2, -
h2)),((w2, -
h2),(-
w2, -h2))]where
f a b = (g a, g b)g (a, b) = H.Vector
a bh2 =
100w2 =
100Функция initChipmunk инициализирует библиотеку Chipmunk
. Она должна быть вызвана один раз долюбой из функций библиотеки Hipmunk
. Функции new[Body|Shape|Space] создают объекты модели. Мы сде-лали стены неподвижными, присвоив им бесконечную массу и момент инерции (initWall). Упругость удара
определяется переменной elasticity, она не может быть больше единицы. Единица обозначает абсолютно
упругое столкновение. В документации к Hipmunk
не рекомендуют присваивать значение равное единицеиз-за возможных погрешностей округления, поэтому мы выбираем число близкое к единице. После иници-
ализации элементов модели мы запускаем цикл, в котором происходит обновление модели (step) и печать
положения шарика. Обратите внимание на то, что координаты шарика никогда не выйдут за установленные
рамки.
Теперь объединим OpenGL и Hipmunk:
module Main where
import Control.Applicative
import Control.Applicative
import Data.StateVar
import Data.IORef
import Graphics.UI.GLFW
import System.Exit
import Control.Monad
import qualified Physics.Hipmunk
as
Himport qualified Graphics.UI.GLFW as
Gimport qualified Graphics.Rendering.OpenGL as
Gtitle =
”in the box”----------------------------
-- inits
type Time = Double
-- frames per second
fps :: Int
fps =
60296 | Глава 20: Императивное программирование
-- frame time in milliseconds
frameTime :: Time
frameTime =
1000 * ((1::Double) / fromIntegral fps)nearOne =
0.9999ballMass =
20ballMoment = H.
momentForCircle ballMass (0, ballRadius) 0ballRadius =
10initPos = H.Vector
0 0initVel = H.Vector
0 0wallThickness =
1wallPoints =
fmap (uncurry f) [((-
ow2, -oh2), (-ow2, oh2)),((-
ow2, oh2),(ow2, oh2)),
((ow2, oh2),
(ow2, -
oh2)),((ow2, -
oh2),(-
ow2, -oh2))]where
f a b = (g a, g b)g (a, b) = H.Vector
a bdt :: Double
dt =
0.5minVel :: Double
minVel =
10width, height :: Double
height =
500width =
700w2, h2 :: Double
h2 =
height / 2w2 =
width / 2ow2, oh2 :: Double
ow2 =
w2 - 50oh2 =
h2 - 50data State = State
{ stateBall
:: H.Body
, stateSpace
:: H.Space
}
ballPos :: State -> StateVar H.Position
ballPos = H.
position . stateBallballVel :: State -> StateVar H.Velocity
ballVel = H.
velocity . stateBallmain = do
H.
initChipmunkinitGLFW
state <-
newIORef =<< initStateloop state
loop :: IORef State -> IO
()loop state = do
display state
onMouse state
sleep frameTime
Основные библиотеки | 297
loop state
simulate :: State -> IO Time
simulate a = do
t0 <-
get G. timeH.
step (stateSpace a) dtt1 <-
get G. timereturn (t1 -
t0)initGLFW :: IO
()initGLFW = do
G.
initializeG.
openWindow (G.Size (d2gli width) (d2gli height)) [] G.WindowG.
windowTitle $= titleG.
windowCloseCallback $= exitWith ExitSuccessG.
windowSizeCallback$=
(\size -> G. viewport $= (G.Position 0 0, size))G.
clearColor $= G.Color4 1 1 1 1G.
ortho (-dw2) (dw2) (-dh2) (dh2) (-1) 1where
dw2 = realToFrac w2dh2 =
realToFrac h2initState :: IO State
initState = do
space <- H.
newSpaceinitWalls space
ball <-
initBall space initPos initVelreturn $ State
ball spaceinitWalls :: H.Space -> IO
()initWalls space =
mapM_ (uncurry $ initWall space) wallPointsinitWall :: H.Space -> H.Position -> H.Position -> IO
()