ラケットを動かしてみよう!

注意点

テキストをちゃんと読んでから質問してください。
テキストをしっかり読まずに、図やテキストを流し読みをして分かった気になって、テキストを読めば分かることを質問してくる方が非常に多いです。

エディタ(導入必須)

繰り返しになりますが、xyzzy、Emacsなどのエディタの導入をお願いします。
特にWindows の方は xyzzy を必ず使って下さい。

エディタの導入方法はこちらです。

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

ラケットを表示する

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

ダウンロードした資料を解凍して、Sample01フォルダ直下にあるGame.javaを開いて下さい。

まず最初に、ラケットの位置を表す変数、racket_x、racket_y を定義し、初期化しています。

/********* 変数定義はこちらに *********/
// 型 変数名; の順に書いて定義する
// ラケットのX座標
int racket_x;
// ラケットのY座標
int racket_y;

/********* 初期化の手順はこちらに *********/
public void initGame()
{
    // ラケットの座標を初期化する
    racket_x = 270;
    racket_y = 450;
}
	

続いて、更新・描画処理です。

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

/********* 画像の描画はこちらに *********/
public void drawGame()
{
    // 画面を白で塗りつぶします
    gc.clearScreen();

    // 色を青にセットします
    gc.setColor(0, 0, 255);
    // (racket_x, racket_y)の位置に、幅100, 高さ20 の長方形を描画します
    gc.fillRect(racket_x, racket_y, 100, 20);
}
	

Sample01では、ラケットを塗りつぶした長方形として表現しています。
gc.fillRect で、塗りつぶした長方形を画面に描画することができます。
塗りつぶした長方形ではなく、辺だけを描画したい場合は、gc.drawRect を使うこともできます。

まず、gc.setColor(0, 0, 255); で、色を青にセットしています。
そして、gc.fillRect(racket_x, racket_y, 100, 20); で、塗りつぶした長方形を描画しています。
この際、塗りつぶす色は、直前でセットした青となります。

サンプルの数字を変えたり、新しい命令を追加したりして、色々と試してみましょう。

ラケットを動かす

次に、ラケットを動かしてみます。
右キーが押されている場合は右へ、左キーが押されている場合には左へ移動するようにします。
そのためには、キー情報を取得しなければなりません。

キー情報を取得する

isKeyPushed(キー); などの命令を使って、キー入力の状態を調べることができます。
それぞれの命令は以下の通りです。

GameCanvas内で使えるキーは、以下の通りです。

キーが押されたらラケットを動かす

上で学んだことを活かして、ラケットを動かしてみましょう。
Sample02フォルダ直下にあるGame.javaを開いて下さい。

/********* 物体の移動等の更新処理はこちらに *********/
public void updateGame()
{
    // 左キーが押された場合に真
    if(gc.isKeyPushed(gc.KEY_LEFT))
    {
        // ラケットを左に動かす
        racket_x = racket_x - 5;
    }

    // 右キーが押された場合に真
    if(gc.isKeyPushed(gc.KEY_RIGHT))
    {
        // ラケットを右に動かす
        racket_x = racket_x + 5;
    }
}
	

更新処理以外は、Sample01と同じです。

ここでは、左キーが押されたら左に 5 動かし、右キーが押されたら右に 5 動かしています。

if(gc.isKeyPushed(gc.KEY_LEFT)) は、左キーが押された瞬間のみ真になります。
if(gc.isKeyPushed(gc.KEY_RIGHT)) は、右キーが押された瞬間のみ真になります。

ラケットに弾を跳ね返らせる

ラケットにテニスボールが当たったら、テニスボールが跳ね返るようにしましょう。
Sample03 フォルダ直下にあるGame.javaを開いて下さい。

まず最初に、テニスボールとラケット用の変数を定義し、初期化しています。

/********* 変数定義はこちらに *********/
// 型 変数名; の順に書いて定義する
// ボールのX座標
int ball_x;
// ボールのY座標
int ball_y;
// ボールのX方向の速度
int ball_speed_x;
// ボールのY方向の速度
int ball_speed_y;
// ラケットのX座標
int racket_x;
// ラケットのY座標
int racket_y;

/********* 初期化の手順はこちらに *********/
public void initGame()
{
    // ボールの座標を初期化する
    ball_x = 0;
    ball_y = 100;

    // ボールの速度を初期化する
    ball_speed_x = 5;
    ball_speed_y = 5;

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

次は、updateGame 内を見てみましょう。

// 左キーが押された場合に真
if(gc.isKeyPushed(gc.KEY_LEFT))
{
    // ラケットを左に動かす
    racket_x = racket_x - 5;
}
// 右キーが押された場合に真
if(gc.isKeyPushed(gc.KEY_RIGHT))
{
    // ラケットを右に動かす
    racket_x = racket_x + 5;
}
	

これは、左キーが押されたらラケットを左に、右キーが押されたらラケットを右に動かす処理です。
Sample02 で学びましたね。

// Y方向に ball_speed_y ずつ進める
ball_y = ball_y + ball_speed_y;

// X方向に ball_speed_x ずつ進める
ball_x = ball_x + ball_speed_x;

// ボールが画面の上を越えた場合
if(ball_y < 0)
{
    // ボールのY方向の速度を反転させる
    ball_speed_y = -ball_speed_y;
}

// ボールが画面の右を越えるか、画面の左を越えた場合
if(ball_x > 616 || ball_x < 0)
{
    // ボールのX方向の速度を反転させる
    ball_speed_x = -ball_speed_x;
}
	

こちらは、ボールを動かす処理と、画面端で跳ね返らせる処理です。
忘れてしまった方は、前回の講義を見返してみましょう。
前回と異なり、画面下を越えた場合のみ跳ね返らないようにしています。

以下の部分が、今回のポイントとなる部分です。

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

ここでは、ラケットにボールが当たるかどうか、つまりラケットとボールが重なるかどうかをチェックしています。
そして、重なった場合にのみ跳ね返らせています。

このような、2つの物体が重なるかどうかをチェックすることを、当たり判定と呼びます。

当たり判定

GameCanvas では、以下の命令を使って当たり判定を行うことができます。

Sample03 の場合、ラケットを 幅100 高さ20 の四角形、ボールを 幅24 高さ24 の四角形として、2つの四角形が重なるかどうかを判定しています。

なお drawGame では、画像とラケットをそれぞれ描画しています。

/********* 画像の描画はこちらに *********/
public void drawGame()
{
    // 画面を白で塗りつぶします
    gc.clearScreen();

    // img0.png を(ball_x, ball_y)に描画します
    gc.drawImage(0, ball_x, ball_y);

    // 色を青にセットします
    gc.setColor(0, 0, 255);
    // (racket_x, racket_y)の位置に、幅100, 高さ20 の長方形を描画します
    gc.fillRect(racket_x, racket_y, 100, 20);
}
	

どのように判定しているか?

当たり判定命令が、内部的にどのように判定しているのかを、ここで詳しく説明してみます。
難しいと感じた方は、無理に理解せずとも問題ありません。

以下の4つの条件を全て満たした場合、2つの四角形 A, B は重なります。


図:当たり判定の解説

当たり判定を行う2つの物体を、それぞれ A, B とします。
A の 座標は(x1, y1) 、幅と高さは w1, h1 です。
同様に、B の座標は(x2, y2)、幅と高さは w2, h2 です。

これを前述の条件に当てはめてみると、以下の式となります。

これをプログラムで表現すると、以下のようになります。

if( x1 < x2 + w2 && x1 + w1 > x2 && y1 < y2 + h2 && y1 + h1 > y2)
	

課題1

今回の授業で作ったプログラムを改造します。
押した瞬間だけしか移動できなかったラケットを、押しっぱなしで移動できるようにしてください。

Kadai01フォルダの中のGame.javaを元に挑戦してみましょう。
Kadai01フォルダの中のanswer01.jar ファイルを開くと、どのようにすれば良いか見ることができます。


図:課題1の実行画面。左右キーを押すとラケットがその方向へと動き、ボールに当るとボールが跳ね返る

課題2

課題1の内容を改良します。
ラケットの幅と高さを、それぞれ半分にしてください。
その際、幅と高さは、それぞれ変数が保持するようにしましょう。

Kadai02フォルダの中のGame.javaを元に挑戦してみましょう。
Kadai02フォルダの中のanswer02.jar ファイルを開くと、どのようにすれば良いか見ることができます。


図:課題2の実行画面。課題1の半分のサイズのラケットが表示されている

課題3

課題2の内容を改良します。
左右にしか移動できなかったラケットを、上下にも移動できるようにしてください。

Kadai03フォルダの中のGame.javaを元に挑戦してみましょう。
Kadai03フォルダの中のanswer03.jar ファイルを開くと、どのようにすれば良いか見ることができます。


図:課題3の実行画面。課題2のラケットが上下左右に移動できるようになっている

戻る