繰り返しになりますが、エディタの導入をお願いします。
エディタは、プログラムを書くためのソフトです。
テキストの、ツール・素材の紹介ページにエディタがありますので、ダウンロードして使いましょう。
こちらです。
特に、Windows の方は xyzzy を必ず使って下さい。
本格的にプログラムを書く上で、ちゃんとしたエディタを使うことは欠かせません。
絶対にメモ帳を使ってはいけません。
※勘違いしている方が多いようですが、メモ帳などのエディタはあくまで 「テキストファイルを編集するためのソフト」です。
メモ帳で保存したからといって、保存するデータが変わるわけではありません。
メモ帳で保存しても、xyzzy で保存しても、保存される .java ファイルの形式は変わりません。
しかし、メモ帳を使って作業をされると、今後困りますので、極力 xyzzy を使うようにしてください。
プログラミングが苦手で、上手くいかず質問してくる人ほど xyzzy を使っていないケースが多く、非常に困ります
自力でできず、TA・SAに質問しようという人は、必ず xyzzy を使うようにして下さい。
まず、本日の講義資料をダウンロードしてください。
第5回資料(Windows用)
第5回資料(Mac用)
配列とは、同じ型の複数のデータをひとまとめにしたものです。
// 配列の型[] 配列名 = new 配列の型[配列の大きさ]; int[] ball_x = new int[3];
配列の場合、変数定義の部分でこのように記述します。
このプログラムは、ball_x という int 型の配列で、大きさは 3 である、という意味になります。
ball_x[0] = 0; ball_x[1] = 100; ball_x[2] = 200;
配列を使う場合には、このように記述します。
それぞれ、以下のような意味です。
ball_x[0] = 0; で、配列の 0番目(先頭) に 0 をセット。
ball_x[1] = 100; で、配列の 1 番目に 100 をセット。
ball_x[2] = 200; で、配列の 2 番目に、200 をセット。
配列は 0 から数えますので、大きさ 3 の配列は、0, 1, 2 の 3 つのデータを保持できます。
配列を使うことで、定義の部分でわざわざ
int ball_x0; int ball_x1; int ball_x2;
のように、いちいち記述せずにすむのです。
それでは、配列を使ってボールを 3 個同時に出してみましょう。
ダウンロードした資料を解凍して、Sample01 フォルダ直下にあるgame.javaを開いて下さい。
このプログラムでは、3つのボールを斜めに動かして、壁に当たったら跳ね返るようにしています。
/********* 変数定義はこちらに *********/ // 型 変数名; の順に書いて定義する // ボールのX座標 int[] ball_x = new int[3]; // ボールのY座標 int[] ball_y = new int[3]; // ボールのX方向の速度 int[] ball_speed_x = new int[3]; // ボールのY方向の速度 int[] ball_speed_y = new int[3];
ここでは、ボールの座標と速度を、それぞれ大きさ 3 の配列として定義しています。
/********* 初期化の手順はこちらに *********/ public void initGame() { // ボールの座標を初期化する ball_x[0] = 0; ball_y[0] = 100; ball_x[1] = 100; ball_y[1] = 100; ball_x[2] = 200; ball_y[2] = 100; // ボールの速度を初期化する ball_speed_x[0] = 5; ball_speed_y[0] = 5; ball_speed_x[1] = 5; ball_speed_y[1] = 5; ball_speed_x[2] = 5; ball_speed_y[2] = 5; }
0 番目のボールは (0, 100)、1 番目のボールは (100, 100)、2 番目のボールは (200, 100) でそれぞれ初期化しています。
速度は全部 5 で初期化しています。
/********* 物体の移動等の更新処理はこちらに *********/ public void updateGame() { // Y方向に ball_speed_y ずつ進める ball_y[0] = ball_y[0] + ball_speed_y[0]; ball_y[1] = ball_y[1] + ball_speed_y[1]; ball_y[2] = ball_y[2] + ball_speed_y[2]; // X方向に ball_speed_x ずつ進める ball_x[0] = ball_x[0] + ball_speed_x[0]; ball_x[1] = ball_x[1] + ball_speed_x[1]; ball_x[2] = ball_x[2] + ball_speed_x[2]; // ボールが画面の上を越えるか、画面の下を越えた場合 if(ball_y[0] < 0 || ball_y[0] > 456) { // ボールのY方向の速度を反転させる ball_speed_y[0] = -ball_speed_y[0]; } if(ball_y[1] < 0 || ball_y[1] > 456) { // ボールのY方向の速度を反転させる ball_speed_y[1] = -ball_speed_y[1]; } if(ball_y[2] < 0 || ball_y[2] > 456) { // ボールのY方向の速度を反転させる ball_speed_y[2] = -ball_speed_y[2]; } // ボールが画面の右を越えるか、画面の左を越えた場合 if(ball_x[0] > 616 || ball_x[0] < 0) { // ボールのX方向の速度を反転させる ball_speed_x[0] = -ball_speed_x[0]; } if(ball_x[1] > 616 || ball_x[1] < 0) { // ボールのX方向の速度を反転させる ball_speed_x[1] = -ball_speed_x[1]; } if(ball_x[2] > 616 || ball_x[2] < 0) { // ボールのX方向の速度を反転させる ball_speed_x[2] = -ball_speed_x[2]; } } /********* 画像の描画はこちらに *********/ public void drawGame() { // 画面を白で塗りつぶします gc.clearScreen(); // img0.png を描画します gc.drawImage(0, ball_x[0], ball_y[0]); gc.drawImage(0, ball_x[1], ball_y[1]); gc.drawImage(0, ball_x[2], ball_y[2]); }
ボールを動かす部分と、ボールを端で跳ね返らせる部分、ボールを描画する部分を、それぞれボールの数だけ書いています。
同じような処理を何度も書いていて、非常に面倒くさいです。
これがもしボールの数が 10 個だったらと思うと・・・考えたくもないですね。
このような場合に使われる構文として、for 文があります。
Sample02 フォルダ直下にある game.java を開いて下さい。
/********* 初期化の手順はこちらに *********/ public void initGame() { for(int i=0; i<3; i=i+1) { // ボールの座標を初期化する ball_x[i] = 100 * i; ball_y[i] = 100; ball_speed_x[i] = 5; ball_speed_y[i] = 5; } }
まず、initGame の中身が、Sample01 と比べてかなりスマートになっています。
( * は、掛け算を行うときの記号です。ちなみに、 / が割り算です。)
ここで使われているものが、for文です。
for 文の書き方は、for ( 初期値; 継続条件; カウンタの加減算 ) となります。
for 文は、同じような処理を何度も繰り返す場合に使われる構文です。
初期値で定義した変数の値が、継続条件を満たす(継続条件が真)である限り、何度もブロックの中が実行されます。
(初期値で定義した変数のことを、カウンタと呼びます)
initGame の中では、for文に差し掛かった瞬間、まず i というカウンタ変数が定義され、0 で初期化されています。
その後、ブロックの中が実行されます。
i の中身は 0 なので、実行される内容は次のような感じになります。
(ball_x[0] = 100 * 0; では、100 × 0 なので、0 が代入されます。)
// ボールの座標を初期化する ball_x[0] = 100 * 0; ball_y[0] = 100; ball_speed_x[0] = 5; ball_speed_y[0] = 5;
ブロックの中身を実行し終わると、再び for 文の先頭に戻ってきて、カウンタの加減算処理が実行されます。
ここでは、i=i+1 なので、i の中身が 1 となります。
カウンタの加減算の後、継続条件を判定します。
i の中身は 1 なので、i < 3 は真となります。
真なので、再びブロックの中が実行されます。実行される内容は次のような感じです。
// ボールの座標を初期化する ball_x[1] = 100 * 1; ball_y[1] = 100; ball_speed_x[1] = 5; ball_speed_y[1] = 5;
これまでと同様、ブロックの中身を実行し終わると、カウンタの加減算処理です。
i=i+1 なので、i の中身が 2 となります。
その後、継続条件が判定され、i < 3 は真となり、再びブロックの中が実行されます。実行される内容は次のような感じです。
// ボールの座標を初期化する ball_x[2] = 100 * 2; ball_y[2] = 100; ball_speed_x[2] = 5; ball_speed_y[2] = 5;
ブロックの中身を実行し終わると、カウンタの加減算処理です。
i=i+1 なので、i の中身が 3 となります。
その後、継続条件が判定されます。
i < 3 は偽なので、for 文がここで終了します。
なお、この for 文 で定義した i は、for 文の中(ブロック内)以外で使うことはできません。
もちろん、for 文の中に、if 文や for 文などの他の構文を入れることも可能です。
腕に自身のある方はどんどん使っていきましょう。
フラグとは、立っている状態( ON )と、折れている状態( OFF )の2つの状態をとる変数です。
GameCanvas (というよりもJava) では、boolean 型 の変数で、フラグを管理することが出来ます。
実際の使い方は、次のような感じです。
/********* 変数定義はこちらに *********/ // 型 変数名; の順に書いて定義する // フラグ boolean flag; /********* 初期化の手順はこちらに *********/ public void initGame() { // フラグの初期化 boolean flag = true; }
変数定義で、boolean 型の変数を定義し、
initGame で、変数の中身を true に初期化しています。
if(flag) { }
updateGame や、drawGame の中で使う場合には、このようにして使います。
この if 文は、変数 flag の中身が true なら真、false なら偽となります。
フラグを使って時間差でボールを出してみましょう。
Sample03 フォルダ直下にある game.java を開いて下さい。
このプログラムでは、1 秒ごとに新しいボールを出しています。
updateGame → drawGame は、1/30 秒毎に繰り返し実行されているので、30 回に 1 度ボールを出せば良いことになります。
/********* 変数定義はこちらに *********/ // 型 変数名; の順に書いて定義する // ボールのX座標 int[] ball_x = new int[10]; // ボールのY座標 int[] ball_y = new int[10]; // ボールのX方向の速度 int[] ball_speed_x = new int[10]; // ボールのY方向の速度 int[] ball_speed_y = new int[10]; // ボールが生きているか、死んでいるかのフラグ boolean[] ball_alive_flag = new boolean[10]; // 次に有効にするボール番号 int next_alive_ball_num; // ゲームの経過時間 int time;
ここでは、新たに3つの変数が追加されました。
また、配列の大きさが 10 となっています。
/********* 初期化の手順はこちらに *********/ public void initGame() { for(int i=0; i<10; i=i+1) { // ボールの座標を初期化する ball_x[i] = 0; ball_y[i] = 0; // ボールの速度を初期化する ball_speed_x[i] = 5; ball_speed_y[i] = 5; // ボールのフラグを初期化 ball_alive_flag[i] = false; } // 次に有効にするボール番号を初期化 next_alive_ball_num = 0; // ゲームの経過時間を初期化 time = 0; }
初期化処理です。
ボールは全て左上から現れるものとし、全てのボールを(0, 0) で初期化しています。
最初は1つもボールが無い状態なので、ボールのフラグは全て false です。
次に有効にするボール番号は、最初のボール番号である 0
ゲームの経過時間も、開始時間なので 0 です。
/********* 物体の移動等の更新処理はこちらに *********/ public void updateGame() { // 30回に1回、ボールを有効に if(time % 30 == 0) { // ボールは10個までなので、それを超えない場合のみ実行する if(next_alive_ball_num < 10) { // ボールを有効に ball_alive_flag[next_alive_ball_num] = true; // 次のボールの番号へ。 next_alive_ball_num = next_alive_ball_num + 1; } } for(int i=0; i<10; i=i+1) { // 有効(true)なボールのみ実行 if(ball_alive_flag[i]) { // Y方向に ball_speed_y ずつ進める ball_y[i] = ball_y[i] + ball_speed_y[i]; // X方向に ball_speed_x ずつ進める ball_x[i] = ball_x[i] + ball_speed_x[i]; // ボールが画面の上を越えるか、画面の下を越えた場合 if(ball_y[i] < 0 || ball_y[i] > 456) { // ボールのY方向の速度を反転させる ball_speed_y[i] = -ball_speed_y[i]; } // ボールが画面の右を越えるか、画面の左を越えた場合 if(ball_x[i] > 616 || ball_x[i] < 0) { // ボールのX方向の速度を反転させる ball_speed_x[i] = -ball_speed_x[i]; } } } // 時間を 1 進める time = time + 1; }
updateGame です。順番に説明していきます。
難しいですが、あせらず順番に理解していきましょう。
if(time % 30 == 0) は、30回に1回だけ成立します。
% は、割り算した余りです。例えば、time の中身が 100 なら、time % 30 の答えは 10 となります。
つまり、この if 文が成立するのは、time の中身が 0, 30, 60, 90 ... となる、30の倍数の時です。
next_alive_ball_num は、次に有効にするボール番号です。
最初に if( next_alive_ball_num < 10 ) が真となった場合、next_alive_ball_num の中身は 0 なので、
ball_alive_flag[next_alive_ball_num] = true; は、ball_alive_flag[0] = true; となります。
フラグを true にした後で、next_alive_ball_num に 1 加算しています。
これにより、次に ball_alive_flag[next_alive_ball_num] = true; に来た際には、前回の次の配列要素が true となります。
if( ball_alive_flag[i] ) は、ball_alive_flag[i] が true の場合のみ真となります。
このブロックの中では、ボールを動かし、壁に跳ね返らせる処理を行っています。
つまり、有効な( true である)ボールだけを動かしています。
そして最後に、time = time + 1; で、時間に 1 加算しています。
/********* 画像の描画はこちらに *********/ public void drawGame() { // 画面を白で塗りつぶします gc.clearScreen(); // img0.png を描画します for(int i=0; i<10; i=i+1) { // 有効(true)なボールのみ実行 if(ball_alive_flag[i]) { gc.drawImage(0, ball_x[i], ball_y[i]); } } }
drawGame です。
ボールを動かす処理同様、有効な( true である)ボールだけを描画しています。
複数のボールを時間差で出し、ラケットで打ち返せるようにして下さい。
Kadai01フォルダの中のgame.javaを元に挑戦してみましょう。
answer01.jar ファイルを開くと、どのように動かせば良いか見ることができます。
応用課題です。
ボタンを押すと、ラケットから弾が出るようにしてみましょう。
連続で発射できるように、弾は配列で管理するものとします。
弾の画像は、img3.png です。
難しい課題なので、無理だと思ったら挑戦しなくても結構です。
最終課題で、シューティングゲームのようなものを作ってみたいと考えている方は、是非挑戦してみてください。
Kadai02フォルダの中のgame.javaを元に挑戦してみましょう。
answer02.jar ファイルを開くと、どのようにすれば良いか見ることができます。
応用課題1のように、ボタンを押すとラケットから弾が出るようにします。
そして、弾がボールに当たったら、ボールと弾が消えるようにしてください。
ボールは左右に動き、端に来たら跳ね返るものとします。
Kadai03フォルダの中のgame.javaを元に挑戦してみましょう。
answer03.jar ファイルを開くと、どのようにすれば良いか見ることができます。