我一直想给玻璃钢一次机会,昨天我终于咬了一颗子弹,开始使用Netwire 5(这本身是一个相当武断的选择,但我必须从某个地方开始!)我已经到了“代码可以工作”的地步,但我注意到了一些模式,我不确定它们是如何使用库的一部分,或者它们是否是我在某个地方做错事的征兆。
我从本教程开始,这足以让我很容易地启动和运行--我现在有一个旋转立方体,由一个简单的“递增数”线控制:
spin :: (HasTime t s, Monad m) => Wire s e m a GL.GLfloat
spin = integral 0 . 5当"Esc“按下时,应用程序将退出,并利用网络输入中提供的电线。
shouldQuit :: (Monoid e, Functor m, Monad m) => Wire s e (GLFWInputT m) a a
shouldQuit = keyPressed GLFW.Key'Escape这两者之间的一个重要区别是,spin从不抑制--它应该总是返回一些值--而shouldQuit一直在抑制;直到键被实际按下,在这种情况下,我退出了应用程序。
让我感到不安的是我不得不使用这些电线的方式。现在,它看起来像这样:
(wt', spinWire') <- stepWire spinWire st $ Right undefined
((qt', quitWire'), inp'') <- runStateT (stepWire quitWire st $ Right undefined) inp'
case (qt', wt') of
(Right _, _) -> return ()
(_, Left _) -> return () -- ???
(_, Right x) -> --do things, render, recurse into next frame这种模式有两件事让我感到不舒服。首先,我将Right undefined传递给对stepWire的两个调用。我认为(如果我的理解是正确的),这个参数是用来将事件发送到电线上的,而且由于我的电线没有使用任何事件,这是“安全的”,但感觉很糟糕(编辑可能这里的" events“是错误的--本教程将其描述为”阻塞值“,但要点仍然存在--我从未打算阻止,也不打算在我的线路中的任何地方使用e参数)。我想看看是否有一个版本的stepWire,因为你知道你从来没有一个事件,即使你有一个事件,你也不会对它做出反应,但是你看不到一个事件。我试着制作连接e参数(),然后将Right ()传递到任何地方,这感觉比undefined稍微少了一点,但仍然不太能代表我的意图。
类似地,返回值也是一个Either。这对于shouldQuit线路来说是完美的,但请注意,我必须在wt'上进行模式匹配,这是spin线路的输出。我真的不知道这对抑制意味着什么,所以我只是return (),但我可以想象,随着电线数量的增加,这会变得很难处理,而且,它也不像我的意图那样能代表我的意图--拥有一条永不抑制的电线,我可以一直依赖它来保持下一个值。
所以,尽管我有一些代码可以工作,但我还是有一种不安的感觉,那就是我“做错了”,而且由于Netwire 5很新,所以很难找到“惯用”代码的例子,我可以用它来检查,看看我是否接近目标。这就是这个库的用途,还是我遗漏了什么?
编辑:我成功地解决了我提到的第二个问题(spin的Either结果上的模式匹配),方法是将spin和shouldQuit组合成一个Wire
shouldContinuePlaying :: (Monoid e, Functor m, Monad m) => Wire s e (GLFWInputT m) a a
shouldContinuePlaying = keyNotPressed GLFW.Key'Escape
game :: (HasTime t s, Monoid e, Functor m, Monad m) => Wire s e (GLFWInputT m) a GL.GLfloat
game = spin . shouldContinuePlaying沿着这条线走会给我一个更合理的返回值--如果是Left,我可以退出,否则我就有数据要处理了。它还暗示了比我原来的方法更好的可组合性。
不过,我仍然必须将Right undefined作为这条新线路的输入。诚然,现在只有一种方法,但我仍然不确定这是否是正确的方法。
发布于 2015-03-08 08:46:21
在程序的最顶层,您将有一些具有(缩写)类型Wire a b的线路。这将需要传递一些类型为a的内容,并且每次您迈出一步,它都会返回一些类型为b的内容。例如,a和b都可以是游戏的WorldState,也可以是物理模拟器的[RigidBody]。在我看来,在最高级通过Right undefined是可以的。
尽管如此,您忽略了输入线的重要Alternative实例Wire a b。它提供了一个操作符<|>,它以非常好的方式工作:
假设我们有两根电线:
w1 :: Wire a b
w2 :: Wire a b如果w1抑制,那么
w1 <|> w2 == w2如果w1不抑制,那么
w1 <|> w2 == w1这意味着w1 <|> w2只有在w1和w2都抑制的情况下才能抑制。这很好,这意味着我们可以做这样的事情:
spin :: (HasTime t s, Monad m) => Wire s e m a GL.GLfloat
spin = integral 0 . (10 . keyPressed GLFW.Key'F <|> 5)当你按F键时,你的旋转速度会提高一倍!
如果你想在按下按钮后改变电线的语义,你必须更有创意,但不要太多。如果你的电线表现不同,那就意味着你在做某种开关。开关文档主要要求您使用跟随类型。
这里有一条电线,作用就像标识线,直到你按下给定的键,然后将永远抑制:
trigger :: GLFW.Key -> GameWire a a
trigger key =
rSwitch mkId . (mkId &&& ((now . pure mkEmpty . keyPressed key) <|> never))有了这个,你可以做一些很酷的事情,比如:
spin :: (HasTime t s, Monad m) => Wire s e m a GL.GLfloat
spin = integral 0 . spinSpeed
where
spinSpeed = 5 . trigger GLFW.Key'F -->
-5 . trigger GLFW.Key'F -->
spinSpeed当您点击F时,这将在前进和后退之间切换旋转器。
https://stackoverflow.com/questions/28595783
复制相似问题