2014年8月16日土曜日

モグラ叩きゲームで学ぶアンドロイドプログラミング (8/8)

前回は、音楽を付けるところまでやりました。
今回は、あまりにも簡単すぎるのでゲームの難易度を少し上げようと思います。

全体のソースコードは以下にあります。
https://gist.github.com/mrp1q7z/d42c75408e7a62683428

もぐらは出てきたらずっと同じ位置にいるのでゲームとしては簡単すぎて面白くありません。そこで、出てきて一定時間たったら引っ込み、別の場所に出るというように、神出鬼没にしてみたいと思います。

もぐらを引っ込めるためのタイマーを宣言します。(45行目)
private Timer mMoleTimer = null;

もぐらを表示する際、一定時間経過したら引っ込める処理を記述します。(181行目〜)
if (mMoleTimer != null) {
    mMoleTimer.cancel();
}
long delay = (long) (Math.random() * (1000 - 100) + 100);
mMoleTimer = new Timer(true);
mMoleTimer.schedule(new TimerTask() {
    @Override
    public void run() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                printMole();
            }
        });
    }
}, delay);

100〜1000までの乱数を発生させてこれを表示時間(ミリ秒)としています。

ゲームオーバー時にタイマーの終了処理を行います。(134行目〜)
mMoleTimer.cancel();
mMoleTimer = null;

実行してみます。
もぐらがヒョコヒョコとあちこちに出てくるようになったと思います。
難易度も上がってなかなかスコアが伸びません。


ただここで問題が...
もぐらを叩こうとがんばっていると、「Game Over」が出てきて
出てきた瞬間にタップしてしまうので、すぐにリプレイされてしまいます。

そこで、「Game Over」をしばらく表示しておくようにします。
画面を修正、「画面タップでリプレイ」という文字にIDを付けます。
<TextView
    android:id="@+id/replay_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/game_over_text"
    android:layout_centerHorizontal="true"
    android:text="画面タップでリプレイ"
    android:textSize="20sp"
    android:textColor="#888888"/>

この文字を保持する変数を宣言します。(46行目)
private TextView mReplayText;

変数に値をセットします。(64行目)
mReplayText = (TextView) findViewById(R.id.replay_text);

ゲームスタート時に非表示にします。(107行目)
mReplayText.setVisibility(View.INVISIBLE);

ゲームオーバー時に2秒後に表示するようにします。(137行目〜)
Timer timer = new Timer(true);
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                mReplayText.setVisibility(View.VISIBLE);
            }
        });
    }
}, 2000);

Game Over をタップしても「画面タップでリプレイ」が表示されていない場合は、何もしないようにします。(217行目〜)
if (mReplayText.getVisibility() != View.VISIBLE) {
    return;
}

実行してみます。
「画面タップでリプレイ」が表示されてないときはリプレイしなくなりました。

結構ゲームらしくなりました。
まだまだ改善の余地はあると思いますが、「モグラ叩きゲームで学ぶアンドロイドプログラミング」はこれにて終了とします。

長らくのお付き合いありがとうございました。

アプリは Google Play にて公開しています。

ソースコードは GitHub で公開しています。
https://github.com/mrp1q7z/WhacMole
※ライセンスはGPLv3となっています。
※以下のファイルは「小森平」さん(http://taira-komori.jpn.org/)の著作です。
res/raw/middle_punch1.mp3
res/raw/swing1.mp3

2014年8月15日金曜日

モグラ叩きゲームで学ぶアンドロイドプログラミング (7/8)

前回は、Game Overを出すところまでやりました。
今回は、音楽でも付けてよりゲームらしくします。

全体のソースコードは以下にあります。
https://gist.github.com/mrp1q7z/49d45fea537c07d6a202

その前に最初のスコアが100になっているので0にします。
<TextView
android:id="@+id/scoreText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="0"
android:textSize="30sp" />

activity_main.xmlの「text="100"」を「text="0"」に変更します。

適当な効果音を探してきます。
今回は、以下にしました。ありがとうございました。
・「middle_punch1/中打」「swing1/素振り1」 by 小森平さん
http://taira-komori.jpn.org/attack01.html

※音楽や画像の素材を利用する場合は利用規約をよく読んで違反なきよう使いましょう。

ダウンロードした効果音を「res/raw」にコピーします。
「raw」フォルダがない場合は新たに作成します。


ソースを変更していきます。
効果音を鳴らすために必要な変数を宣言します。(29行目〜)
private SoundPool mSound;
private int[] mSoundId;


効果音をロードします。(37行目〜)
mSoundId = new int[2];
mSound = new SoundPool(mSoundId.length, AudioManager.STREAM_MUSIC, 0);
mSoundId[0] = mSound.load(getApplicationContext(), R.raw.middle_punch1, 0);
mSoundId[1] = mSound.load(getApplicationContext(), R.raw.swing1, 0);


ボタンをクリックしたときに効果音を再生するようにします。(158、161行目)
private View.OnClickListener mButtonClicked = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (view != mMoleButton) {
            mSound.play(mSoundId[1], 1.0F, 1.0F, 0, 0, 1.0F);
            return;
        }
        mSound.play(mSoundId[0], 1.0F, 1.0F, 0, 0, 1.0F);

    ....
}
もぐらを叩いた時と穴を叩いた時で再生する音を変えています。

終了時に効果音の開放を行います。(138行目〜)
@Override
public void onDestroy() {
    super.onDestroy();
    mSound.release();
}

実行してみます。
音が出るようになったと思います。

今日はここまで。次回に続く。

2014年8月14日木曜日

モグラ叩きゲームで学ぶアンドロイドプログラミング (6/8)

前回は、もくらを叩くとスコアが+1されるところまでやりました。
今回は、もぐらを叩いたら次の場所にもぐらが出現するようにします。

全体のソースコードは以下にあります。
https://gist.github.com/mrp1q7z/f1ef3c7940cb58366de2

スコアを+1するタイミングでもぐらを表示してやります。(148行目)
printMole();
mButtonClickedに上記処理を追加します。

実行してみます。


もぐらを叩くと別の場所にもぐらが現れるようになりました。
が、前の位置にもぐらが残ったままになります。

もぐらを表示するときに、前のもぐらを消すようにします。(130行目〜)
if (mMoleButton != null) {
    mMoleButton.setBackgroundResource(R.drawable.bg_button);
}


実行してみます。


前のもぐらが消えるようになりました。

だんだんゲームらしくなってきました。
が、タイムが0になったのにゲームが続けられます。
これを直します。

タイムアウトしたら半透明の幕を出して操作できないようにします。
レイアウトファイルを修正します。


赤い部分が変更で、黄色い部分が追加したところです。
黄色い部分は「android:visibility="invisible"」にして、表示しないようにしておきます。

プログラムソースの方も変更します。
ゲームオーバーの幕を保持する変数を宣言します。(26行目)
private RelativeLayout mGameOver;

変数に値をセットします。(37行目)
mGameOver = (RelativeLayout) findViewById(R.id.game_over_container);

ゲームオーバーしたら幕を表示するようにします。(108行目)
mGameOver.setVisibility(View.VISIBLE);

幕をクリックしたときの処理を記述します。(152行目〜)
private View.OnClickListener mGameOverClicked = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        mGameOver.setVisibility(View.INVISIBLE);
        mScore = 0;
        String strScore = String.valueOf(mScore);
        mScoreText.setText(strScore);
        mGameTime = 60;
        gameStart();
    }
};

クリックと処理を紐付けます。(38行目)
mGameOver.setOnClickListener(mGameOverClicked);

実行してみます。


今日はここまで。次回に続く。




2014年8月12日火曜日

モグラ叩きゲームで学ぶアンドロイドプログラミング (5/8)

更新が遅くなってしまい、すいません。
さて、前回に引き続き、今回は、もぐらを叩いたときの処理を実装します。

全体のソースコードは以下にあります。
https://gist.github.com/mrp1q7z/c5a1f8eaedd419c018a4


画面 (activity_main.xml) を一部修正します。
スコアを表示するテキストにID(名前)を付けます。
IDはプログラムから参照するものだけ付にけます。
参照しないものについては付けなくてもOKです。

「scoreText」という名前にしました。


次に、プログラムからスコアを操作するための変数を定義します。(19行目)
private TextView mScoreText;
定義した変数に値をセットします。(33行目)
mScoreText = (TextView) findViewById(R.id.scoreText);

スコアを管理する変数も定義します。(20行目)
private int mScore;
スコアを初期化します。(32行目)
mScore = 0;

ボタンがクリックされたときの処理を記述します。(131行目〜)
private View.OnClickListener mButtonClicked = new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        mScore++;
        String strScore = String.valueOf(mScore);
        mScoreText.setText(strScore);
    }
};

とりあず、スコアを1ずつ増やしていくようにします。

ボタンと上記処理を紐付けます。(61行目〜)
for (int row = 0; row < mButton.length; row++) {
    for (int col = 0; col < mButton[1].length; col++) {
        mButton[row][col].setOnClickListener(mButtonClicked);
    }

}
ここまでできたら実行してみましょう。


ボタンをクリックするとスコアが1ずつ増えていくと思います。
ただ、どのボタンでもスコアが増えていくので、もぐらがいるかどうかの
判定をするようにします。

もぐらがどのボタンに表示されているかを管理するための変数を定義します。(18行目)
private Button mMoleButton;
上記変数を初期化します。 (31行目)
mMoleButton = null;
もぐらを表示するときに上記変数に値をセットします。(128行目)
mMoleButton = mButton[row][col];

ボタンがクリックされたときの処理で判定を行います。(134行目)
if (view != mMoleButton) {
    return;
}

もぐらでない場合は何もせずに戻るようにします。

ここまでできたら実行してみましょう。


もぐらをクリックしたときはスコアが増えて、他の場所をクリックしたときは何も起きないようになったと思います。

今日はここまで。次回に続く。