ラベル モグラ叩きゲーム の投稿を表示しています。 すべての投稿を表示
ラベル モグラ叩きゲーム の投稿を表示しています。 すべての投稿を表示

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;
}

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

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


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

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




2014年4月12日土曜日

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

前回に引き続き、今回は、タイマーの処理を実装します。

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


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

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



次に、プログラムから残り時間を操作するための変数を定義します。(17行目)
private TextView mTimeText;

定義した変数に値をセットします。(27行目)
mTimeText = (TextView) findViewById(R.id.timeText);

次に、残り時間をカウントダウンするための変数を定義します。(18行目)
private int mGameTime = 60;
あらかじめ「60」とう値をセットしていますが、これは60秒という意味です。
この値を変えると残り時間を変更することができます。

次に、タイマーのような一定時間で処理を繰り返すには「Timer」というクラスを使います。そのための変数を定義します。(19行目)
private Timer mTimer = null;

次に、「gameStart」というメソッドを追加して、ゲームスタート時の処理を記述します。(64〜86行目)

private void gameStart() {
        printMole();

        if (mTimer != null) {
            return;
        }
        mTimer = new Timer(true);
        mTimer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mGameTime--;
                        if (mGameTime <= 0) {
                            gameOver();
                        }
                        mTimeText.setText(Integer.toString(mGameTime));
                    }
                });
            }
        }, 1000, 1000);

}

65行目:モグラを表示するメソッド「printMole」を呼びます。(前回、onResumeから呼び出していたもの)

67〜69行目:すでにタイマーがスタートしているかを判定し、すでにスタートしている場合は処理を抜けます。

70行目:タイマー変数の初期化

71行目:scheduleAtFixedRate(TimerTask task, long delay, long period)は、delayミリ秒あとの時間を基準としてperiodミリ秒単位でタスクを繰り返す。今回の場合だと、71行目の「new TimerTask() {」〜85行目の「}」までがタスクで、85行目の1つめの1000がdelay、2つめの1000がperiodになります。

タスクの中では、mGameTimeをカウントダウンして(77行目)
0以下になったら gameOver メソッドを呼び出して(78〜80行目)
残り時間を画面に表示(81行目)
しています。

途中の run() を Override していたり、
mHandler.post() だったりは
意味が分からなくてもこんなもんだと思っていただければOKです。

次に、「gameOver」メソッドを追加し、ゲーム終了時の処理を記述します。(88〜91行目)
private void gameOver() {
        mTimer.cancel();
        mTimer = null;
}


タイマーをキャンセルして、変数をヌルで初期化しています。

最後に、onResume の printMole を gameStart に置きかえます。(96行目)
protected void onResume() {
        super.onResume();
        gameStart();
}


ここまでできたら実行してみましょう。
Time が1秒づつ減っていくと思います。


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


2014年3月22日土曜日

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

前回にひき続き、今回はいよいよモグラを登場させましょう。

まず、モグラの画像を res/drawable-hdpi/mole.png にコピーします。

次に、MainActivity.javaを修正していきます。
全体のソースコードは以下にあります。
https://gist.github.com/mrp1q7z/9705061

ボタンを保持する変数を定義します。(11行目)
縦5x横4の合計20個の配列として宣言します。
Button[][] mButton = new Button[5][4]; // [行][列]
ボタンを保持する変数に値をセットします。(18〜41行目)
mButton[0][0] = (Button) findViewById(R.id.Button1A);
mButton[0][1] = (Button) findViewById(R.id.Button1B);
mButton[0][2] = (Button) findViewById(R.id.Button1C);
・・・
mButton[4][3] = (Button) findViewById(R.id.Button5D);

モグラの画像を表示するメソッドを追加します。(71〜75行目)
行と列は乱数を発生させてランダムな場所に表示します。
private void printMole() {
  int row = (int) (Math.random() * 5);
  int col = (int) (Math.random() * 4);
  mButton[row][col].setBackgroundResource(R.drawable.mole);
}

上記メソッド(printMole)をアプリケーションの画面が表示された直後に
発生するイベント「onResume」で呼び出すようにします。(53〜57行目)
@Override
protected void onResume() {
  super.onResume();
  printMole();
}

ここまでできたら実行してみましょう。
ランダムに表示位置を変更しているので、画面を閉じて再度実行すると違う場所に表示されるはずです。


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

2014年3月14日金曜日

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

前回に続いて、今回も画面周りを作っていきましょう。

1.画像を追加

以下の画像を res/drawable-hdpi にコピーします。

モグラを叩いたときの手のマーク:btn_push.png
モグラの出てくる穴:hole.png

2.ボタンの背景画像を作成

モグラが出てくる部分はボタンにします。
そのボタンの背景画像を作成します。

res/drawable-nodpi/bg_button.xml というファイルを作成し、以下のように記述します。
※drawable-nodpi というフォルダがない場合は新規作成します。


<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- ボタンが押されている -->
    <!-- フォーカスされていない -->
    <item android:state_focused="false" android:state_pressed="true">
        <layer-list>
            <item android:drawable="@drawable/btn_push">
        </item></layer-list>
    </item>

    <!-- ボタンが押されていない -->
    <!-- フォーカスされていない -->
    <item android:state_focused="false" android:state_pressed="false">
        <layer-list>
            <item android:drawable="@drawable/hole">
        </item></layer-list>
    </item>

    <!-- ボタンが押されている -->
    <!-- フォーカスされた -->
    <item android:state_focused="true" android:state_pressed="true">
        <layer-list>
            <item android:drawable="@drawable/btn_push">
        </item></layer-list>
    </item>

    <!-- ボタンが押されていない -->
    <!-- フォーカスされた -->
    <item android:state_focused="true" android:state_pressed="false">
        <layer-list>
            <item android:drawable="@drawable/hole">
        </item></layer-list>
    </item>

</selector>

これは、ボタンが押されていないときは、モグラの穴を表示し、ボタンが押された時には手のマークを表示するように設定しています。

3.画面にボタンを配置する

縦に5つ、横に4つの格子状にボタンを配置します。
あと、上部にはスコアと、タイムの表示をします。
activity_main.xml を以下のように修正します。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bk_grass"
    tools:context="com.yojiokisoft.whacmole.app.MainActivity">

    <LinearLayout
        android:id="@+id/relativeLayout"
        android:layout_width="fill_parent"
        android:orientation="horizontal"
        android:paddingTop="20dp"
        android:paddingLeft="10dp"
        android:layout_height="60dp">

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Score:"
            android:textSize="25sp" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="100"
            android:textSize="30sp" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Time:"
            android:textSize="25sp" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="60"
            android:textSize="30sp" />

    </LinearLayout>

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentEnd="true"
        android:layout_alignParentRight="false"
        android:layout_below="@+id/relativeLayout">

        <TableLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true">

            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_weight="1">

                <Button
                    android:id="@+id/Button1A"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button1B"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button1C"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button1D"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

            </TableRow>

            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_weight="1">

                <Button
                    android:id="@+id/Button2A"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button2B"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button2C"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button2D"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

            </TableRow>

            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_weight="1">

                <Button
                    android:id="@+id/Button3A"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button3B"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button3C"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button3D"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

            </TableRow>

            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_weight="1">

                <Button
                    android:id="@+id/Button4A"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button4B"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button4C"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button4D"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

            </TableRow>

            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_weight="1">

                <Button
                    android:id="@+id/Button5A"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button5B"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button5C"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

                <Button
                    android:id="@+id/Button5D"
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@drawable/bg_button" />

            </TableRow>
        </TableLayout>
    </RelativeLayout>

</RelativeLayout>


Button の背景には先ほど作成した bg_button を指定しています。

4.実行してみる


スコアやタイムは固定だし、モグラも出て来ませんが、モグラ叩きっぽくなりました。
ボタンを押すと、押した部分が手のマークになります。

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

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

アンドロイドプログラミングを始めようと思っている人に向けて
サンプルプログラムを作りながら学んでいくコーナーです。

ステップ、バイ、ステップで少しずつ開発していき、
最終的にモグラ叩きゲームの完成を目指します。

※開発環境は整っているという前提です。
※ここでは、Android Studio 0.5.1 を使います。


1.プロジェクトを作成

プロジェクト名は「WhacMole」にしました。



Blanck Activity を選択して、次へ


Activity Name は「MainActivity」にして、フィニッシュ。

2.背景画像を追加


drawable-hdpiに bk_grass.jpg を追加します。


activity_main.xml を開き、RelativeLayout の background に先ほど追加した
bk_grass を選択します。

3.実行してみる

背景画像が表示されました。

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