bloxorz-0.1: Cubezor.hs
module Cubezor where
import Graphics.Rendering.OpenGL
import Etc
import Maps
import Quaternion
-- Cube types
data CubePos = CubePos {
x :: Int,
y :: Int
} deriving Show
data CubeOrientation = Standing | Horizontal | Vertical deriving Eq
data CubeRolling = CrNo | CrUp | CrDown | CrRight | CrLeft | CrFalling | CrWinning deriving (Eq, Show)
data Cube = Cube { pos1 :: CubePos
, pos2 :: CubePos
, angle :: GLfloat
, rolling :: CubeRolling
, quat :: Quaternion
, rotOffset :: Vector3 GLfloat
, rotAxis :: Vector3 GLfloat
, fallOffset :: GLfloat
} deriving Show
cubeRollingSpeed :: GLfloat
cubeRollingSpeed = 360.0
newCube :: Maps.Level -> Cube
newCube level = Cube {
pos1 = p,
pos2 = p,
angle = 0.0,
rolling = CrNo,
quat = quatIdentity,
rotOffset = (Vector3 0.0 0.0 0.0 :: Vector3 GLfloat),
rotAxis = (Vector3 0.0 0.0 0.0 :: Vector3 GLfloat),
fallOffset = 0.0
} where
(x,y) = lStartPos level
p = CubePos {x = x, y = y}
renderCube :: Cube -> IO ()
renderCube cubex = preservingMatrix $ do
let xx = fromIntegral ((x $ pos1 cubex) + (x $ pos2 cubex))
let yy = fromIntegral ((y $ pos1 cubex) + (y $ pos2 cubex))
let zz = if orientation cubex == Standing then 2.0 else 1.0
if (rolling cubex == CrFalling) || (rolling cubex == CrWinning)
then translate (Vector3 0 (fallOffset cubex) 0 :: Vector3 GLfloat)
else return ()
translate $ (Vector3 xx 0 yy :: Vector3 GLfloat)
if rolling cubex /= CrNo
then do
translate $ vecNeg $ rotOffset cubex
rotate (angle cubex) (rotAxis cubex)
translate $ rotOffset cubex
else
return ()
translate $ (Vector3 0.0 zz 0.0 :: Vector3 GLfloat)
m <- quat2Matrix $ quat cubex
multMatrix m
scale (1.0 :: GLfloat) 2.0 1.0
cube
upCube :: Cube -> Cube
upCube cube =
if rolling cube == CrNo
then
cube { rolling = CrUp
, rotAxis = Vector3 (-1.0) 0.0 0.0
, rotOffset = Vector3 0.0 0.0 ro
}
else
cube
where
ro = if orientation cube == Vertical
then 2.0
else 1.0
downCube :: Cube -> Cube
downCube cube =
if rolling cube == CrNo
then
cube { rolling = CrDown
, rotAxis = Vector3 1.0 0.0 0.0
, rotOffset = Vector3 0.0 0.0 ro
}
else
cube
where
ro = if orientation cube == Vertical
then (-2.0)
else (-1.0)
leftCube :: Cube -> Cube
leftCube cube =
if rolling cube == CrNo
then
cube { rolling = CrLeft
, rotAxis = Vector3 0.0 0.0 1.0
, rotOffset = Vector3 ro 0.0 0.0
}
else
cube
where
ro = if orientation cube == Horizontal
then 2.0
else 1.0
rightCube :: Cube -> Cube
rightCube cube =
if rolling cube == CrNo
then
cube { rolling = CrRight
, rotAxis = Vector3 0.0 0.0 (-1.0)
, rotOffset = Vector3 ro 0.0 0.0
}
else
cube
where
ro = if orientation cube == Horizontal
then (-2.0)
else (-1.0)
fallCube :: Cube -> Cube
fallCube cube = cube { rolling = CrFalling
, fallOffset = 0.0
}
winCube :: Cube -> Cube
winCube cube = cube { rolling = CrWinning
, fallOffset = 0.0
}
orientation :: Cube -> CubeOrientation
orientation cube =
if x1 == x2 && y1 == y2
then Standing
else
if x1 < x2 && y1 == y2
then Horizontal
else Vertical
where
x1 = x $ pos1 cube
y1 = y $ pos1 cube
x2 = x $ pos2 cube
y2 = y $ pos2 cube
updateCube :: GLfloat -> Cube -> Cube
updateCube dt cube =
if (angle cube > 90.0) && (rolling cube /= CrFalling) && (rolling cube /= CrWinning)
then
cube { pos1 = p1
, pos2 = p2
, quat = q
, angle = 0
, rolling = CrNo
}
else
if rolling cube /= CrNo
then cube { angle = a
, fallOffset = fo
}
else cube
where
(p1,p2,q) = updatePosition cube
fo = if (rolling cube == CrFalling) || (rolling cube == CrWinning)
then fallOffset cube - 10.0 * dt
else 0.0
a = if rolling cube == CrWinning
then 0.0
else angle cube + cubeRollingSpeed * dt
updatePosition :: Cube -> (CubePos, CubePos, Quaternion)
updatePosition cube =
case rolling cube of
CrUp -> case orientation cube of
Standing -> ( CubePos xx (yy - 2)
, CubePos xx (yy - 1)
, quatMul q qq
)
Horizontal -> ( CubePos xx (yy - 1)
, CubePos (xx + 1) (yy - 1)
, quatMul q qq
)
Vertical -> ( CubePos xx (yy - 1)
, CubePos xx (yy - 1)
, quatMul q qq
)
where q = quatFromAngleAxis piPer2 (-1.0) 0.0 0.0
CrDown -> case orientation cube of
Standing -> ( CubePos xx (yy + 1)
, CubePos xx (yy + 2)
, quatMul q qq
)
Horizontal -> ( CubePos xx (yy + 1)
, CubePos (xx + 1) (yy + 1)
, quatMul q qq
)
Vertical -> ( CubePos xx (yy + 2)
, CubePos xx (yy + 2)
, quatMul q qq
)
where q = quatFromAngleAxis piPer2 1.0 0.0 0.0
CrLeft -> case orientation cube of
Standing -> ( CubePos (xx - 2) yy
, CubePos (xx - 1) yy
, quatMul q qq
)
Horizontal -> ( CubePos (xx - 1) yy
, CubePos (xx - 1) yy
, quatMul q qq
)
Vertical -> ( CubePos (xx - 1) yy
, CubePos (xx - 1) (yy + 1)
, quatMul q qq
)
where q = quatFromAngleAxis piPer2 0.0 0.0 1.0
CrRight -> case orientation cube of
Standing -> ( CubePos (xx + 1) yy
, CubePos (xx + 2) yy
, quatMul q qq
)
Horizontal -> ( CubePos (xx + 2) yy
, CubePos (xx + 2) yy
, quatMul q qq
)
Vertical -> ( CubePos (xx + 1) yy
, CubePos (xx + 1) (yy + 1)
, quatMul q qq
)
where q = quatFromAngleAxis piPer2 0.0 0.0 (-1.0)
-- otherwise just return the old value
_ -> (pos1 cube, pos2 cube, quat cube)
where
xx = x $ pos1 cube
yy = y $ pos1 cube
qq = quat cube
isCubeUpdated :: Cube -> Cube -> Bool
isCubeUpdated cube0 cube1 = (angle cube0 > 90.0) && (angle cube1 == 0.0)