packages feed

h-raylib-5.6.0.0: examples/basic-automation-events/src/Main.hs

{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TemplateHaskell #-}

module Main where

import Control.Monad (when)
import Data.Maybe (fromJust, isJust)
import Raylib.Core
  ( clearBackground,
    closeWindow,
    getFrameTime,
    getMousePosition,
    initWindow,
    isKeyDown,
    isKeyPressed,
    isMouseButtonPressed,
    newAutomationEventList,
    peekAutomationEventList,
    playAutomationEvent,
    setAutomationEventBaseFrame,
    setAutomationEventList,
    setTargetFPS,
    startAutomationEventRecording,
    stopAutomationEventRecording,
    windowShouldClose,
  )
import Raylib.Core.Shapes (drawCircleV, drawRectangle, drawRectangleLines)
import Raylib.Core.Text (drawText, measureText)
import Raylib.Types
  ( AutomationEvent (AutomationEvent),
    AutomationEventList (automationEventList'events),
    AutomationEventListRef,
    Color (Color),
    KeyboardKey (KeyDown, KeyLeft, KeyP, KeyR, KeyRight, KeyUp),
    MouseButton (MouseButtonLeft),
    pattern Vector2,
  )
import Raylib.Types.Core (Vector2)
import Raylib.Util (WindowResources, drawing, managed, raylibApplication)
import Raylib.Util.Colors (black, red, white)

type AppState = (WindowResources, Int, Int, Maybe (Vector2, Float), Maybe ([AutomationEvent], Integer), Bool, Bool, Maybe AutomationEventListRef)

startup :: IO AppState
startup = do
  window <- initWindow 800 600 "raylib [core] example - basic automation events"
  setTargetFPS 60
  rWidth <- measureText "REC" 30
  pWidth <- measureText "PLAY" 30
  return (window, rWidth, pWidth, Nothing, Nothing, False, False, Nothing)

mainLoop :: AppState -> IO AppState
mainLoop (window, rWidth, pWidth, mState, playback, playing, recording, lRef) = do
  drawing
    ( do
        toggleRec <- (&& not playing) <$> isKeyPressed KeyR
        let recording' = if toggleRec then not recording else recording
        lRef' <-
          if toggleRec && recording'
            then
              ( do
                  l <- newAutomationEventList
                  Just <$> managed window (setAutomationEventList l)
              )
            else return lRef
        when toggleRec $ if recording' then setAutomationEventBaseFrame 60 >> startAutomationEventRecording else stopAutomationEventRecording
        when recording' $ drawText "REC" (790 - rWidth) 10 30 red

        lEvents <- case lRef' of
          Nothing -> return []
          Just l -> automationEventList'events <$> peekAutomationEventList l
        let playback' =
              if toggleRec && not recording'
                then Just (lEvents, 0)
                else playback
        startPlay <- isKeyPressed KeyP
        let playing' = isJust playback' && not recording' && (startPlay || playing)

        playback'' <-
          if playing'
            then
              ( do
                  let (events, f) = fromJust playback'
                  let (thisFrame, rest) = span (\(AutomationEvent frame _ _) -> frame == f) events

                  drawText "PLAY" (790 - pWidth) 10 30 red
                  mapM_ playAutomationEvent thisFrame

                  if null events then return Nothing else return $ Just (rest, f + 1)
              )
            else return playback'
        let (playback''', playing'') =
              case playback'' of
                Nothing -> if null lEvents then (Nothing, False) else (Just (lEvents, 0), False)
                v -> (v, playing')

        clearBackground white

        mousePressed <- isMouseButtonPressed MouseButtonLeft
        mousePos <- getMousePosition
        frameTime <- getFrameTime
        let mState' = if mousePressed then Just (mousePos, 0) else (\(p, t) -> (p, t + frameTime)) <$> mState
        let mState'' = mState' >>= (\m@(_, t) -> if t > 2 then Nothing else Just m)

        case mState'' of
          Nothing -> drawText "Click somewhere or press the arrow keys" 10 10 20 black >> drawText "Press 'R' to start or stop recording, and 'P' to play the recording" 10 40 20 black
          Just (p@(Vector2 x y), t) ->
            ( do
                when (t < 1.0) $ drawCircleV p (sin (realToFrac t * pi / 1.0) * 10) red
                drawText ("Mouse clicked at (" ++ show x ++ ", " ++ show y ++ ")") 10 (if y < 50 && t < 1.0 then 570 else 10) 20 black
            )

        uDown <- isKeyDown KeyUp
        dDown <- isKeyDown KeyDown
        lDown <- isKeyDown KeyLeft
        rDown <- isKeyDown KeyRight
        let lb = Color 172 204 252 255
        let shiftLeft =
              case mState'' of
                Nothing -> 0
                Just (Vector2 x y, t) -> if x > 580 && y > 490 && t < 1.0 then -580 else 0

        (if uDown then drawRectangle else drawRectangleLines) (660 + shiftLeft) 500 60 40 lb
        (if dDown then drawRectangle else drawRectangleLines) (660 + shiftLeft) 550 60 40 lb
        (if lDown then drawRectangle else drawRectangleLines) (590 + shiftLeft) 550 60 40 lb
        (if rDown then drawRectangle else drawRectangleLines) (730 + shiftLeft) 550 60 40 lb

        return (window, rWidth, pWidth, mState'', playback''', playing'', recording', lRef')
    )

shouldClose :: AppState -> IO Bool
shouldClose _ = windowShouldClose

teardown :: AppState -> IO ()
teardown (window, _, _, _, _, _, _, _) = closeWindow (Just window)

raylibApplication 'startup 'mainLoop 'shouldClose 'teardown