164 lines
8.0 KiB
Haskell
164 lines
8.0 KiB
Haskell
module Dodge.Camera where
|
|
|
|
import Dodge.Data
|
|
import Dodge.Base
|
|
|
|
import Geometry
|
|
|
|
import Control.Lens
|
|
import Control.Monad
|
|
|
|
import Data.Maybe
|
|
import qualified Data.Set as S
|
|
import qualified Data.IntMap.Strict as IM
|
|
|
|
import qualified SDL as SDL
|
|
|
|
updateCamera :: World -> World
|
|
updateCamera = rotCam . moveCamera . updateAimTime . updateScopeZoom
|
|
|
|
updateAimTime :: World -> World
|
|
updateAimTime w
|
|
| SDL.ButtonRight `S.member` _mouseButtons w
|
|
= w & cameraAimTime %~ \t -> min (t+1) 10
|
|
| otherwise = w & cameraAimTime %~ \t -> max (t-1) 0
|
|
|
|
moveCamera :: World -> World
|
|
moveCamera w = w & cameraPos .~ idealPos
|
|
& cameraCenter .~ sightFrom
|
|
where aimRangeFactor | _cameraZoom w == 0 = 0
|
|
| otherwise = (fromMaybe 0 $ yourItem w ^? itAimingRange) / _cameraZoom w
|
|
aimTimeFactor = fromIntegral (w ^. cameraAimTime) / 10
|
|
aimingMult | SDL.ButtonRight `S.member` _mouseButtons w = 1
|
|
| otherwise = 0
|
|
ypos = _crPos $ you w
|
|
idealOffset = rotateV (_cameraRot w) (aimRangeFactor * aimingMult *.* _mousePos w)
|
|
currentOffset = currentPos -.- camCenter
|
|
idealPos = camCenter +.+ rotateV (_cameraRot w)
|
|
-- (aimRangeFactor * aimTimeFactor *.* _mousePos w)
|
|
(aimRangeFactor * aimingMult *.* _mousePos w)
|
|
currentPos = _cameraPos w
|
|
camCenter = ypos +.+ scope
|
|
isCam :: Bool
|
|
isCam = fromMaybe False $ yourItem w ^? itAttachment . _Just . scopeIsCamera
|
|
scope = fromMaybe (0,0) $ yourItem w ^? itAttachment . _Just . scopePos
|
|
sightFrom | isCam = camCenter
|
|
| otherwise = ypos
|
|
|
|
|
|
|
|
|
|
updateScopeZoom :: World -> World
|
|
updateScopeZoom w
|
|
| SDL.ButtonRight `S.member` _mouseButtons w = case w ^? scppoint of
|
|
Just x
|
|
| x > 9 -> zoomInLongGun $ zoomInLongGun
|
|
$ w & creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
. itAttachment . _Just . scopeZoomChange -~ 2
|
|
| x > 0 -> zoomInLongGun
|
|
$ w & creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
. itAttachment . _Just . scopeZoomChange -~ 1
|
|
| x < -9 -> zoomOutLongGun $ zoomOutLongGun
|
|
$ w & creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
. itAttachment . _Just . scopeZoomChange +~ 2
|
|
| x < 0 -> zoomOutLongGun $ zoomOutLongGun
|
|
$ w & creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
. itAttachment . _Just . scopeZoomChange +~ 1
|
|
| otherwise -> w
|
|
_ -> w
|
|
| otherwise = w & creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
. itAttachment . _Just %~ updateScope
|
|
where scppoint = creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
. itAttachment . _Just . scopeZoomChange
|
|
updateScope (ItScope _ _ _ bl) = ItScope (0,0) 0 1 bl
|
|
updateScope otherAtt = otherAtt
|
|
|
|
zoomSpeed = 39/40
|
|
|
|
zoomInLongGun :: World -> World
|
|
zoomInLongGun w | currentZoom < 8 = over (wpPointer . itAttachment . _Just . scopePos)
|
|
(\p -> p +.+ (4-(4*zoomSpeed)) / currentZoom *.* mousep)
|
|
$ over (wpPointer . itAttachment . _Just . scopeZoom) (\z -> z / zoomSpeed)
|
|
w
|
|
| otherwise = w
|
|
where wpPointer = creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
wp = _crInv (_creatures w IM.! 0) IM.! (_crInvSel (_creatures w IM.! 0))
|
|
Just currentZoom = wp ^? itAttachment . _Just . scopeZoom
|
|
mousep = rotateV (_cameraRot w) $ _mousePos w
|
|
|
|
zoomOutLongGun :: World -> World
|
|
zoomOutLongGun w | currentZoom > 0.5 = over (wpPointer . itAttachment . _Just . scopePos)
|
|
-- (\p -> p -.- 2/(2 * currentZoom) *.* _mousePos w)
|
|
-- (\p -> p -.- 2*zoomSpeed/currentZoom *.* p)
|
|
(\p -> p)
|
|
$ over (wpPointer . itAttachment . _Just . scopeZoom) (\z -> z * zoomSpeed)
|
|
w
|
|
| otherwise = w
|
|
where wpPointer = creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
wp = _crInv (_creatures w IM.! 0) IM.! (_crInvSel (_creatures w IM.! 0))
|
|
Just currentZoom = wp ^? itAttachment . _Just . scopeZoom
|
|
currentCursorDisplacement = fromJust $ _itAttachment wp
|
|
|
|
rotCam = rotateCameraL . rotateCameraR . zoomCamIn . zoomCamOut . zoomCam
|
|
|
|
rotateCameraL :: World -> World
|
|
rotateCameraL w | SDL.KeycodeQ `S.member` _keys w
|
|
= w & cameraRot +~ 0.015
|
|
& creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
. itAttachment . _Just . scopePos %~ rotateV 0.015
|
|
| otherwise = w
|
|
rotateCameraR :: World -> World
|
|
rotateCameraR w | SDL.KeycodeE `S.member` _keys w
|
|
= w & cameraRot -~ 0.015
|
|
& creatures . ix 0 . crInv . ix (_crInvSel (_creatures w IM.! 0))
|
|
. itAttachment . _Just . scopePos %~ rotateV (-0.015)
|
|
| otherwise = w
|
|
zoomCamIn :: World -> World
|
|
zoomCamIn w | SDL.KeycodeJ `S.member` _keys w
|
|
= w {_cameraZoom = _cameraZoom w + 0.01}
|
|
| otherwise = w
|
|
zoomCamOut :: World -> World
|
|
zoomCamOut w | SDL.KeycodeK `S.member` _keys w
|
|
= w {_cameraZoom = max (_cameraZoom w - 0.01) 0.01}
|
|
| otherwise = w
|
|
|
|
-- the 395 here limits the max zoom out, is 25 less than the current screen
|
|
-- size, thus matches up with it
|
|
zoomCam :: World -> World
|
|
--zoomCam w = w
|
|
zoomCam w = over cameraZoom changeZoom w
|
|
where maxViewDistance = 800
|
|
camPos = _cameraCenter w
|
|
camRot = _cameraRot w
|
|
wallZoom = min (halfWidth w / (horizontalMax+10) )
|
|
(halfHeight w / (verticalMax+10) )
|
|
idealZoom | SDL.ButtonRight `S.member` _mouseButtons w
|
|
= scZoom *
|
|
(
|
|
min (fromMaybe 20 $ yourItem w ^? itZoom . itAimZoomMax)
|
|
$ max (fromMaybe 0.2 $ yourItem w ^? itZoom . itAimZoomMin)
|
|
(wallZoom * fromMaybe 1 (yourItem w ^? itZoom . itAimZoomFac))
|
|
)
|
|
| otherwise
|
|
= min (fromMaybe 20 $ yourItem w ^? itZoom . itZoomMax)
|
|
$ max (fromMaybe 0.2 (yourItem w ^? itZoom . itZoomMin))
|
|
(wallZoom * fromMaybe 1 (yourItem w ^? itZoom . itZoomFac))
|
|
changeZoom curZoom | curZoom > idealZoom + 0.01 = 0.05 * (19*curZoom + idealZoom)
|
|
| curZoom < idealZoom - 0.01 = 0.05 * (19*curZoom + idealZoom)
|
|
| otherwise = idealZoom
|
|
-- zs = take 20 [-maxViewDistance,0 - 0.9*maxViewDistance..]
|
|
zs = take 9 [-maxViewDistance,0 - 0.8*maxViewDistance..]
|
|
rRays = rotF [( maxViewDistance,y) | y <- zs]
|
|
lRays = rotF [(-maxViewDistance,y) | y <- zs]
|
|
tRays = rotF [(y, maxViewDistance) | y <- zs]
|
|
bRays = rotF [(y,-maxViewDistance) | y <- zs]
|
|
rotF = map (h . (+.+) camPos . rotateV (_cameraRot w))
|
|
h p = fromMaybe p $ collidePointIndirect camPos p $ wallsAlongLine camPos p w
|
|
h' x p = dotV (rotateV camRot x) (p -.- camPos)
|
|
horizontalMax = maximum $ map (h' (1,0)) rRays ++ map (h' (-1,0)) lRays
|
|
verticalMax = maximum $ map (h' (0,1)) tRays ++ map (h' (0,-1)) bRays
|
|
scZoom = fromMaybe 1 $ yourItem w ^? itAttachment . _Just . scopeZoom
|
|
|
|
dirRays :: Float -> [Point2]
|
|
dirRays dir = take 11 $ iterate (rotateV (0.5 * pi / 10)) $ rotateV (dir-pi*0.25) (600,0)
|