首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >正确使用Netwire (5)

正确使用Netwire (5)
EN

Stack Overflow用户
提问于 2015-02-18 23:12:29
回答 1查看 249关注 0票数 5

我一直想给玻璃钢一次机会,昨天我终于咬了一颗子弹,开始使用Netwire 5(这本身是一个相当武断的选择,但我必须从某个地方开始!)我已经到了“代码可以工作”的地步,但我注意到了一些模式,我不确定它们是如何使用库的一部分,或者它们是否是我在某个地方做错事的征兆。

我从本教程开始,这足以让我很容易地启动和运行--我现在有一个旋转立方体,由一个简单的“递增数”线控制:

代码语言:javascript
复制
spin :: (HasTime t s, Monad m) => Wire s e m a GL.GLfloat
spin = integral 0 . 5

当"Esc“按下时,应用程序将退出,并利用网络输入中提供的电线。

代码语言:javascript
复制
shouldQuit :: (Monoid e, Functor m, Monad m) => Wire s e (GLFWInputT m) a a
shouldQuit = keyPressed GLFW.Key'Escape

这两者之间的一个重要区别是,spin从不抑制--它应该总是返回一些值--而shouldQuit一直在抑制;直到键被实际按下,在这种情况下,我退出了应用程序。

让我感到不安的是我不得不使用这些电线的方式。现在,它看起来像这样:

代码语言:javascript
复制
(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很新,所以很难找到“惯用”代码的例子,我可以用它来检查,看看我是否接近目标。这就是这个库的用途,还是我遗漏了什么?

编辑:我成功地解决了我提到的第二个问题(spinEither结果上的模式匹配),方法是将spinshouldQuit组合成一个Wire

代码语言:javascript
复制
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作为这条新线路的输入。诚然,现在只有一种方法,但我仍然不确定这是否是正确的方法。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-03-08 08:46:21

在程序的最顶层,您将有一些具有(缩写)类型Wire a b的线路。这将需要传递一些类型为a的内容,并且每次您迈出一步,它都会返回一些类型为b的内容。例如,ab都可以是游戏的WorldState,也可以是物理模拟器的[RigidBody]。在我看来,在最高级通过Right undefined是可以的。

尽管如此,您忽略了输入线的重要Alternative实例Wire a b。它提供了一个操作符<|>,它以非常好的方式工作:

假设我们有两根电线:

代码语言:javascript
复制
w1 :: Wire a b
w2 :: Wire a b

如果w1抑制,那么

代码语言:javascript
复制
w1 <|> w2 == w2

如果w1不抑制,那么

代码语言:javascript
复制
w1 <|> w2 == w1

这意味着w1 <|> w2只有在w1w2都抑制的情况下才能抑制。这很好,这意味着我们可以做这样的事情:

代码语言:javascript
复制
spin :: (HasTime t s, Monad m) => Wire s e m a GL.GLfloat
spin = integral 0 . (10 . keyPressed GLFW.Key'F <|> 5)

当你按F键时,你的旋转速度会提高一倍!

如果你想在按下按钮后改变电线的语义,你必须更有创意,但不要太多。如果你的电线表现不同,那就意味着你在做某种开关。开关文档主要要求您使用跟随类型

这里有一条电线,作用就像标识线,直到你按下给定的键,然后将永远抑制:

代码语言:javascript
复制
trigger :: GLFW.Key -> GameWire a a
trigger key =
  rSwitch mkId . (mkId &&& ((now . pure mkEmpty . keyPressed key) <|> never))

有了这个,你可以做一些很酷的事情,比如:

代码语言:javascript
复制
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时,这将在前进和后退之间切换旋转器。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28595783

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档