提问人:TheSinisterStone 提问时间:10/21/2023 最后编辑:K. A. BuhrTheSinisterStone 更新时间:10/22/2023 访问量:71
如何在 Haskell 的 SDL2 绑定中绘制随机放置的矩形?
How to draw randomly-placed rectangles in Haskell's SDL2 bindings?
问:
我正在尝试使用 Haskell 在 SDL2 中绘制随机定位的矩形。IO monad 真的让我发疯,我无法让它工作。我已经准备好了样板 SDL2 代码和 的自定义数据类型,我想做的就是在函数中随机生成矩形,然后在函数中绘制它们。RectangleObject
main
appLoop
我收到错误:
BadRandomRectangles.hs:17:61-85: error:
• Couldn't match expected type: [RectangleObject]
with actual type: IO [RectangleObject]
• In the fourth argument of ‘GameState’, namely
‘(createRandomRectangles 10)’
In the expression:
GameState
(V2 10 10) (V2 40 40) (V2 1 1) (createRandomRectangles 10)
In an equation for ‘gameState’:
gameState
= GameState
(V2 10 10) (V2 40 40) (V2 1 1) (createRandomRectangles 10)
|
17 | let gameState = GameState (V2 10 10) (V2 40 40) (V2 1 1) (createRandomRectangles 10) in
| ^^^^^^^^^^^^^^^^^^^^^^^^^
我的代码是:
{-# LANGUAGE OverloadedStrings #-}
import SDL
import System.Random
import Control.Monad (unless, replicateM)
import Foreign.C.Types (CInt)
data RectangleObject = RectangleObject { rectPosn :: V2 CInt, rectDim :: V2 CInt };
data GameState = GameState { posn :: V2 CInt, dim :: V2 CInt, vel :: V2 CInt, objects :: [RectangleObject] };
main :: IO ()
main = do
initializeAll
window <- createWindow "Rectangles" (defaultWindow { windowInitialSize = V2 640 480 })
renderer <- createRenderer window (-1) defaultRenderer
let gameState = GameState (V2 10 10) (V2 40 40) (V2 1 1) (createRandomRectangles 10) in
appLoop renderer gameState
destroyRenderer renderer
destroyWindow window
quit
appLoop :: Renderer -> GameState -> IO ()
appLoop renderer gameState = do
events <- pollEvents
clear renderer
rendererDrawColor renderer $= V4 0 0 0 255
-- Get the RectangleObjects from the game state and draw them
let objs = objects gameState
mapM_ (\(RectangleObject posn dim) -> fillRect renderer (Just $ Rectangle (P $ posn) dim)) objs
-- Fill a rectangle of size 1280x720 with black color
fillRect renderer (Just $ Rectangle (P $ V2 0 0) (V2 1280 720))
rendererDrawColor renderer $= V4 255 0 0 255
fillRect renderer (Just $ Rectangle (P $ posn gameState) (dim gameState))
present renderer
SDL.delay 16
unless qPressed (appLoop renderer (updateGameState vGameState))
updateGameState :: GameState -> GameState
updateGameState (GameState posn dim vel objs) =
GameState (posn + vel) dim vel objs
createRandomRectangles :: Int -> IO [RectangleObject]
createRandomRectangles n = replicateM n generateRandomRectangle
generateRandomRectangle :: IO RectangleObject
generateRandomRectangle = do
x <- randomRIO (1, 10)
y <- randomRIO (1, 10)
w <- randomRIO (1, 10)
h <- randomRIO (1, 10)
return $ RectangleObject (V2 x y) (V2 w h)
答:
2赞
K. A. Buhr
10/22/2023
#1
您的主要问题是,在此代码中:
let gameState = GameState (V2 10 10) (V2 40 40) (V2 1 1) (createRandomRectangles 10) in
appLoop renderer gameState
表达式是 类型,但对象中的第四个字段是纯 .createRandomRectangles 10
IO [RectangleObject]
GameState
[RectangleObject]
将其改写为:
rects <- createRandomRectangles 10
let gameState = GameState (V2 10 10) (V2 40 40) (V2 1 1) rects in
appLoop renderer gameState
您的函数应键入 check。main
您的代码中仍然有几个未定义的变量( 和 ),渲染器中也存在一些逻辑错误(例如,您正在绘制随机矩形,然后通过用黑色矩形绘制它们来擦除它们)。此外,随机矩形非常小,它们只是在左上角显示为小点。qPressed
vGameState
经过几次调整后,以下代码似乎有效,甚至看起来“像游戏一样”。祝你好运!
{-# LANGUAGE OverloadedStrings #-}
import SDL
import System.Random
import Control.Monad (unless, replicateM)
import Foreign.C.Types (CInt)
data RectangleObject = RectangleObject { rectPosn :: V2 CInt, rectDim :: V2 CInt };
data GameState = GameState { posn :: V2 CInt, dim :: V2 CInt, vel :: V2 CInt, objects :: [RectangleObject] };
main :: IO ()
main = do
initializeAll
window <- createWindow "Rectangles" (defaultWindow { windowInitialSize = V2 640 480 })
renderer <- createRenderer window (-1) defaultRenderer
rects <- createRandomRectangles 10
let gameState = GameState (V2 10 10) (V2 40 40) (V2 1 1) rects in
appLoop renderer gameState
destroyRenderer renderer
destroyWindow window
quit
appLoop :: Renderer -> GameState -> IO ()
appLoop renderer gameState = do
events <- pollEvents
clear renderer
-- Fill a rectangle of size 1280x720 with black color
rendererDrawColor renderer $= V4 0 0 0 255
fillRect renderer (Just $ Rectangle (P $ V2 0 0) (V2 1280 720))
-- Get the RectangleObjects from the game state and draw them in green
let objs = objects gameState
rendererDrawColor renderer $= V4 255 255 0 255
mapM_ (\(RectangleObject posn dim) -> fillRect renderer (Just $ Rectangle (P $ posn) dim)) objs
-- Draw the main game rectangle in red
rendererDrawColor renderer $= V4 255 0 0 255
fillRect renderer (Just $ Rectangle (P $ posn gameState) (dim gameState))
present renderer
SDL.delay 16
-- unless qPressed (appLoop renderer (updateGameState vGameState))
appLoop renderer (updateGameState gameState)
updateGameState :: GameState -> GameState
updateGameState (GameState posn dim vel objs) =
GameState (posn + vel) dim vel objs
createRandomRectangles :: Int -> IO [RectangleObject]
createRandomRectangles n = replicateM n generateRandomRectangle
generateRandomRectangle :: IO RectangleObject
generateRandomRectangle = do
let scale = 500
x <- randomRIO (1, scale)
y <- randomRIO (1, scale)
w <- randomRIO (1, scale)
h <- randomRIO (1, scale)
return $ RectangleObject (V2 x y) (V2 w h)
评论