今回やること
- Spaceキーで止められるようにする
- 止めたら上の段に移動する
完成品はコチラ ellie-app.com
実装解説
Space
キーの入力を待ち受けるようにする
subscription
subscriptions : Model -> Sub Msg subscriptions model = Sub.batch [ Time.every 500 Blinking , Browser.Events.onKeyDown (D.map KeyDown keyDecoder) ]
Sub.Batch
で複数のsubscription
を定義した
キー入力を判別する
type KeyType = Space | Other keyDecoder : Decoder KeyType keyDecoder = D.map toKey (D.field "key" D.string) toKey : String -> KeyType toKey key = case key of " " -> Space _ -> Other
browser/keyboard.md at master · elm/browser · GitHub
Browser.Events - browser 1.0.2
を参考にした
Browser.keyDown
はonKeyDown : Decoder msg -> Sub msg
になっているので
受け取ったキー入力をDecode
してSpace
とそれ以外で分けるようにした
ググるとkeyCode
がたくさん出てきたんだけど、APIはkey
を推奨しているのでkey
にしてみた
update
type Msg = Blinking Time.Posix | KeyDown KeyType type KeyType = Space | Other KeyDown keyType -> case keyType of Space -> let currentPoint = case model.lightPoints of [] -> { x = 0, y = 0 } headPoint :: rest -> headPoint nextRow = { rowSize = currentPoint.x - 1, columnSize = 6 } in ( { model | stoppedLightPoints = model.stoppedLightPoints ++ model.lightPoints , lightPoints = setStartPoints nextRow 3 } , Cmd.none ) Other -> ( model, Cmd.none )
新たにKeyDown
Variantを定義してSpace
とOther
でパターンマッチ
Space
の時は現在の行(厳密にはPoint
)を取得し、光る箇所を一段上の行の右端にするようにした
また、積み重ねていく必要があるためSpace
を押した時点の光っている箇所を保存するstoppedLightPoints
も定義した
光らせる部分
type alias Model = { boxList : List Box , fieldSize : FieldSize , lightPoints : List Point , moveMode : MoveMode , stoppedLightPoints : List Point } update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of Blinking _ -> let concatLightPoints = model.lightPoints ++ model.stoppedLightPoints blinking box = if List.member box.point concatLightPoints then { box | lightMode = LightOn } else { box | lightMode = LightOff }
stoppedLightPoints
にSpace
を押した時点の光っている箇所、
lightPoints
に現在動いている行の光っている箇所がはいっているので
マージし一つの配列にして、配列内に含まれるPoint
を光らせる様にした
これで積み上げることが出来た!
…と思ったら何かラグい。スペース押したら1マス分絶対ずれる
AB先生のエスパー
1Tick分のラグが間違いなくある。描画とModelの更新にズレが有るのかなーなんだろ
— 🐊すがわに🐊 (@nek0roll) 2020年9月23日
内容わからないですがエスパーしますhttps://t.co/Gl9nWs4KTkhttps://t.co/Gl9nWs4KTk
— ABAB↑↓BA (@ababupdownba) 2020年9月23日
いわゆるFPS的なやつです
マジもんの超能力者でビックリした
画面の更新にTIme.every
を使っているけどNGだった
正しくはBrowser.Events.onAnimationFrame
だった
Time - time 1.0.0
ちなみにTime.every
のDocに「アニメーションには使わないほうがいいよ」って書いてあった(大反省)
しかも親切にBrowser.Events.onAnimationFrame
のリンクまである
コンパイラ外でも助けてくれるElmママの優しさに涙が止まりません
onAnimationFrame
を使う
subscription
subscriptions : Model -> Sub Msg subscriptions model = Sub.batch [ Browser.Events.onAnimationFrame Blinking , Browser.Events.onKeyDown (D.map KeyDown keyDecoder) ]
1秒で出来た
ただ問題があって、1秒に60回更新されるのでめちゃくちゃ難化してしまった
ズレはなくなった…気がする(多分)
何らかの方法で60回を半分にするとか出来ると思うので、後々対応していく
まずは積み上げて動かすことが出来たので一旦ゴール
まとめ
- Docはちゃんと読みましょう
onAnimationFrame
便利すぎる
js
だとsetTimeout
とかでやって大変だった記憶がある
次回
- 積み上げた際に下の段と重なっていないマスを落とす
- 1つも重なっていなければゲームオーバー
- 動き速すぎ問題対処
の予定