Upgrade to Pro — share decks privately, control downloads, hide ads and more …

QMLでFlappyBirdを作ろう

Yuto Tokunaga
September 03, 2015

 QMLでFlappyBirdを作ろう

creating Flappy Bird by QML

Yuto Tokunaga

September 03, 2015
Tweet

More Decks by Yuto Tokunaga

Other Decks in Programming

Transcript

  1. QML の紹介 UI記述用言語 Component を組み合わせてUIを組み上げていく Animation, State などを 宣言的に 記述できる

    プロパティバインディングによる状態の管理 書いたアプリは Windows, Mac, Linux, Android, iOS どこでも動 く QMLの日本語のイントロダクション QMLプログラミング入門へよ うこそ! — Getting started QML programming Japanese translation 2014.04.05 ドキュメント 2 / 59
  2. サンプルのダウンロード https://goo.gl/1hSiDG からダウンロード /qml/main.qml をqmlscene.exe にドラッグ・アンド・ドロップして起 動. /step[2-5]/ はスライドの各ステップに対応しています./qml/ は完

    成形のソースコードが入っています. 自分で一から作りたい場合は/qml/ と同じ階層に新しくフォルダを 作成してください. 7 / 59
  3. Flappy Bird のつくりかた 1. リソース(鳥とか障害物の画像)を用意する 2. アプリケーションの基本部分を作る 3. 鳥を飛ばす 4.

    障害物を作る・当たりを判定する 5. 鳥を作りこむ 6. ゲームのシーンを作る 10 / 59
  4. Step2 アプリケーションの基本部分を作る QMLのアプリで一番基本の部分を作る.main.qml に以下の内容を書 く. import QtQuick 2.2 import QtQuick.Controls

    1.3 ApplicationWindow { title: "Flappy Bird" width: 288 height: 512 visible: true Image { anchors.fill: parent source: "../assets/bg_day.png" } } 12 / 59
  5. anchors.fill: parent; anchors.margins: 50 四方の間隔を50px空けて 親の中央に位置する anchors.right: parent.right; anchors.rightMargin: 50

    間隔を50px空け て親の右端に位置する anchors.right: item1.left; anchors.rightMargin: 50 item1との間隔を 50px空ける 18 / 59
  6. import QtQuick 2.2 Rectangle { width: 500; height: 500 color:

    "red" Rectangle { width: 200; height: 200 color: "blue" anchors { left: parent.left bottom: parent.bottom leftMargin: 50 bottomMargin: 100 } } } リサイズしてもアンカーで定義した位置関係が変わらないことが 確認できる 20 / 59
  7. 鳥を作ろう main.qml と同じ階層にEntity フォルダを作り,以下をEntity/Bird.qml として保存. import QtQuick 2.2 AnimatedSprite {

    id: bird width: 34; height: 24 property real v: 0 source: "../../assets/bird_yellow.png" frameDuration: 600 frameWidth: 17 frameHeight: 12 frameCount: 3 } AnimatedSprite については後で説明します. 25 / 59
  8. 変数を追加する QMLではプロパティが変数にあたる. 以下をGame に追加. property int t: 0 // 時間

    property real g: 0.5 // 重力加速度 property real pyonV: 8 // スペースキーを押した時に加えられる速度 27 / 59
  9. 一定時間ごとに処理を行う QMLのTimer コンポーネントを利用する.これは指定した時間ごと に指定された処理を行う. Timer { id: timer running: true

    interval: 33 // 33msecごとに処理を行う repeat: true onTriggered: { // 実行される処理 update() t++ // 時間の変数を更新 } } 28 / 59
  10. 鳥を落下させる 一定時間ごとに鳥を下方向に動かす. function update() { // fall down bird.v +=

    g bird.y += bird.v } Bird { id: bird x: (parent.width - width) / 3 } y, v, g は下方向に正の値を取る. 29 / 59
  11. お気づきでしょうか,これはJavaScriptです. QMLにはJavaScript(ES5)のロジックを埋め込める.ゲームロジ ックはJavaScriptで記述していくことになる. QMLでは最初に紹介したアンカー以外にx y を指定してコンポー ネントを移動させることができる. QMLのid コンポーネントに名前を付けるにはid を使う.Bird

    コンポーネン トにbird というIDを付けておくと,例えば位置Yはbird.y というよ うに参照できる. 先ほどBird コンポーネントを作った時にv という実数型のプロパテ ィを作った.ここではGame からBird のv を参照し値を変更してい る. 31 / 59
  12. スペースキーで速度を変える Keys.onSpacePressed: pyon() function pyon() { bird.v = -pyonV }

    キーボード入力に反応するにはKeys を使う. 33 / 59
  13. パイプを作る 隙間の上端と隙間部分の長さを指定することができるパイプのコ ンポーネント./step4/Entity/Pipe.qml を参照. ステージを作る パイプを何本かステージ上に用意しておく (clear ) 時間経過に伴い左にずれていく (update

    ) 画面の左端までパイプがずれて見えなくなったら右端に配置し直 す (update ) パイプの隙間は乱数で適当に設定する (setPipeRandom ) パイプと鳥が衝突していないか判定する (isClear ) パイプをくぐり抜けたか判定する (scoreUp ) /step4/Entity/Stage.qml を参照 35 / 59
  14. Game にStage を配置して,これらの関数を呼び出す.start goOver を 追加,update を修正. 鳥の初期位置設定,ステージの初期化,フラグ変更 (start )

    ステージ上の障害物や地面・天井に衝突すればゲーム終了 (update ) パイプの隙間を抜けたらスコアを上げる (update ) ゲームオーバーしたらフラグを戻し鳥を停止 (goOver ) /step4/Game.qml 参照 36 / 59
  15. プロパティバインディング プロパティを別のプロパティと連携して値を連動させる機能. QMLの一番の目玉機能といってもよい. import QtQuick 2.2 Rectangle { width: 300;

    height: 300 color: "red" Rectangle { width: parent.width / 2 height: parent.height / 3 color: "blue" } } ウィンドウをリサイズ(赤の四角の大きさを変える)と青の四角 の大きさが連動して変わることが確認できる. 38 / 59
  16. Timer のrunning プロパティにisPlaying をバインディングする.start やgoOver でisPlaying を変更してやるとタイマーが連動する. Timer { id:

    timer running: isPlaying ... } 今まで使っていた: はバインディングの意味.JavaScriptコード内 で用いている= (代入)とは意味合いが異なる. 39 / 59
  17. import QtQuick 2.2 SpriteSequence { id: bird; width: 34; height:

    24 property real v: 0 Sprite { name: 'flying' source: "../../assets/bird_yellow.png" frameDuration: 600 frameWidth: 17 frameHeight: 12 frameCount: 3 } Sprite { name: 'drafting' source: "../../assets/bird_yellow.png" frameDuration: 50 frameWidth: 17 frameHeight: 12 frameCount: 3 } Sprite { name: 'die' source: "../../assets/bird_yellow.png" frameX: 51 frameWidth: 17 frameHeight: 12 frameCount: 1 } } 43 / 59
  18. Sprite が各状態に相当する.bird.jumpTo('flying') のようにして状態 遷移する. property bool isUpdrafting: false function start()

    { ... bird.jumpTo('flying') } function pyon() { bird.v = -pyonV isUpdrafting = true // updraftCount = 0; bird.jumpTo('drafting') } function update() { ... if (isUpdrafting && bird.v > 0) { isUpdrafting = false bird.jumpTo('flying') } } function goOver() { ... bird.jumpTo('die') } 44 / 59
  19. 任意の出来事を通知するシグナル プロパティの定義とは別にシグナルを作成することもできる. // ゲームオーバーを通知するためのシグナル signal gameOver(int score) シグナルには引数を指定できる.対応するハンドラはonGameOver と いう名称になる.

    onGameOver: { console.log("score: ", score); result.score = score; game.state = 'result'; } ハンドラ内で引数を利用することができる.プロパティの定義と 同様,引数には型付けが必要.(JavaScriptを使っていると不自然 に思うだろうけど) 50 / 59
  20. 状態の管理 その2 ゲームの現在の状態によって表示する画面を切り替えたい. プロパティバインディングとJavaScriptコードでの条件分岐でも 対応できるが,管理したい状態が増えると式が煩雑になったり, 同じような条件分岐があちこち点在するようになり,管理が大変に なる. color: mouseArea.containsMouse ?

    "blue" : "red" (プロパティバインディングは非常に強力で,JavaScriptの式に も対応している.width: height + 30 などもそうだが,JavaScript の式中に含まれるプロパティの値が変わると,その式を再評価す る仕組みになっている.) 53 / 59
  21. states state を用いた状態の管理 コンポーネントにもとから備わっているstates プロパティに各状態 を記述していく.State の中にはStateChangeScript PropertyChanges な ど,その状態に切り替わった時に実行する動作を記述できる.

    初期状態はstate で定義する.game.state = 'play' とすることによ り,状態の切り替えを行える. state: 'title' states: [ State { name: "title" }, State { name: "play" StateChangeScript { script: play.start() } }, State { name: "result" } ] 54 / 59
  22. 最後にGame にTitle Play Resutl を配置して完了!お疲れ様でした. Title { id: title anchors.fill:

    parent visible: game.state === 'title' onBeginPlay: game.state = 'play' } Play { id: play anchors.fill: parent visible: game.state !== 'title' onGameOver: { console.log("score: ", score); result.score = score; game.state = 'result'; } } Result { id: result anchors.fill: parent visible: game.state === 'result' onBackToTitle: game.state = 'title' } 55 / 59
  23. References How to Make a Flappy Bird Game with V-Play

    | V-Play 2.4 | V- Play Game Engine Mobile - Flappy Bird - Version 1.2 Sprites - The Spriters Resource QMLプログラミング入門へようこそ! — Getting started QML programming Japanese translation 2014.04.05 ドキュメント Qt QuickではじめるクロスプラットフォームUIプログラミング 59 / 59