gpt4 book ai didi

f# - 为什么在 Observable.merge 的这种用法中顺序很重要?

转载 作者:行者123 更新时间:2023-12-05 00:24:53 26 4
gpt4 key购买 nike

我正在尝试使用 F# 中的 Observables 编写一个基本的“游戏循环”。基本上,我将事件的基本输入流概念化为合并在一起的两个流:用户的按键(游戏仅使用键盘开始)和游戏的常规滴答声(例如,每秒 60 次)。

我的问题似乎源于这样一个事实,即观察到的序列之一,即滴答声,也是在窗口上调用 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 )。

最佳答案

在伪代码中,merge 的作用是:

firstStream.Subscribe(...);
secondStream.Subscribe(...);

您传递给 Observable.create 的订阅功能是同步的,永远不会将控制权交还给调用者。这意味着 merge本身被阻止尝试订阅 displayStream 之后的任何流。 .当您对流重新排序时, displayStream首先,您阻止它订阅您的 KeyPressed溪流。这就是为什么你会看到你所看到的行为。

在某些方面,您的 displayStream表现不佳。 Subscribe方法不应该阻塞。

所以,要么确保 displayStream是列表中的最后一项,或者对代码进行一些重构。你可以只使用 SubjectdisplayStream .然后订阅所有内容,最后启动“显示循环”,在此执行当前在 displayStream 中的循环。定义和每次循环时,只需调用 OnNext就此主题而言。

关于f# - 为什么在 Observable.merge 的这种用法中顺序很重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25634698/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com