【发布时间】:2014-09-08 15:12:01
【问题描述】:
我正在尝试使用 F# 中的 Observables 编写一个基本的“游戏循环”。基本上,我将事件的基本输入流概念化为两个流合并在一起:用户的按键(游戏开始时仅使用键盘)和游戏的常规滴答声(例如,每秒 60 次)。
我的问题似乎源于这样一个事实,即观察到的序列之一,即滴答声,也是在 Window 上调用 DispatchEvents() 的循环,允许它处理其输入并触发按键事件,所以一个流如果有意义的话,事件实际上是由另一个驱动的。代码如下:
open System;
open System.IO
open SFML.Window
open SFML.Graphics
open System.Reactive
open System.Reactive.Linq
open System.Diagnostics
type InputEvent =
| Tick of TimeSpan
| KeyPressed of Keyboard.Key
[<EntryPoint;STAThread>]
let main _ =
use window = new RenderWindow(VideoMode(640u, 480u), "GameWindow")
window.SetVerticalSyncEnabled(true)
let displayStream =
Observable.Create(
fun (observer:IObserver<TimeSpan>) ->
let sw = Stopwatch.StartNew()
while (window.IsOpen()) do
window.DispatchEvents() // this calls the KeyPressed event synchronously
window.Display() // this blocks until the next vertical sync
window.Clear()
observer.OnNext sw.Elapsed
sw.Restart()
observer.OnCompleted();
{ new IDisposable with member this.Dispose() = ()})
let onDisplay elapsedTime =
// draw game: code elided
let inputEvents = Observable.merge
(window.KeyPressed |> Observable.map (fun key -> KeyPressed(key.Code)))
(displayStream |> Observable.map (fun t -> Tick(t)))
use subscription =
inputEvents.Subscribe(fun inputEvent -> match inputEvent with
| Tick(t) -> onDisplay(t)
| KeyPressed(key) -> printfn "%A" key)
0
但是,如果我更改 Observable.merge 中的参数顺序,则此方法有效:
let inputEvents = Observable.merge
(displayStream |> Observable.map (fun t -> Tick(t)))
(window.KeyPressed |> Observable.map (fun key -> KeyPressed(key.Code)))
然后游戏渲染(调用 onDisplay),但我没有看到 KeyPressed 事件打印到控制台。这是为什么?
(如果您想知道什么是 SFML,这里是 link)。
【问题讨论】:
标签: f# system.reactive