2015-02-26 10 views
1

Есть ли способ вяза (или, вернее, что является правильным способом), чтобы остановить и запустить функцию Time.fps на основе состояния приложения (сохраненного в модели) ? Например, в приложении, над которым я работаю, когда нажата клавиша паузы, поле состояния модели установлено на «Приостановлено». Я бы хотел, чтобы fps остановился, пока не будет установлено значение Playing снова. Моя первоначальная мысль заключалась в том, чтобы использовать , но это вызывает ошибку. Я собрал этот пример, который по своей структуре похож на мое приложение для демонстрации.Elm - Переключение fps на основе состояния модели (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 

Вы можете увидеть это "работает" here.

Мое предположение заключается в том, что оно не работает, потому что model и timeDelta рекурсивно зависят друг от друга, но я не уверен. В любом случае, как мне следует остановить остановку fps, когда приложение находится в состоянии паузы? Должен ли я сохранять состояние работы отдельно от модели?

Спасибо!

ответ

1

В общем случае рекурсивно определенные сигналы не поддерживаются. Компилятор просто недостаточно хорош, чтобы еще раз проверить ошибочно определенные рекурсивные значения. Вы можете посмотреть связанный вопрос/ответ на SO о рекурсивном определении: https://stackoverflow.com/a/22284451/859279

Если ваша игра может быть приостановлена ​​только пробелом и будет заблокирована только некоторым вводом, который не зависит от состояния игры, вы можете могут фактически использовать 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 
+0

Определенно вариант, по крайней мере, для пользовательских условных условных обозначений. Что мне делать, если бы я хотел, чтобы таймер в модели гаснул до 0, когда приложение должно вернуться в меню? Таймер гаснет как часть игрового цикла, и время может быть добавлено на основе взаимодействия с пользователем. В конечном счете, однако, событие, которое вызывает изменение состояния от «Воспроизведения» до «Меню», является нажатием таймера 0, который может быть вызван только «Time.fps». Я не хочу, чтобы в меню отображалось «Time.fps», поэтому я снова полагаюсь на состояние модели, и это не кажется явным, чтобы работать. Мысли? – Rhitakorrr

+0

Одним из вариантов является попытка [взломать это ограничение] (http://stackoverflow.com/a/28278235/859279). Другим является принятие «Time.fps» до сих пор и дождаться, когда связанный хак будет изменен на языковой компонент [который, кажется, является планом] (https://groups.google.com/d/msg/elm Обсудите/CgHtzkrwlpA/85qLig9TGgoJ). – Apanatshka

+0

Похоже, я просто буду держать 'Time.fps' все время на все время и с нетерпением жду версии 0.15. Спасибо за подробный ответ кстати! – Rhitakorrr