Elm - 根据模型状态切换 fps (fpsWhen)

Elm - Toggling fps based on model state (fpsWhen)

在 elm 中有没有一种方法(或者更确切地说,什么是正确的方法)来根据应用程序的状态(存储在模型中)停止和启动 Time.fps 函数?例如,在我正在处理的应用程序中,当按下暂停键时,模型的状态字段设置为暂停。我希望 fps 停止,直到它再次设置为播放。我最初的想法是使用 Time.fpsWhen,但它会引发错误。我把这个在结构上类似于我的应用程序的示例放在一起进行演示。

import Signal
import Time
import Keyboard
import Text
import Graphics.Element (Element)

---- MODELS ----

type State = Running | Stopped
type Action = ToggleRunning | DeltaTime Float

type alias Model = {state : State, counter : Float}

---- UPDATE ----

update : Action -> Model -> Model
update action model = case action of
  DeltaTime dt -> { model | counter <- model.counter + dt }
  ToggleRunning -> { model | state <- if model.state == Running then Stopped else Running }

---- VIEW ----

view : Model -> Element
view model = Text.asText model

---- INPUTS ----

stateToggleKey : Signal Action
stateToggleKey = Signal.map (always ToggleRunning) <| Signal.keepIf identity False Keyboard.space

timeDelta : Signal Action
timeDelta = Signal.map DeltaTime <| Time.fpsWhen 20 (Signal.map (.state >> (==) Running) model)

input : Signal Action
input = Signal.merge stateToggleKey timeDelta

model : Signal Model
model = Signal.foldp update {state=Running, counter=0} input

main : Signal Element
main = Signal.map view model

可以看到"running"here.

我的假设是它不起作用,因为 modeltimeDelta 递归地相互依赖,但我不确定。无论如何,当应用程序处于暂停状态时,我应该如何停止 fps?我是否必须将 运行 状态与模型分开存储?

谢谢!

一般不支持递归定义的信号。编译器还不够好,无法检查错误定义的递归值。您可能想查看有关递归定义的相关 question/answer:

如果你的游戏只能通过空格键暂停,并且只能通过一些不依赖于游戏状态的输入来取消暂停,你实际上可以使用 fpsWhen:

onDown s = keepIf ((==) True) True s

playing = Signal.merge (always False <~ onDown Keyboard.spacebar) (always True <~ onDown Keyboard.enter)
-- turn the two arguments to merge around for the playing signal to start with True

-- another way where spacebar toggles pausing:
playing = Signal.foldp (\_ b -> not b) False (onDown Keyboard.spacebar)

timeDeltas = Time.fpsWhen 60 playing

inputs = (,,) <~ timeDeltas ~ playing ~ etc

state = Signal.foldp update startState inputs

main = view <~ state