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.
我的假设是它不起作用,因为 model
和 timeDelta
递归地相互依赖,但我不确定。无论如何,当应用程序处于暂停状态时,我应该如何停止 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
在 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.
我的假设是它不起作用,因为 model
和 timeDelta
递归地相互依赖,但我不确定。无论如何,当应用程序处于暂停状态时,我应该如何停止 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