使用netwire进行游戏实体建模

Ven*_*nge 9 haskell frp

我将使用netwire和OpenGL在Haskell中编写实时游戏.基本的想法是每个对象将由一个导线表示,它将获得一些数据作为输入并输出其状态,然后我将它全部挂钩到一个大的线路,将GUI的状态作为输入并输出世界状态,然后我可以将其传递给渲染器以及碰撞检测等一些"全局"逻辑.

我不确定的一件事是:我如何键入电线?并非所有实体都有相同的输入; 玩家是唯一可以访问键输入状态的实体,寻找需要目标位置的导弹等.

  • 一个想法是将一个ObjectInput类型传递给所有东西,但这对我来说似乎很糟糕,因为我可能会意外地引入我不想要的依赖项.
  • 在另一方面,我不知道是否有SeekerWire,一个PlayerWire,一个EnemyWire等,将是一个好主意,因为他们几乎"相同"的,所以我不得不在它们之间复制功能.

我该怎么办?

ert*_*tes 7

抑制幺半群e抑制异常的类型.这不是电线产生的,但大约需要为同样的作用eEither e a.换句话说,如果组合线路<|>,则输出类型必须相等.

假设您的GUI事件通过输入传递到线路,并且您有一个连续的按键事件.建模的一种方法是最直接的:

keyDown :: (Monad m, Monoid e) => Key -> Wire e m GameState ()
Run Code Online (Sandbox Code Playgroud)

该线路将当前游戏状态作为输入,并()在按下该键时产生一个.虽然没有按下按键,但它只是禁止按键.大多数应用程序并不真的在乎,为什么电线抑制,所以大部分的电线与抑制mempty.

表达此事件的更方便的方法是使用阅读器monad:

keyDown :: (Monoid e) => Key -> Wire e (Reader GameState) a a
Run Code Online (Sandbox Code Playgroud)

对于这个变体真正有用的是,现在你不必将游戏状态作为输入传递.相反,这条线在偶数发生时就像身份线一样,并且当它没有时它会抑制:

quitScreen . keyDown Escape <|> mainGame
Run Code Online (Sandbox Code Playgroud)

我们的想法是,当按下keyDown Escape退出键时,事件线会暂时消失,因为它的作用就像身份线一样.因此,整个电线就像quitScreen假设它不会抑制自身一样.一旦释放钥匙,事件线就会抑制,因此组合物quitScreen也会受到抑制.因此,整个电线就像mainGame.

如果你想限制一条线可以看到的游戏状态,你可以轻松地为它编写一个线组合器:

trans :: (forall a. m' a -> m a) -> Wire e m' a b -> Wire e m a b
Run Code Online (Sandbox Code Playgroud)

这允许您申请withReaderT:

trans (withReaderT fullGameStateToPartialGameState)
Run Code Online (Sandbox Code Playgroud)

  • 我真的是唯一一个懂得如何从给定签名中编写`keyDown`的人太傻了吗?我的意思是,你似乎暗示你可以用电线本身的线monad做某事,但我不明白这是怎么回事? (2认同)