snake-hs/app/Main.hs

87 lines
2.9 KiB
Haskell
Raw Normal View History

2026-03-24 15:40:22 +03:00
module Main where
2026-03-28 18:38:00 +03:00
import SDL
2026-03-30 00:01:17 +03:00
import qualified SDL.Font as FONT
2026-03-28 18:38:00 +03:00
import qualified Data.Text as Text
import Control.Monad (unless)
import SDL.Raw (getTicks)
import Data.Word (Word32)
2026-03-30 00:01:17 +03:00
import Foreign.C (CInt)
import Snake
import Assets
import Graphics
2026-03-24 15:40:22 +03:00
main :: IO ()
main = do
2026-03-28 18:38:00 +03:00
initializeAll
2026-03-30 00:01:17 +03:00
FONT.initialize
window <- createWindow (Text.pack "Haskell Snake") defaultWindow {windowInitialSize = snakeWindowSize}
2026-03-28 18:38:00 +03:00
renderer <- createRenderer window (-1) defaultRenderer
2026-03-30 00:01:17 +03:00
assets <- loadAssets renderer
appLoop renderer assets (initialState boardSize (2, 2))
freeAssets assets
2026-03-28 18:38:00 +03:00
destroyRenderer renderer
destroyWindow window
targetFps :: Word32
2026-03-29 21:07:11 +03:00
targetFps = 5
2026-03-28 18:38:00 +03:00
targetFrameMs :: Word32
targetFrameMs = 1000 `div` targetFps
2026-03-30 00:01:17 +03:00
boardSize :: (Int, Int)
boardSize = (12, 8)
boardWindowSize :: (Int, Int) -> V2 CInt
boardWindowSize (w, h) = V2 (fromIntegral w * tileSize) (fromIntegral h * tileSize)
snakeWindowSize :: V2 CInt
snakeWindowSize = boardWindowSize boardSize
appLoop :: Renderer -> Assets -> Game -> IO ()
appLoop renderer assets game = do
2026-03-28 18:38:00 +03:00
frameStart <- getTicks
events <- pollEvents
let eventIsExitPress event = case eventPayload event of
2026-03-30 00:01:17 +03:00
KeyboardEvent keyboardEvent ->
keyboardEventKeyMotion keyboardEvent == Pressed &&
keysymKeycode (keyboardEventKeysym keyboardEvent) == KeycodeQ
WindowClosedEvent _ -> True
_ -> False
2026-03-28 18:38:00 +03:00
exitPressed = any eventIsExitPress events
2026-03-30 00:01:17 +03:00
let eventIsRestartPress event = case eventPayload event of
KeyboardEvent keyboardEvent ->
keyboardEventKeyMotion keyboardEvent == Pressed &&
keysymKeycode (keyboardEventKeysym keyboardEvent) == KeycodeR
_ -> False
restartPresssed = any eventIsRestartPress events
let eventDirectionPress event = case eventPayload event of
2026-03-29 18:39:27 +03:00
KeyboardEvent keyboardEvent ->
if keyboardEventKeyMotion keyboardEvent == Pressed
then getInputByKeycode $ keysymKeycode (keyboardEventKeysym keyboardEvent)
else NothingPressed
_ -> NothingPressed
2026-03-30 00:01:17 +03:00
input = foldMap eventDirectionPress events
(_, updatedGame) <- if restartPresssed then pure (IntoEmpty, initialState (10, 8) (2, 2)) else runTick game input
renderFrame renderer assets updatedGame
2026-03-29 18:39:27 +03:00
unless exitPressed $ do
2026-03-30 00:01:17 +03:00
frameEnd <- getTicks
let elapsed = frameEnd - frameStart
2026-03-29 18:39:27 +03:00
delay (targetFrameMs - elapsed)
2026-03-30 00:01:17 +03:00
appLoop renderer assets updatedGame
2026-03-28 18:38:00 +03:00
2026-03-29 18:39:27 +03:00
getInputByKeycode :: Keycode -> MovementInput
getInputByKeycode KeycodeW = UpPressed
getInputByKeycode KeycodeUp = UpPressed
getInputByKeycode KeycodeD = RightPressed
getInputByKeycode KeycodeRight = RightPressed
getInputByKeycode KeycodeS = DownPressed
getInputByKeycode KeycodeDown = DownPressed
getInputByKeycode KeycodeA = LeftPressed
getInputByKeycode KeycodeLeft = LeftPressed
getInputByKeycode _ = NothingPressed