在这篇文章中出色的答案的引导下,我试图获得一个ArrowLoop不使用箭头表示法的工作示例。在我完全理解箭头在幕后的工作原理之前,我对使用箭头表示法感到不舒服。话虽这么说,我已经构建了一个小程序,基于我对 Arrows 的(有限)理解应该可以工作。然而,它最终以可怕的异常终止<<loop>>:
module Main where
import Control.Wire
import FRP.Netwire
farr :: SimpleWire (Int, Float) (String, Float)
farr = let
fn :: Int -> Float -> ((String, Float), SimpleWire (Int, Float) (String, Float))
fn i f = (("f+i: " ++ (show (fromIntegral i + f)), f + 0.1), loopFn)
loopFn :: SimpleWire (Int, Float) (String, Float)
loopFn = mkSFN $ \(i, f) -> fn i f
in
mkSFN $ \(i, _) -> fn i 0.0 …Run Code Online (Sandbox Code Playgroud) 我一直想给FRP一点时间,昨天我终于咬了一口,然后开始使用Netwire 5开始(这本身就是一个相当随意的选择,但我必须从某个地方开始!).我已经设法达到了"有效的代码"这一点,但我注意到了一些模式,我不确定它们是如何使用库的一部分,或者它们是否是我的症状.在某处做错了什么.
我从这个教程开始,这足以让我很容易地启动和运行 - 我现在有一个由简单的"递增数字"线控制的旋转立方体:
spin :: (HasTime t s, Monad m) => Wire s e m a GL.GLfloat
spin = integral 0 . 5
Run Code Online (Sandbox Code Playgroud)
当按下"Esc"时,应用程序将退出,使用netwire-input-glfw中提供的电线:
shouldQuit :: (Monoid e, Functor m, Monad m) => Wire s e (GLFWInputT m) a a
shouldQuit = keyPressed GLFW.Key'Escape
Run Code Online (Sandbox Code Playgroud)
这些之间的一个重要区别是spin永远不会抑制 - 它应该总是返回一些价值 - 同时一直shouldQuit抑制; 直到按键实际被按下,在这种情况下我退出了应用程序.
让我感到不安的是我最终不得不使用这些电线的方式.现在,它看起来像这样:
(wt', spinWire') <- stepWire spinWire st $ Right undefined
((qt', quitWire'), inp'') <- runStateT (stepWire quitWire st $ Right …Run Code Online (Sandbox Code Playgroud) 三个月后更新
我在下面的回答中使用netwire-5.0.1+ sdl,在使用Arrows和Kleisli Arrows进行I/O的功能反应编程结构中.虽然太简单,不能被称为"游戏",但它应该是非常可组合的并且非常可扩展.
原版的
我正在学习Haskell,并尝试用它制作一个小游戏.但是,我想看看小型(规范)文本游戏的结构.我也尽量保持代码尽可能纯净.我现在正在努力了解如何实施:
State,在http://www.gamedev.net/page/resources/_/technical/game-programming/haskell-game-object-design-or-how-functions-can-get-you中试了一下-apples-r3204,但是虽然单个组件可以在有限的步骤中工作和更新,但我看不出如何在无限循环中使用它.如果可能的话,我想看一个基本上最小的例子:
我没有任何可用的代码,因为我无法获得最基本的东西.我在网上找到的任何其他材料/示例都使用其他一些库,比如SDL或GTK驱动事件.我发现在Haskell中完全写的唯一一个是http://jpmoresmau.blogspot.com/2006/11/my-first-haskell-adventure-game.html,但是那个在主循环中看起来不像是一个尾递归(同样,我不知道这是否重要).
或者,可能Haskell不打算做这样的事情?或者我可能应该放入mainC?
编辑1
所以我在https://wiki.haskell.org/Simple_StateT_use中修改了一个小例子,使它更简单(并且它不符合我的标准):
module Main where
import Control.Monad.State
main = do
putStrLn "I'm thinking of a number between 1 and 100, can you guess it?"
guesses <- execStateT (guessSession answer) 0
putStrLn $ "Success in " ++ (show guesses) ++ " tries."
where
answer = …Run Code Online (Sandbox Code Playgroud) 正如问题标题所说,我正在尝试创建一条产生位置的导线(在每一步中以一定的速度移动位置),"弹跳"掉其他物体.我能想到的最简单的例子就是在一个盒子里移动,就像在一些屏幕保护程序中一样.
我写这个函数是为了做到这一点(仅针对一个轴):
import Control.Wire
bouncyWire :: Double -> Double -> Double -> Double -> Wire () IO a Double
bouncyWire startPosition startVelocity lowerBound upperBound = proc _ -> do
rec
v <- delay startVelocity -< if p < lowerBound || p > upperBound
then -v else v
p <- integral_ startPosition -< v
returnA -< p
Run Code Online (Sandbox Code Playgroud)
(我实际上使用它与不同的monad,但这段代码实际上并没有使用它,这会使问题过于复杂).
counterSession $ 1/60然而,踩着它,我遇到了一个问题 - 而不是从墙上"弹跳",它会卡在那里.我认为发生的事情是它一直在翻转速度v,但我不知道为什么.我想我可能会使用延迟错误或其他东西.