ゲームアプリ (Catch the Ball)

【Android Studio】ゲームアプリ開発入門 第4回「タイマーで画像を動かす」

 

ここまでの記事はこちら
 

前回は、タップするたびに青いボックスが少しだけ上に動くようにしました。

今回はタイマーを使って

  • 画面をタップしている間は上に移動
  • 画面から指を離すと下に移動

のように、青いボックスを上下に動かしてみます。
 
 


 

動画

動画では Android Studio 3.1.4 を使用していますが 3.6 ~ 4.2 / 2020.3.1 Arctic Fox でも動作確認済みです。

【Android Studio】ゲームアプリ開発入門 #4 青いボックスを上下に動かす

 
 

解説

タイマーでボックスを動かす

毎秒・毎分など、一定間隔で処理を実行するときはタイマーを使います。
 

MainActivity.java を開いて、4・5・18~28行目を追加します。

 

必要な import

必要な import は3つです。

import android.os.Handler;
import java.util.Timer;
import java.util.TimerTask;

 
 

タイマーについて

タイマーの処理は少し複雑にみえるかも知れませんが、分解して見てみましょう。
 

まずは timer.schedule(…) の部分です。

schedule(TimerTask task, long delay, long period)
TimerTask task実行する処理(タスク)
long delayタスクを実行するまでに待機する時間(ミリ秒で指定)
long periodタスクの実行間隔(ミリ秒で指定)

 
このゲームでは「待機時間は無しで、20ミリ秒毎にタスクを実行する」と設定しています。
 
 

次に、実行するタスク TimerTask task の部分です。

新しい TimerTask を作成して、run() メソッドを用意します。run() メソッドの中には繰り返し実行する処理を書きます。


 
 

繰り返し実行する処理は changePos() メソッドです。(この後書いていきます。)

changePos() メソッドには

  • 画像の位置を変更
  • スコアラベルを更新

をするための処理を書きます。
 
 

20 ミリ秒毎に changePos() メソッドを呼び出して画面を更新していきますが、Android 開発では「メインスレッド外で UI を変更することはできない」という決まりがあります。

言い換えると「TimerTask からはスコアラベルを更新できない」ということです。
 
 

このとき使うのが Handler です。

handler.post で UI スレッドに Runnable を渡して UI を更新するという方法で、changePos() メソッドを実行します。


 
 

Handler を使わないと
Only the original thread that created a view hierarchy can touch its views.
というエラーメッセージが表示されます。

このエラーが出た場合は、タイマー処理を見直してみてください。

*このエラーは API 26 以上のエミュレーター・実機では表示されませんが、API 25 以下の場合はアプリが強制終了となるのでご注意ください。
 
 
 

changePos() メソッドを用意

先ほど用意したタイマーで20ミリ秒毎に実行する changePos() メソッドを書きます。

5~7行目を追加します。* onTouchEvent 内の box.setY(boxY); は削除してください。

 
 
 

タッチイベントの処理を変更

現在は、画面をタップするごとに青いボックスが少しだけ上に移動するようになっています。
 

ここからは

  • 画面をタップしている間は上に
  • 画面に触れていない時は下に

青いボックスが動くようにします。
 
 

6行目を追加します。

 
 

changePos メソッドと onTouchEvent メソッドを以下のように書き換えます。

 
 

action_flg は「画面をタップしているか、タップしていないか」を判定するために使います。
 

onTouchEvent メソッドでは

  • 画面をタップしたら action_flg を true
  • 画面から指を離したら action_flg を false

にします。
 

ボックスの位置を変更する changePos メソッドでは

  • action_flg が true だったら boxY を上へ
  • action_flg が false だったら boxY を下へ

移動させています。
 
 
 

アプリを実行

ここでアプリを実行してみます。

 
 
 

青いボックスが消えてしまいましたね。

onCreate メソッドでタイマーをスタートしているので、画面が描画された時には青いボックスが下に落ち続けてしまっていることが原因です。画面をタップし続けるとまた上がってきます。

画面をタップしてからタイマーが起動するように修正していきましょう。
 

タイマー開始のタイミングを修正

ゲーム開始の判定も boolean 型の変数を使って行います。

2行目を追加します。

 
 

onTouchEvent を以下のように書き換えます。
* onCreate 内の startLabel.setVisibility(View.INVISIBLE); とタイマー処理は削除してください。

 
 

start_flg

  • false の場合はゲーム開始前
  • true の場合はゲームプレイ中

となります。
 

onTouchEvent では、初めて画面がタップされた時に

  1. start_flg を true にする
  2. startLabel を消す
  3. タイマーを開始

という処理を行います。
 

ゲームが始まって start_flg が true になると、21~27行目の action_flg の判定処理が行われるようになります。
 
 

startLabel の非表示について

startLabel.setVisibility(View.INVISIBLE);
startLabel.setVisibility(View.GONE);

TextView や ImageView などの要素を非表示にするには setVisibility メソッドを使います。

INVISIBLE は非表示にするだけ、GONE は完全に消すという違いがあります。

どちらを使っても問題ありませんが、ゲームが始まったら startLabel は不要なので GONE で完全に消してしまいましょう。
 
 

アプリを実行

アプリを実行して、このように動いていれば成功です。

 
 

今のままでは、青いボックスが画面の外に移動できてしまいます。

次はここを修正していきましょう。
 
 

青いボックスが画面から出ないようにする

ここで必要になるのが

  • frameLayout の高さ
  • 青いボックスの Y 座標
  • 青いボックスのサイズ

の3つです。


 
 

5・6行目を追加します。

 
 

7~11行目を追加します。 * onCreate 内の boxY = 500.0f; は削除してください。

 
 

必要な import

必要な import は1つです。

import android.widget.FrameLayout;

 
 

boxSize

青いボックスの画像は正方形なので box.getHeight() で高さだけ取得しています。
 
 

なぜ onCreate でサイズを取得しないのか?

「どうして FrameLayout のサイズを onCreate メソッドで取得しないのか?」と思われる方がいるかもしれません。

理由は onCreate メソッド内ではビューの描画が完了していないからです。

ビューの描画が完了していない状態で frameLayout の高さや画像サイズを取得しようとしても 0 が返ってきてしまいます。

そのため、ビューの描画が確実に完了している onTouchEvent メソッド内でサイズを取得しました。

box の Y 座標である boxY も同じ理由で onTouchEvent メソッド内で取得しています。
 
 
 

最後に changePos メソッドに 9・11行目を追加します。

 

9行目

if (boxY < 0) boxY = 0;

boxY が 0 より小さくなった場合は、青いボックスが frame の外に出ている状態です。

frame から出ないように boxY は 0 未満にならないようにします。
 

11行目

if (boxY > frameHeight – boxSize) boxY = frameHeight – boxSize;

青いボックスが画面の一番下にある時、boxY は frame の高さからボックスの高さを引いた値になります。

これ以上 boxY の値が大きくなると画面から出てしまうので、frameHeight – boxSize よりも大きくならないようにします。
 


 
 
 

アプリを実行

アプリを実行してください。

青いボックスが画面から消えなければ成功です!

 

上手く動かない場合は、一番下にここまでのコードを貼っているのでご確認ください。
 
 
 

次に行うこと

少しずつゲームらしくなってきましたね!次回はオレンジ・ピンク・ブラックボールを動かしていきましょう。

第5回 「ボールを動かす」に進む
 
 
 
 
Android Studioアプリ開発のメニューはこちら
 
 

ここまでのコード

 
 

ABOUT ME
Sara
「わかりやすく・シンプル」をモットーに、スマホアプリ・ウェブアプリの作り方を紹介します。 独学でプログラミングを勉強をしている方、基礎は勉強したけれど次に何をすれば良いか分からない...という方のお役に立てるサイトを目指しています🙂
guest
4 Comments
古い順
新しい順 人気順
Inline Feedbacks
View all comments
take
take
8 months ago

最近Androidでの開発にチャレンジをはじめて、こちらのサイトで勉強させていただいています

1点疑問なのですが、boxYにはonCreateで値を入れてますが、
onTouchEventで改めてboxY = box.getY()としているのはどのような理由なのでしょうか
試しにコメントアウトしても同じような動きに見えたので質問です

take
take
8 months ago
Reply to  Sara

Saraさん、丁寧な回答ありがとうございます!
もう少し進めた上で質問するべきでした、、、

4
0
この記事にコメントするx