我试图进入网络,我挖掘了文档,介绍,教程和诸如此类的东西,但几乎每一个教程&现有的代码已经过时了,因为网络5和使用的功能,从网络4,只是不再与我们在一起。自述文件有一定的帮助,但并不是所有的东西都会编译,而且它几乎没有提供足够的信息来开始工作。
我想要一个解释或者一个例子,只是为了让游戏循环运行并且能够对事件做出反应,所以我寻求信息,所以我最终会知道:
main中运行的。还有其他相关的事。
我想,从那里我可以运行一些东西,所以我可以通过实验来学习其余的东西(因为第5版的文档和教程的状态是可怕的不存在,我希望一些很快就会出现)。
谢谢!
发布于 2014-08-16 12:42:25
免责声明:我还没有找到任何使用Netwire的大型程序,所以我要写的每一篇文章都应该带一点点盐,因为它是基于我自己使用Netwire的经验。我在这里使用的示例大多以从我自己的图书馆和使用玻璃钢编写游戏的尝试为例,可能不是“正确的方法”。
问题1:基本结构(比如如何在反应性香蕉中驱动网络--使用处理程序、定义行为和对事件的反应的描述)。
会话:,网络图书馆的作者,给出了一个关于网络程序的基本结构的很好的答案。由于它有点旧,我将在这里概述其中的一些要点。在我们看电线之前,让我们先看看网络是如何处理时间的,这是玻璃钢的底层驱动因素。在不使用测试工具testWire的情况下提高时间的唯一方法是生成一个Session,该Session将有状态地返回时间增量。将Sessions保存状态封装在它们的类型中的方式:
newtype Session m s = Session { stepSession :: m (s, Session m s) }在这里,Session位于Monad (通常是IO)中,每次计算它时,都返回s类型的“时间状态”值和一个新的Session。通常,任何有用的状态s都可以编写为Timed值,该值可以返回Real t的某些实例。
data Timed t s
class (Monoid s, Real t) => HasTime t s | s -> t where
-- | Extract the current time delta.
dtime :: s -> t
instance (Monoid s, Real t) => HasTime t (Timed t s)例如,在游戏中,您通常使用想要一个固定的时间步骤来执行更新调用。netwire将这一概念编码如下:
countSession_ :: Applicative m => t -> Session m (Timed t ())countSession_以时间步骤(在本例中为t类型的固定值)作为输入,并生成状态值为Timed t ()类型的Session。这意味着它们只编码一个类型为t的值,并且不携带带有()值的任何附加状态。在我们讨论电线之后,我们将看到这在评估它们中起着怎样的作用。
导线:网线的主要类型是:
Wire s e m a b此连线描述类型为反应式的b值,该值执行以下操作:
a类型的反应性值作为输入m中运行e类型的抑制值。s给出的时间状态根据无功值的性质,导线可以被认为是时变函数.因此,每条线都被编码为时间(或时间状态s)的函数,在这一时刻产生一个b类型的新值,以及一条新的线来计算类型a的下一个输入。通过返回一个值和一个新线路,函数可以通过函数定义来包含状态。
此外,电线可能抑制或不产生一个值。这对于未定义计算(例如当鼠标位于应用程序窗口之外时)非常有用。这允许您实现像switch这样的东西,其中一条线更改为另一条线以继续执行(例如玩家完成跳转)。
有了这些想法,我们就可以看到网络中电线的主要驱动因素:
stepWire :: Monad m => Wire s e m a b -> s -> Either e a -> m (Either e b, Wire s e m a b)stepWire wire timestate input就像我们前面说的那样:它需要一个wire,并将当前的timestate和input从前面的线路传递给它。然后,在底层的Monad m中,它要么生成Right b的值,要么用Left e的值进行抑制,然后给出下一个用于计算的线路。
问题2:它最终是如何进行的。
使用Session和Wire类型的值,我们可以构造一个循环,它一遍又一遍地做两件事:
下面是一个程序的示例,该程序将固定计数器更改为永久计数为2:
import Control.Wire
-- My countLoop operates in the IO monad and takes two parameters:
-- 1. A session that returns time states of type (Timed Int ())
-- 2. A wire that ignores its input and returns an Int
countLoop :: Session IO (Timed Int ()) -> Wire (Timed Int ()) () IO a Int -> IO ()
countLoop session wire = do
(st, nextSession) <- stepSession session
(Right count, nextWire) <- stepWire wire st (Right undefined)
print count
countLoop nextSession nextWire
-- Main just initializes the procedure:
main :: IO ()
main = countLoop (countSession_ 1) $ time >>> (mkSF_ (*2))问题3:如何处理IO事件(如鼠标单击、按键或游戏循环回调)、事件如何在会话中出现等。
关于如何做到这一点,有一些争论。在这种情况下,我认为最好利用底层的Monad m,只需将当前状态的快照传递给stepWire函数即可。在这样做的时候,我的大部分输入线看起来都是这样的:
mousePos :: Wire s e (State Input) a (Float, Float)其中,忽略对线路的输入,从State单机读取鼠标输入。我使用State而不是Reader来正确地处理键退出(所以点击UI也不会点击UI下面的东西)。状态在我的main函数中设置,并传递给runState,后者也执行线步。像这样的电线的抑制行为可以使一些优雅的代码。例如,假设您的箭头键有连接线right和left,如果按下键并以其他方式进行抑制,则产生值。您可以使用如下所示的电线创建字符移动:
(right >>> moveRight) <|> (left >>> moveLeft) <|> stayPut由于连线是Alternative的一个实例,如果right抑制,它只会转到下一个可能的线路。a <|> b只有在a和b都抑制的情况下才能抑制。
您也可以编写代码来利用netwire的Event系统,但是您必须自己制作使用Control.Wire.Unsafe.Event返回Event的连接。尽管如此,我还没有发现这种抽象比简单的抑制更有用。
发布于 2015-09-29 22:28:54
回答这个问题可能为时已晚,但我在这里有一个答案,其中包含了Netwire 5程序的(极简式)结构:网络中的控制台交互?。
https://stackoverflow.com/questions/25338856
复制相似问题