一人テニスゲーム、完成!!

エディタ(導入必須)

繰り返しになりますが、エディタの導入をお願いします。

エディタは、プログラムを書くためのソフトです。
テキストの、ツール・素材の紹介ページにエディタがありますので、ダウンロードして使いましょう。
こちらです。

特に、Windows の方は xyzzy を必ず使って下さい。
本格的にプログラムを書く上で、ちゃんとしたエディタを使うことは欠かせません。
絶対にメモ帳を使ってはいけません。

※勘違いしている方が多いようですが、メモ帳などのエディタはあくまで 「テキストファイルを編集するためのソフト」です。
メモ帳で保存したからといって、保存するデータが変わるわけではありません。
メモ帳で保存しても、xyzzy で保存しても、保存される .java ファイルの形式は変わりません。

しかし、メモ帳を使って作業をされると、今後困りますので、極力 xyzzy を使うようにしてください。

プログラミングが苦手で、上手くいかず質問してくる人ほど xyzzy を使っていないケースが多く、非常に困ります
自力でできず、TA・SAに質問しようという人は、必ず xyzzy を使うようにして下さい。

完成へ向けて

まず、本日の講義資料をダウンロードしてください。
第6回資料(Windows用)
第6回資料(Mac用)

ボールの出てくる位置をバラバラにしてみる。

前回の授業では、画面にボールを複数出すことを学びました。
それを元に、ボールの出てくる場所をバラバラにしてみましょう。

乱数

乱数とは、ランダムな数値(バラバラな数字)のことです。
要するに、サイコロと同じだと考えて下さい。

サイコロを振ると、1 〜 6 の数字のどれかを返します。
(つまり、サイコロは 1 〜 6 の乱数を生成しています。)
GameCanvas では、gc.rand(1, 6); と書くと、サイコロを一回振ったのと同じことになります。

以下のような感じで使用します。

// 受け取る変数を定義
int random_num;

(中略)

// gc.rand(1, 6); は 1 〜 6 のうちいずれかの値を返し、random_num はその値を保持する
random_num = gc.rand(1, 6);
	

実際に使ってみましょう。
ダウンロードした資料を解凍して、Sample01フォルダ直下にあるgame.javaを開いて下さい。
Sample01 は、前回の講義の Sample03 を元に変更を加えたものです。見比べながら考えてみましょう。

/********* 初期化の手順はこちらに *********/
public void initGame()
{
    for(int i=0; i<10; i=i+1)
    {
        // ボールの座標を初期化する
        // X座標を、0 〜 600 の範囲の乱数で初期化する
        ball_x[i] = gc.rand(0, 600);
        ball_y[i] = 0;

        (中略)
    }

   (以下略)
}
	

前回の講義の Sample03 と比べて、変更した箇所は 1 ヶ所だけです。
ball_x[i] = gc.rand(0, 600); で、ボールのX座標を 0 〜 600 の範囲のいずれかの数字で初期化しています。

コンパイルして実行してみましょう。
ボールの現れる場所がバラバラになっているのが分かりますね。

スコア

スコア(点数)をつけてみましょう。
Sample02フォルダ直下にあるgame.javaを開いて下さい。

このプログラムでは、弾をラケットで打ち返す度に点数を10点追加しています。
現在の点数は、画面の左上に描画しています。

/********* 変数定義はこちらに *********/
// 型 変数名; の順に書いて定義する

(中略)

// 点数
int score;

/********* 初期化の手順はこちらに *********/
public void initGame()
{
    (中略)

    // 点数を初期化
    score = 0;
}
	

変数定義に、点数を保持する score を追加しています。
初期化部分では、score を 0 で初期化しています。

/********* 物体の移動等の更新処理はこちらに *********/
public void updateGame()
{
    (中略)

    // ボールと、ラケットが当たった場合に真
    if(gc.checkHitRect(racket_x, racket_y, racket_w, racket_h, ball_x, ball_y, 24, 24))
    {
        // ボールのY方向の速度を反転させる
        ball_speed_y = -ball_speed_y;

        // 点数を10点加算する
        score = score + 10;
    }
}
	

ボールが当たった際に、点数を10点足しています。
score = score + 10; の部分です。

/********* 画像の描画はこちらに *********/
public void drawGame()
{
    (中略)

    // 点数を描画します
    gc.drawString("Score " + score, 0, 0);
}
	

gc.drawString("Score " + score, 0, 0); で、画面の左上に点数を描画しています。

文字列の後に + 変数名(あるいは数字)と書くと、文字列に数字をつなげることができます。
"Score " + score で、"Score scoreの中の数字" という文字列になります。

ハイスコア

今までゲームをプレイした中で一番良かった点数(スコア)のことを、ハイスコアといいます。
ハイスコアを画面に表示してみましょう。
Sample03フォルダ直下にあるgame.javaを開いて下さい。
Sample03 は、Sample02 を元に変更を加えたものです。見比べながら考えてみましょう。

/********* 変数定義はこちらに *********/
// 型 変数名; の順に書いて定義する

(中略)

// 点数
int score;
// ハイスコア
int high_score;

/********* 初期化の手順はこちらに *********/
public void initGame()
{
    (中略)

    // 点数を初期化
    score = 0;
    // ハイスコアを初期化
    high_score = 0;
}
	

変数定義に、ハイスコアを保持する high_score を追加しています。
初期化部分では、high_score を 0 で初期化しています。

/********* 物体の移動等の更新処理はこちらに *********/
public void updateGame()
{
    (中略)

    // ボールが画面の下を越えた場合
    if(ball_y > 480)
    {
        // 最初の状態に戻す
        // ボールの座標を初期化する
        ball_x = 0;
        ball_y = 100;

        // ラケットの座標を初期化する
        racket_x = 270;
        racket_y = 450;

        // 点数を初期化する
        score = 0;
    }

    // ボールと、ラケットが当たった場合に真
    if(gc.checkHitRect(racket_x, racket_y, racket_w, racket_h, ball_x, ball_y, 24, 24))
    {
        // ボールのY方向の速度を反転させる
        ball_speed_y = -ball_speed_y;

        // 点数を10点加算する
        score = score + 10;

        // 点数がハイスコアを上回っていたら
        if(score > high_score)
        {
            // ハイスコアを更新
            high_score = score;
        }
    }
}
	

ボールが当たった際に、点数がハイスコアを上回っていたら、ハイスコアの更新をする処理を追加しています。
加えて、ボールが画面下を越えた場合に、必要な変数を初期化する処理を追加しています。

/********* 画像の描画はこちらに *********/
public void drawGame()
{
        (中略)

    // 点数を描画します
    gc.drawString("Score " + score, 0, 0);
    gc.drawString("HighScore " + high_score, 200, 0);
}
	

スコアの隣りに、ハイスコアを描画する処理を追加しています。

ハイスコアのセーブ・ロード

GameCanvas では、データをセーブデータに保存し、後で保存したデータを読み込むことが&できます。

では、実際の使い方を見てみましょう。
Sample04 フォルダ直下にあるgame.javaを開いて下さい。
Sample04 では、ゲームを終了する際にハイスコア情報を保存し、ゲームを起動した時に保存したハイスコア情報を読み込んでいます。

/********* 初期化の手順はこちらに *********/
public void initGame()
{
    (中略)

    // ハイスコアを読み込む
    high_score = gc.load(0);

}

    (中略)

/********* 終了時の処理はこちらに *********/
public void finalGame()
{
    // ハイスコアをセーブ
    gc.save(0, high_score);
}
	

finalGame() は、右上の×ボタンを押してゲームを終了した場合に実行される処理です。
ここでは、終了した時にハイスコアを 0 番にセーブしています。

initGame() では、0 で初期化する代わりに、0 番にセーブしたデータを読み込んでいます。
セーブデータが無い場合には 0 が返されるので、セーブデータが無い場合でもちゃんと 0 で初期化することができます。

関数を定義する

※ 難しい項目ですので、腕に自信のある方以外は読み飛ばしてもらってかまいません。

関数を使うと、複数の命令を1つにまとめることができます。
実は、今までの講義で使ってきた gc.drawImage などの gc. で始まる命令は全て関数です。
GameCanvas 側で用意されたこれらの関数は、複雑な処理をひとつにまとめ、簡単にゲームを作れるように工夫されています。

では、関数の作り方を学んでいきましょう。 関数を使いこなすことで、より良いプログラムが書けるようになります。
関数の自作に挑戦してみましょう。

Sample05 フォルダ直下にあるgame.javaを開いて下さい。
このプログラムは、画面を青く塗りつぶすだけの単純なものです。

    (中略)

/********* 画像の描画はこちらに *********/
public void drawGame()
{
    // 青く塗りつぶす関数を呼ぶ
    clearBlue();
}

/********* 終了時の処理はこちらに *********/
public void finalGame() {}


// 青で画面を塗りつぶす関数を定義
void clearBlue()
{
    // 色を青にセット
    gc.setColor(0, 0, 255);
    // 画面を塗りつぶす
    gc.fillRect(0, 0, 640, 480);
}
	

一番下で、clearBlue という関数を定義しています。
この関数の中には、2 つの命令が記述されています。

定義した関数 clearBlue は、drawGame 内で呼ばれています。
clearBlue が呼ばれると、clearBlue の中身が上から順に実行されます。
(ここでは、色を青にセットし、その色で画面を塗りつぶしている)

もう一つ具体例を見てみましょう。
Sample06 フォルダ直下にあるgame.javaを開いて下さい。

Sample06 は、Sample04 を元に変更を加えたものです。
ボールが画面の下を超えた場合の初期化処理を、関数としてまとめています。

// ゲームスタート時の状態に初期化する関数を定義
void resetGameValue()
{
    // ボールの座標を初期化する
    ball_x = 0;
    ball_y = 100;

    // ラケットの座標を初期化する
    racket_x = 270;
    racket_y = 450;

    // 点数を初期化する
    score = 0;
}
	

一番下で、resetGameValue という関数を定義しています。
この関数の中に、ゲーム中に変化する変数の初期化命令をまとめています。

/********* 初期化の手順はこちらに *********/
public void initGame()
{
   (中略)

    // ゲーム中に変更される変数を初期化
    resetGameValue();
}

/********* 物体の移動等の更新処理はこちらに *********/
public void updateGame()
{
    (中略)

    // ボールが画面の下を越えた場合
    if(ball_y > 480)
    {
        // ゲーム開始の状態に初期化する関数を呼び出す
        resetGameValue();
    }

    (中略)
}
	

resetGameValue 関数は、ゲーム内で変化していく値だけを初期化する関数です。
initGame 内と、updateGame 内でボールが画面の下を超えた場合に呼ばれています。

このように、いくつかの場所に同じような処理がまとまっている場合に、関数を使うと非常に便利です。
同じ内容を何度も書かずにすみますし、変更する場合も、一箇所書き換えるだけですみます。

関数の引数

関数を呼び出す際にカッコの中に書く数字のことを、引数と言います。
例えば、gc.setColor(0, 0, 255); は、3 つの引数を持つ関数です。
Sample05, Sample06 で作った関数は、カッコの中になにもないので、引数無しの関数です。

引数を活用した関数を定義してみましょう。
Sample07 フォルダ直下にあるgame.javaを開いて下さい。
引数に渡した数値を使って、画面を塗りつぶす関数を定義しています。

    (中略)

/********* 画像の描画はこちらに *********/
public void drawGame()
{
    // 画面を塗りつぶす関数を呼ぶ
    // ここでは、赤で塗りつぶしている
    clearWindow(255, 0, 0);
}

/********* 終了時の処理はこちらに *********/
public void finalGame() {}


// 引数に渡した数値を使って、画面を塗りつぶす関数を定義
void clearWindow(int r, int g, int b)
{
    // 色を青にセット
    gc.setColor(r, g, b);
    // 画面を塗りつぶす
    gc.fillRect(0, 0, 640, 480);
}
	

定義された clearWindow 関数には、int 型の3つの引数 r, g, b があります。
そして、drawGame では、255, 0, 0 の引数で drawGame を呼び出しています。

ここで呼び出された clearWindow の引数はそれぞれ、r は 255、g は 0、b は 0 です。
つまり、gc.setColor(r, g, b); は、gc.setColor(255, 0, 0); として実行されます。

関数の戻り値

関数は、値を返すこともできます。この返す値を、戻り値といいます。
例えば、gc.rand は、int 型の値を返す関数です。

それでは、戻り値の例を説明します。
Sample08 フォルダ直下にあるgame.javaを開いて下さい。
このプログラムでは、引数に与えた数字を 2 乗して返す関数を定義しています。

/********* 変数定義はこちらに *********/
// 型 変数名; の順に書いて定義する
int value;

(中略)

/********* 物体の移動等の更新処理はこちらに *********/
public void updateGame()
{
    value = square(7);
}

(中略)

// 引数に渡した数値を使って、画面を塗りつぶす関数を定義
int square(int n)
{
    return n * n;
}
	

square という、int 型の引数 1 つをとり、2乗した値を返す関数を定義しています。
return 値; と書くと、その値が返されます。
return された時点で関数は終了するので、return より下に命令を書いても実行されません。注意しましょう。

square の前に書いてある int は、戻り値の型です。
ここでは、int 型の値を返すと定義しています。
なお、ここに void と書くと、値を返さない関数となります。
その場合は、return 文を書かなくてもエラーにはなりません。

updateGame 内で、square() を呼んでいます。
この関数の中では、n * n で引数を二乗して、return でその結果を返しています。

課題

今までの課題と、今回の授業内容を組み合わせて、1人用テニスゲームを完成させてください。
自分なりに工夫して、面白いゲームを作ってみましょう。

また、余裕のある方は、関数にチャレンジしてみましょう。

戻る